#include"k3bloom.h" #include #include"k3.h" #include #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; }