mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-01 19:28:02 +03:00
280 lines
9.4 KiB
C++
280 lines
9.4 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "blur.hpp"
|
|
#include "../fbo.hpp"
|
|
#include "../gl_state.hpp"
|
|
#include "../post_process.hpp"
|
|
#include "../render_context.hpp"
|
|
#include "../shader_ft.hpp"
|
|
|
|
struct gaussian_coef_shader_data {
|
|
vec4 g_coef[8];
|
|
};
|
|
|
|
static void post_process_blur_radius_calculate(post_process_blur* blur);
|
|
static void post_process_blur_radius_calculate_gaussian_kernel(float_t* gaussian_kernel,
|
|
float_t radius, int32_t stride, int32_t offset);
|
|
|
|
post_process_blur::post_process_blur() : data(),
|
|
width(), height(), width_down(), height_down(), tex_down(), count_down() {
|
|
reduce_width[0] = 256;
|
|
reduce_height[0] = 144;
|
|
reduce_width[1] = 128;
|
|
reduce_height[1] = 72;
|
|
reduce_width[2] = 64;
|
|
reduce_height[2] = 36;
|
|
reduce_width[3] = 32;
|
|
reduce_height[3] = 18;
|
|
reduce_width[4] = 8;
|
|
reduce_height[4] = 8;
|
|
for (int32_t i = 0; i < 5; i++)
|
|
reduce_texture[i].Init(reduce_width[i], reduce_height[i], 0, GL_RGBA16F, 0);
|
|
downsample_texture.Init(reduce_width[0], reduce_height[0], 0, GL_RGBA16F, 0);
|
|
gaussian_coef_ubo.Create(sizeof(gaussian_coef_shader_data));
|
|
}
|
|
|
|
post_process_blur:: ~post_process_blur() {
|
|
if (!this)
|
|
return;
|
|
|
|
gaussian_coef_ubo.Destroy();
|
|
for (int32_t i = 0; i < count_down; i++)
|
|
tex_down[i].Free();
|
|
free_def(tex_down);
|
|
free_def(height_down);
|
|
free_def(width_down);
|
|
}
|
|
|
|
void post_process_blur::downsample(RenderTexture* rt) {
|
|
int32_t i = 0;
|
|
if (count_down > 0) {
|
|
uniform_value[U_REDUCE] = 1;
|
|
shaders_ft.set(SHADER_FT_REDUCE);
|
|
for (; i < count_down; i++) {
|
|
glViewport(0, 0, width_down[i], height_down[i]);
|
|
tex_down[i].Bind();
|
|
gl_state_active_bind_texture_2d(0, (i ? tex_down[i - 1] : *rt).GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, width_down[i], height_down[i],
|
|
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
|
|
}
|
|
i--;
|
|
}
|
|
|
|
uniform_value[U_REDUCE] = 3;
|
|
shaders_ft.set(SHADER_FT_REDUCE);
|
|
|
|
glViewport(0, 0, reduce_width[0], reduce_height[0]);
|
|
reduce_texture[0].Bind();
|
|
gl_state_active_bind_texture_2d(0, (count_down > 0 ? tex_down[i] : *rt).GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, width, height,
|
|
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.1f, 1.1f, 1.1f, 0.0f);
|
|
|
|
downsample_texture.Bind();
|
|
gl_state_active_bind_texture_2d(0, reduce_texture[0].GetColorTex());
|
|
for (int32_t i = 1; i < 5; i++) {
|
|
float_t scale;
|
|
if (i == 4) {
|
|
scale = 1.0f;
|
|
uniform_value[U_EXPOSURE] = 0;
|
|
shaders_ft.set(SHADER_FT_EXPOSURE);
|
|
}
|
|
else
|
|
{
|
|
scale = 0.75;
|
|
uniform_value[U_REDUCE] = 1;
|
|
shaders_ft.set(SHADER_FT_REDUCE);
|
|
}
|
|
|
|
glViewport(0, 0, reduce_width[i], reduce_height[i]);
|
|
RenderTexture::DrawQuad(&shaders_ft, reduce_width[i - 1], reduce_height[i - 1],
|
|
1.0f, 1.0f, 0.0f, 0.0f, scale, 1.0f, 1.0f, 1.0f, 1.0f);
|
|
gl_state_active_bind_texture_2d(0, reduce_texture[i].GetColorTex());
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, reduce_width[i], reduce_height[i]);
|
|
}
|
|
}
|
|
|
|
void post_process_blur::get_blur() {
|
|
uniform_value[U_ALPHA_MASK] = 0;
|
|
|
|
vec3 intensity = data.intensity;
|
|
vec3* gauss = data.gauss;
|
|
|
|
gaussian_coef_shader_data gaussian_coef = {};
|
|
for (int32_t i = 0; i < POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE && i < 8; i++) {
|
|
*(vec3*)&gaussian_coef.g_coef[i] = gauss[i] * intensity;
|
|
gaussian_coef.g_coef[i].w = 0.0f;
|
|
}
|
|
|
|
gaussian_coef_ubo.WriteMemory(gaussian_coef);
|
|
|
|
uniform_value[U_GAUSS] = 0;
|
|
shaders_ft.set(SHADER_FT_GAUSS);
|
|
gaussian_coef_ubo.Bind(1);
|
|
|
|
downsample_texture.Bind();
|
|
for (int32_t i = 1; i < 4; i++) {
|
|
glViewport(0, 0, reduce_width[i], reduce_height[i]);
|
|
gl_state_active_bind_texture_2d(0, reduce_texture[i].GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, reduce_width[i], reduce_height[i],
|
|
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, reduce_width[i], reduce_height[i]);
|
|
}
|
|
|
|
for (int32_t i = 1; i < 4; i++) {
|
|
glViewport(0, 0, reduce_width[i], reduce_height[i]);
|
|
gl_state_active_bind_texture_2d(0, reduce_texture[i].GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, reduce_width[i], reduce_height[i],
|
|
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, reduce_width[i], reduce_height[i]);
|
|
}
|
|
|
|
uniform_value[U_GAUSS] = 1;
|
|
shaders_ft.set(SHADER_FT_GAUSS);
|
|
|
|
glViewport(0, 0, reduce_width[0], reduce_height[0]);
|
|
gl_state_active_bind_texture_2d(0, reduce_texture[0].GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, reduce_width[0], reduce_height[0],
|
|
1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
|
data.intensity.x * 0.5f, data.intensity.y * 0.5f, data.intensity.z * 0.5f, 1.0f);
|
|
|
|
uniform_value[U_REDUCE] = 7;
|
|
shaders_ft.set(SHADER_FT_REDUCE);
|
|
|
|
glViewport(0, 0, reduce_width[0], reduce_height[0]);
|
|
reduce_texture[0].Bind();
|
|
gl_state_active_bind_texture_2d(0, downsample_texture.GetColorTex());
|
|
gl_state_active_bind_texture_2d(1, reduce_texture[1].GetColorTex());
|
|
gl_state_active_bind_texture_2d(2, reduce_texture[2].GetColorTex());
|
|
gl_state_active_bind_texture_2d(3, reduce_texture[3].GetColorTex());
|
|
RenderTexture::DrawQuad(&shaders_ft, reduce_width[3], reduce_height[3],
|
|
1.0f, 1.0f, 0.0f, 0.0f, 0.25f, 0.15f, 0.25f, 0.25f, 0.25f);
|
|
}
|
|
|
|
void post_process_blur::init_fbo(int32_t width, int32_t height) {
|
|
if (!this || (this->width == width && this->height == height))
|
|
return;
|
|
|
|
this->width = width > 1 ? width : 1;
|
|
this->height = height > 1 ? height : 1;
|
|
|
|
int32_t i = 0;
|
|
width = this->width;
|
|
height = this->height;
|
|
while (width > 512 && height > 288) {
|
|
width /= 2;
|
|
height /= 2;
|
|
i++;
|
|
}
|
|
|
|
RenderTexture* tex_down = this->tex_down;
|
|
int32_t* width_down = this->width_down;
|
|
int32_t* height_down = this->height_down;
|
|
|
|
if (!tex_down)
|
|
tex_down = force_malloc<RenderTexture>(i);
|
|
else if (count_down < i) {
|
|
RenderTexture* temp = force_malloc<RenderTexture>(i);
|
|
memcpy(temp, tex_down, sizeof(RenderTexture) * count_down);
|
|
free_def(tex_down);
|
|
tex_down = temp;
|
|
}
|
|
|
|
if (!width_down)
|
|
width_down = force_malloc<int32_t>(i);
|
|
else if (count_down < i) {
|
|
int32_t* temp = force_malloc<int32_t>(i);
|
|
memcpy(temp, width_down, sizeof(int32_t) * count_down);
|
|
free_def(width_down);
|
|
width_down = temp;
|
|
}
|
|
|
|
if (!height_down)
|
|
height_down = force_malloc<int32_t>(i);
|
|
else if (count_down < i) {
|
|
int32_t* temp = force_malloc<int32_t>(i);
|
|
memcpy(temp, height_down, sizeof(int32_t) * count_down);
|
|
free_def(height_down);
|
|
height_down = temp;
|
|
}
|
|
|
|
count_down = i;
|
|
|
|
i = 0;
|
|
width = this->width;
|
|
height = this->height;
|
|
while (width > 512 && height > 288) {
|
|
width_down[i] = width /= 2;
|
|
height_down[i] = height /= 2;
|
|
i++;
|
|
}
|
|
|
|
for (i = 0; i < count_down; i++)
|
|
tex_down[i].Init(width_down[i], height_down[i], 0, GL_RGBA16F, 0);
|
|
|
|
gl_state_bind_framebuffer(0);
|
|
|
|
this->tex_down = tex_down;
|
|
this->width_down = width_down;
|
|
this->height_down = height_down;
|
|
}
|
|
|
|
void post_process_blur::initialize_data(const vec3& radius, const vec3& intensity) {
|
|
data.radius = vec3::clamp(radius, 1.0f, 3.0f);
|
|
data.intensity = vec3::clamp(intensity, 0.0f, 2.0f);
|
|
post_process_blur_radius_calculate(this);
|
|
}
|
|
|
|
vec3 post_process_blur::get_intensity() {
|
|
return data.intensity;
|
|
}
|
|
|
|
void post_process_blur::set_intensity(const vec3& value) {
|
|
data.intensity = vec3::clamp(value, 0.0f, 2.0f);
|
|
}
|
|
|
|
vec3 post_process_blur::get_radius() {
|
|
return data.radius;
|
|
}
|
|
|
|
void post_process_blur::set_radius(const vec3& value) {
|
|
vec3 temp = vec3::clamp(value, 1.0f, 3.0f);
|
|
if (temp != data.radius) {
|
|
data.radius = temp;
|
|
post_process_blur_radius_calculate(this);
|
|
}
|
|
}
|
|
|
|
static void post_process_blur_radius_calculate(post_process_blur* blur) {
|
|
float_t radius_scale = 0.8f;
|
|
vec3 radius = blur->data.radius;
|
|
post_process_blur_radius_calculate_gaussian_kernel((float_t*)blur->data.gauss, radius.x * radius_scale, 3, 0);
|
|
post_process_blur_radius_calculate_gaussian_kernel((float_t*)blur->data.gauss, radius.y * radius_scale, 3, 1);
|
|
post_process_blur_radius_calculate_gaussian_kernel((float_t*)blur->data.gauss, radius.z * radius_scale, 3, 2);
|
|
}
|
|
|
|
static void post_process_blur_radius_calculate_gaussian_kernel(float_t* gaussian_kernel,
|
|
float_t radius, int32_t stride, int32_t offset) {
|
|
if (stride < 1)
|
|
stride = 1;
|
|
if (offset < 0)
|
|
offset = 0;
|
|
|
|
gaussian_kernel[0 * stride + offset] = 1.0f;
|
|
for (int32_t i = 1; i < POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE; i++)
|
|
gaussian_kernel[i * stride + offset] = 0.0f;
|
|
double_t temp_gaussian_kernel[POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE];
|
|
double_t s = radius;
|
|
s = -1.0 / (2.0 * s * s);
|
|
double_t sum = 0.5;
|
|
temp_gaussian_kernel[0] = 1.0;
|
|
for (size_t i = 1; i < POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE; i++)
|
|
sum += temp_gaussian_kernel[i] = exp(i * i * s);
|
|
|
|
sum = 0.5 / sum;
|
|
for (size_t i = 0; i < POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE; i++)
|
|
gaussian_kernel[i * stride + offset] = (float_t)(temp_gaussian_kernel[i] * sum);
|
|
}
|