Files
korenkonder_ReDIVA/src/CRE/post_process/blur.cpp
T

312 lines
10 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() {
tex[0].init(256, 144, 0, GL_RGBA16F, 0);
tex[1].init(128, 72, 0, GL_RGBA16F, 0);
tex[2].init(64, 36, 0, GL_RGBA16F, 0);
tex[3].init(32, 18, 0, GL_RGBA16F, 0);
tex[4].init(8, 8, 0, GL_RGBA16F, 0);
tex[5].init(256, 144, 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::get_blur(render_texture* rt) {
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 coef = gauss[i] * intensity;
gaussian_coef.g_coef[i] = { coef.x, coef.y, coef.z, 0.0f };
}
gaussian_coef_ubo.WriteMapMemory(gaussian_coef);
int32_t i = 0;
if (count_down > 0) {
uniform_value[U_REDUCE] = 1;
shaders_ft.set_opengl_shader(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].color_texture->tex
: rt->color_texture->tex);
render_texture::draw_quad(&shaders_ft, width_down[i], height_down[i]);
}
i--;
}
uniform_value[U_REDUCE] = 3;
shaders_ft.set_opengl_shader(SHADER_FT_REDUCE);
glViewport(0, 0, 256, 144);
tex[0].bind();
gl_state_active_bind_texture_2d(0, count_down > 0
? tex_down[i].color_texture->tex
: rt->color_texture->tex);
render_texture::draw_quad(&shaders_ft, width, height, 1.0f, 1.1f, 1.1f, 1.1f, 0.0f);
uniform_value[U_GAUSS] = 1;
shaders_ft.set_opengl_shader(SHADER_FT_GAUSS);
glViewport(0, 0, 256, 144);
tex[5].bind();
gl_state_active_bind_texture_2d(0, tex[0].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 256, 144, 1.0f,
data.intensity.x * 0.5f, data.intensity.y * 0.5f, data.intensity.z * 0.5f, 1.0f);
uniform_value[U_REDUCE] = 1;
shaders_ft.set_opengl_shader(SHADER_FT_REDUCE);
glViewport(0, 0, 128, 72);
tex[1].bind();
gl_state_active_bind_texture_2d(0, tex[0].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 256, 144);
uniform_value[U_REDUCE] = 1;
shaders_ft.set_opengl_shader(SHADER_FT_REDUCE);
glViewport(0, 0, 64, 36);
tex[2].bind();
gl_state_active_bind_texture_2d(0, tex[1].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 128, 72);
uniform_value[U_REDUCE] = 1;
shaders_ft.set_opengl_shader(SHADER_FT_REDUCE);
glViewport(0, 0, 32, 18);
tex[3].bind();
gl_state_active_bind_texture_2d(0, tex[2].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 64, 36);
uniform_value[U_EXPOSURE] = 0;
shaders_ft.set_opengl_shader(SHADER_FT_EXPOSURE);
glViewport(0, 0, 8, 8);
tex[4].bind();
gl_state_active_bind_texture_2d(0, tex[3].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 32, 18);
uniform_value[U_GAUSS] = 0;
shaders_ft.set_opengl_shader(SHADER_FT_GAUSS);
gaussian_coef_ubo.Bind(1);
glViewport(0, 0, 128, 72);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[1].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 128, 72, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f);
fbo::blit(tex[0].fbos[0], tex[1].fbos[0],
0, 0, 128, 72,
0, 0, 128, 72, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glViewport(0, 0, 64, 36);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[2].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 64, 36, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f);
fbo::blit(tex[0].fbos[0], tex[2].fbos[0],
0, 0, 64, 36,
0, 0, 64, 36, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glViewport(0, 0, 32, 18);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[3].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 32, 18);
fbo::blit(tex[0].fbos[0], tex[3].fbos[0],
0, 0, 32, 18,
0, 0, 32, 18, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glViewport(0, 0, 128, 72);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[1].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 128, 72, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
fbo::blit(tex[0].fbos[0], tex[1].fbos[0],
0, 0, 128, 72,
0, 0, 128, 72, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glViewport(0, 0, 64, 36);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[2].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 64, 36, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
fbo::blit(tex[0].fbos[0], tex[2].fbos[0],
0, 0, 64, 36,
0, 0, 64, 36, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glViewport(0, 0, 32, 18);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[3].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 32, 18, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
fbo::blit(tex[0].fbos[0], tex[3].fbos[0],
0, 0, 32, 18,
0, 0, 32, 18, GL_COLOR_BUFFER_BIT, GL_LINEAR);
uniform_value[U_REDUCE] = 7;
shaders_ft.set_opengl_shader(SHADER_FT_REDUCE);
glViewport(0, 0, 256, 144);
tex[0].bind();
gl_state_active_bind_texture_2d(0, tex[5].color_texture->tex);
gl_state_active_bind_texture_2d(1, tex[1].color_texture->tex);
gl_state_active_bind_texture_2d(2, tex[2].color_texture->tex);
gl_state_active_bind_texture_2d(3, tex[3].color_texture->tex);
render_texture::draw_quad(&shaders_ft, 32, 18, 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++;
}
render_texture* 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_s(render_texture, i);
else if (count_down < i) {
render_texture* temp = force_malloc_s(render_texture, i);
memcpy(temp, tex_down, sizeof(render_texture) * count_down);
free_def(tex_down);
tex_down = temp;
}
if (!width_down)
width_down = force_malloc_s(int32_t, i);
else if (count_down < i) {
int32_t* temp = force_malloc_s(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_s(int32_t, i);
else if (count_down < i) {
int32_t* temp = force_malloc_s(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);
}