Files
k3/src/k3bloom.c
2025-05-10 18:21:10 +03:00

287 lines
9.9 KiB
C

#include"k3bloom.h"
#include<stddef.h>
#include"k3.h"
#include<assert.h>
#include"gl.h"
static struct k3GLSLP *tonemapper;
static struct k3GLSLP *minibloom1;
static struct k3GLSLP *minibloom2;
int make_mb1() {
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
"uniform vec2 u_sz;" "\n"
"varying vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = gl_Vertex.xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;""\n"
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
"}" "\n"
, NULL) : k3ShaderGLSLV(
"#version 330\n"
"uniform vec2 u_sz;" "\n"
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
"out vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = positions[gl_VertexID].xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;""\n"
" gl_Position = positions[gl_VertexID];" "\n"
"}" "\n"
, NULL);
if(!v) return 0;
struct k3GLSLF *f = !k3IsCore ? k3ShaderGLSLF(
"#define THRESHOLD 0.6" "\n"
"#define FACTOR 0.07" "\n"
"uniform sampler2D u_tex;" "\n"
"varying vec2 v_uv;" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" float luminance = col.r * 0.3086 + col.g * 0.6094 + col.b * 0.0820;" "\n"
" if(luminance < THRESHOLD) col = vec3(0);" "\n"
" return col * FACTOR;" "\n"
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(-4.0 / 512.0, 0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(-3.0 / 512.0, 0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(-2.0 / 512.0, 0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(-1.0 / 512.0, 0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(+0.0 / 512.0, 0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(+1.0 / 512.0, 0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(+2.0 / 512.0, 0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(+3.0 / 512.0, 0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(+4.0 / 512.0, 0));" "\n"
" gl_FragColor = vec4(c, 1);" "\n"
"}" "\n"
, NULL) : k3ShaderGLSLF(
"#version 330\n"
"#define THRESHOLD 0.6" "\n"
"#define FACTOR 0.07" "\n"
"uniform sampler2D u_tex;" "\n"
"in vec2 v_uv;" "\n"
"out vec4 fragcolor;" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" float luminance = col.r * 0.3086 + col.g * 0.6094 + col.b * 0.0820;" "\n"
" if(luminance < THRESHOLD) col = vec3(0);" "\n"
" return col * FACTOR;" "\n"
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(-4.0 / 512.0, 0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(-3.0 / 512.0, 0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(-2.0 / 512.0, 0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(-1.0 / 512.0, 0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(+0.0 / 512.0, 0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(+1.0 / 512.0, 0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(+2.0 / 512.0, 0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(+3.0 / 512.0, 0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(+4.0 / 512.0, 0));" "\n"
" fragcolor = vec4(c, 1);" "\n"
"}" "\n"
, NULL);
if(!f) return 0;
minibloom1 = k3ProgramGLSL(v, f, NULL);
if(!minibloom1) return 0;
return 1;
}
int make_mb2() {
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
"uniform vec2 u_sz;" "\n"
"varying vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = gl_Vertex.xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;" "\n"
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
"}" "\n"
, NULL) : k3ShaderGLSLV(
"#version 330\n"
"uniform vec2 u_sz;" "\n"
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
"out vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = positions[gl_VertexID].xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;" "\n"
" gl_Position = positions[gl_VertexID];" "\n"
"}" "\n"
, NULL);
if(!v) return 0;
struct k3GLSLF *f = !k3IsCore ? k3ShaderGLSLF(
"uniform sampler2D u_tex;" "\n"
"varying vec2 v_uv;" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" return col;" "\n"
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 256.0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 256.0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 256.0));" "\n"
" gl_FragColor = vec4(c, 1);" "\n"
"}" "\n"
, NULL) : k3ShaderGLSLF(
"#version 330\n"
"uniform sampler2D u_tex;" "\n"
"in vec2 v_uv;" "\n"
"out vec4 fragcolor;" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" return col;" "\n"
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 256.0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 256.0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 256.0));" "\n"
" fragcolor = vec4(c, 1);" "\n"
"}" "\n"
, NULL);
if(!f) return 0;
minibloom2 = k3ProgramGLSL(v, f, NULL);
if(!minibloom2) return 0;
return 1;
}
int make_tonemapper() {
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
"varying vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = gl_Vertex.xy * 0.5 + 0.5;" "\n"
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
"}" "\n"
, NULL) : k3ShaderGLSLV(
"#version 330\n"
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
"out vec2 v_uv;" "\n"
"void main() {" "\n"
" v_uv = positions[gl_VertexID].xy * 0.5 + 0.5;" "\n"
" gl_Position = positions[gl_VertexID];" "\n"
"}" "\n"
, NULL);
if(!v) return 0;
struct k3GLSLF *f = k3ShaderGLSLF(
"uniform sampler2D u_tex;" "\n"
"varying vec2 v_uv;" "\n"
"const vec3 WHITE = vec3(0.95045592705, 1.0, 1.08905775076);" "\n"
"const mat3 RGB_2_XYZ = (mat3(" "\n"
" 0.4124564, 0.2126729, 0.0193339," "\n"
" 0.3575761, 0.7151522, 0.1191920," "\n"
" 0.1804375, 0.0721750, 0.9503041" "\n"
"));" "\n"
"const mat3 XYZ_2_RGB = (mat3(" "\n"
" 3.2404542,-0.9692660, 0.0556434," "\n"
" -1.5371385, 1.8760108,-0.2040259," "\n"
" -0.4985314, 0.0415560, 1.0572252" "\n"
"));" "\n"
"float XYZ_TO_LAB_F(float x) {"
" return x > 0.00885645167 ? pow(x, 0.333333333) : 7.78703703704 * x + 0.13793103448;"
"}"
"vec3 XYZ_TO_LAB(vec3 xyz) {"
" vec3 xyz_scaled = xyz / WHITE;"
" xyz_scaled = vec3("
" XYZ_TO_LAB_F(xyz_scaled.x),"
" XYZ_TO_LAB_F(xyz_scaled.y),"
" XYZ_TO_LAB_F(xyz_scaled.z)"
" );"
" return vec3("
" (1.16 * xyz_scaled.y) - 0.16,"
" 5.0 * (xyz_scaled.x - xyz_scaled.y),"
" 2.0 * (xyz_scaled.y - xyz_scaled.z)"
" );"
"}"
"float LAB_TO_XYZ_F(float x) {"
" return (x > 0.206897) ? x * x * x : (0.12841854934 * (x - 0.137931034));"
"}"
"vec3 LAB_TO_XYZ(vec3 Lab) {"
" float w = (Lab.x + 0.16) / 1.16;"
" return WHITE * vec3("
" LAB_TO_XYZ_F(w + Lab.y / 5.0),"
" LAB_TO_XYZ_F(w),"
" LAB_TO_XYZ_F(w - Lab.z / 2.0)"
" );"
"}"
"vec3 toner(vec3 col, float whitepoint, float saturation) {" "\n"
" vec3 xyz = RGB_2_XYZ * col;" "\n"
" vec3 lab = XYZ_TO_LAB(xyz);" "\n"
" lab.yz *= saturation;" "\n"
" float n = lab.x * (1.0 + (lab.x / (whitepoint * whitepoint)));" "\n"
" lab.x = n / (1.0 + lab.x);" "\n"
" xyz = LAB_TO_XYZ(lab);" "\n"
" return XYZ_2_RGB * xyz;" "\n"
"}" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" col = toner(col, 0.80, 1.0);" "\n"
" return col;" "\n"
"}" "\n"
"void main() {" "\n"
" gl_FragColor = vec4(get_col(v_uv), 1);" "\n"
"}" "\n"
, NULL);
if(!f) return 0;
tonemapper = k3ProgramGLSL(v, f, NULL);
if(!tonemapper) return 0;
return 1;
}
int k3BloomInit() {
if(!k3IsCore && !GLAD_GL_ARB_shading_language_100) {
return 0;
}
if(!make_mb1()) return 0;
if(!make_mb2()) return 0;
if(!make_tonemapper()) return 0;
return 1;
}
int k3Bloom(struct k3Offscreen *a, struct k3Offscreen *b) {
if(!minibloom1) return 0;
if(!minibloom2) return 0;
assert(b);
k3BeginOffscreen(b);
k3BlitToScreenEffect(a, false, k3_GLSL, minibloom1, NULL);
k3EndOffscreen(b);
k3BlitToScreenEffect(b, true, k3_GLSL, minibloom2, NULL);
return 1;
}
struct k3GLSLP *k3ToneMapper() {
return tonemapper;
}