////////////////////////////////////////////////
//
// tonemapping
//
////////////////////////////////////////////////

shader 0 "hdrreduce" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0; 
    }
] [
    uniform sampler2DRect tex0; 
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor.rgb = texture2DRect(tex0, texcoord0).rgb;
    }
]

shader 0 "hdrreduce2w" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0;
    }
] [
    uniform sampler2DRect tex0; 
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor.rgb = 0.5*(texture2DRectOffset(tex0, texcoord0, ivec2(-1, 0)).rgb + texture2DRectOffset(tex0, texcoord0, ivec2(1, 0)).rgb);
    }
]

shader 0 "hdrreduce2" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0;
    }
] [
    uniform sampler2DRect tex0; 
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor.rgb = 0.25*(texture2DRectOffset(tex0, texcoord0, ivec2(-1, -1)).rgb + texture2DRectOffset(tex0, texcoord0, ivec2(1, -1)).rgb +
                              texture2DRectOffset(tex0, texcoord0, ivec2(1, 1)).rgb + texture2DRectOffset(tex0, texcoord0, ivec2(-1, 1)).rgb);
    }
]

lazyshader 0 msaaresolve [
    in vec4 vvertex;
    void main(void)
    {
        gl_Position = vvertex;
    }
] [
    uniform sampler2DMS tex0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor = texelFetch(tex0, ivec2(gl_FragCoord.xy), 0);
    }
]

lazyshader 0 msaaresolvedepth [
    in vec4 vvertex;
    void main(void)
    {
        gl_Position = vvertex;
    }
] [
    uniform sampler2DMS tex0;
    @(if $gdepthformat [result [
        @(gdepthunpackparams)
        uniform vec2 gdepthinvscale;
        layout(location = 0) out vec4 fragcolor;
    ]])
    void main(void)
    {
        @(if $gdepthformat [result [
            vec4 packdepth = texelFetch(tex0, ivec2(gl_FragCoord.xy), 0);
            @(gdepthunpack depth packdepth)
            fragcolor = packdepth;
            gl_FragDepth = gdepthinvscale.x / depth - gdepthinvscale.y;
        ]] [result [
            gl_FragDepth = texelFetch(tex0, ivec2(gl_FragCoord.xy), 0).r;
        ]])
    }
]

lazyshader 0 msaareducew [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 tap0, tap1;
    void main(void)
    {
        gl_Position = vvertex;
        tap0 = vtexcoord0; 
        tap1 = vtexcoord0 + vec2(-1.0, 0.0);
    }
] [
    uniform sampler2DMS tex0; 
    in vec2 tap0, tap1;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor = 0.5*(texelFetch(tex0, ivec2(tap0), 0) + texelFetch(tex0, ivec2(tap1), 0));
    }
]

lazyshader 0 msaareduce [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 tap0, tap1, tap2, tap3;
    void main(void)
    {
        gl_Position = vvertex;
        tap0 = vtexcoord0; 
        tap1 = vtexcoord0 + vec2(-1.0,  0.0);
        tap2 = vtexcoord0 + vec2( 0.0, -1.0);
        tap3 = vtexcoord0 + vec2(-1.0, -1.0);
    }
] [
    uniform sampler2DMS tex0; 
    in vec2 tap0, tap1, tap2, tap3;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        fragcolor = 0.25*(texelFetch(tex0, ivec2(tap0), 0) + texelFetch(tex0, ivec2(tap1), 0) +
                          texelFetch(tex0, ivec2(tap2), 0) + texelFetch(tex0, ivec2(tap3), 0));
    }
]

lumweights = "0.2126, 0.7152, 0.0722"
//lumweights = "0.299, 0.587, 0.114"

hdrgammadecode = [
    if (=f $hdrgamma 2) [result [
        @arg1 *= @arg1;
    ]] [result [
        @arg1 = pow(@arg1, vec3(hdrgamma.x));
    ]]
]

hdrgammaencode = [
    if (=f $hdrgamma 2) [result [
        @arg1 = sqrt(@arg1);
    ]] [result [
        @arg1 = pow(@arg1, vec3(hdrgamma.y));
    ]]
]

shader 0 "hdrluminance" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0; 
    }
] [
    uniform sampler2DRect tex0; 
    uniform vec2 hdrgamma;
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 color = texture2DRect(tex0, texcoord0).rgb*2.0;
        @(hdrgammadecode color)
        float lum = dot(color, vec3(@lumweights));
        float loglum = sqrt(clamp(lum, 0.015625, 4.0)) * (1.0/2.0); // allow values as low as 2^-6, and as high 2^2
        fragcolor.rgb = vec3(loglum);
    }
]

shader 0 "hdrluminance2w" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0;
    }
] [
    uniform sampler2DRect tex0; 
    uniform vec2 hdrgamma;
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        @(loopconcat i 2 [result [
            vec3 color@[i] = texture2DRectOffset(tex0, texcoord0, ivec2(@(at ["-1, 0" "1, 0"] $i))).rgb*2.0;
            @(hdrgammadecode [color@[i]])
            float lum@[i] = dot(color@[i], vec3(@lumweights));
            float loglum@[i] = sqrt(clamp(lum@[i], 0.015625, 4.0)) * (1.0/2.0);
        ]])
        fragcolor.rgb = vec3(0.5*(loglum0 + loglum1));
    }
]

shader 0 "hdrluminance2" [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0;
    }
] [
    uniform sampler2DRect tex0; 
    uniform vec2 hdrgamma;
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        @(loopconcat i 4 [result [
            vec3 color@[i] = texture2DRectOffset(tex0, texcoord0, ivec2(@(at ["-1, -1" "1, -1" "1, 1" "-1, 1"] $i))).rgb*2.0;
            @(hdrgammadecode [color@[i]])
            float lum@[i] = dot(color@[i], vec3(@lumweights));
            float loglum@[i] = sqrt(clamp(lum@[i], 0.015625, 4.0)) * (1.0/2.0);
        ]])
        fragcolor.rgb = vec3(0.25*(loglum0 + loglum1 + loglum2 + loglum3));
    }
]

shader 0 "hdraccum" [
    in vec4 vvertex;
    void main(void)
    {
        gl_Position = vvertex;
    }
] [
    uniform sampler2DRect tex0;
    uniform float accumscale;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        float lum = texture2DRect(tex0, vec2(0.5, 0.5)).r * 2.0;
        lum *= lum;
        fragcolor = vec4(vec3(lum*0.25), accumscale);
    }
]

shader 0 "hdrbloom" [
    in vec4 vvertex;
    @(screentexcoord 0)
    @(? (>= $hwvtexunits 4) [
        uniform sampler2D tex2;
    ] [
        in float vcolor;
    ])
    uniform vec4 hdrparams;
    out vec2 texcoord0;
    flat out float lumscale, lumthreshold;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0; 
        float avglum = 4.0 * @(? (>= $hwvtexunits 4) [texture2D(tex2, vec2(0.5, 0.5)).r] [vcolor]);
        lumscale = hdrparams.x * -log2(1.0 - clamp(avglum, 0.03, 0.3))/(avglum + 1e-4);
        lumthreshold = -log2(1.0 - hdrparams.z);
    }
] [
    uniform sampler2DRect tex0; 
    uniform vec2 hdrgamma;
    in vec2 texcoord0;
    flat in float lumscale, lumthreshold;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 color = texture2DRect(tex0, texcoord0).rgb*2.0;
        @(hdrgammadecode color)
        float lum = dot(color, vec3(@lumweights));
        color *= max(lum*lumscale - lumthreshold, 0.0) / (lum + 1e-4);
        @(hdrgammaencode color)
        fragcolor.rgb = color;
    }
]

hdrtonemapvertexshader = [
  result [
    in vec4 vvertex;
    @(screentexcoord 0)
    @(screentexcoord 1)
    @(? (>= $hwvtexunits 4) [
        uniform sampler2D tex2;
    ] [
        in float vcolor;
    ])
    uniform vec4 hdrparams;
    out vec2 texcoord0, texcoord1;
    flat out float lumscale, lumsaturate;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0; 
        texcoord1 = vtexcoord1;
        float avglum = 4.0 * @(? (>= $hwvtexunits 4) [texture2D(tex2, vec2(0.5, 0.5)).r] [vcolor]);
        lumscale = hdrparams.x * -log2(1.0 - clamp(avglum, 0.03, 0.3))/(avglum + 1e-4);
        lumsaturate = -log2(1.0 - hdrparams.y) / lumscale;
    }
  ]
]

hdrtonemapfrag = [
    result [{
        // color = 1.0 - exp2(-color*lumscale);
        float lum = dot(@arg1, vec3(@lumweights));
        @arg1 = min(@arg1, lumsaturate);
        @arg1 *= (1.0 - exp2(-lum*lumscale)) / (dot(@arg1, vec3(@lumweights)) + 1e-4);
    }]
]

hdrtonemapdefs = [
    result [
        uniform vec4 hdrparams;
        uniform vec2 hdrgamma;
        in vec2 texcoord0, texcoord1;
        flat in float lumscale, lumsaturate;
    ]
]

hdrtonemapshaders = [
  (? $arg1 lazyshader shader) 0 [hdrnop@arg1] [
    in vec4 vvertex;
    @(screentexcoord 0)
    out vec2 texcoord0;
    void main(void)
    {
        gl_Position = vvertex;
        texcoord0 = vtexcoord0; 
    }
  ] [
    @arg2
    uniform sampler2DRect tex0;
    in vec2 texcoord0;
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 color = texture2DRect(tex0, texcoord0).rgb;
        fragcolor.rgb = color;
        @arg4
        @(? $arg3 $arg3 [fragcolor.a = 0.0;])
    }
  ]

  (? $arg1 lazyshader shader) 0 [hdrtonemap@arg1] (hdrtonemapvertexshader) [
    @arg2
    uniform sampler2DRect tex0, tex1;
    @(hdrtonemapdefs)
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 bloom = texture2DRect(tex1, texcoord1).rgb*hdrparams.w;
        vec3 color = texture2DRect(tex0, texcoord0).rgb*2.0;
        color += bloom;
        @(hdrgammadecode color)
        @(hdrtonemapfrag color)
        @(hdrgammaencode color)
        fragcolor.rgb = color;
        @arg4
        @(? $arg3 $arg3 [fragcolor.a = 0.0;])
    }
  ]

  if $msaasamples [msaatonemapshaders $arg1 $arg2 $arg3 $arg4]
  if (= $msaasamples 2) [msaasplitshaders $arg1 $arg2 $arg3 $arg4]
]

msaatonemapshaders = [
  if (=s $arg1 "") [lazyshader 0 [msaatonemapsample] (hdrtonemapvertexshader) [
    #extension GL_ARB_sample_shading : enable
    uniform sampler2DRect tex1;
    uniform sampler2DMS tex0;
    @(hdrtonemapdefs)
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 bloom = texture2DRect(tex1, texcoord1).rgb*hdrparams.w;
        vec3 color = texelFetch(tex0, ivec2(texcoord0), gl_SampleID).rgb*2.0;
        color += bloom;
        @(hdrgammadecode color)
        @(hdrtonemapfrag color)
        @(hdrgammaencode color)
        fragcolor = vec4(color, 0.0);
    }
  ]]

  lazyshader 0 [msaatonemap@arg1] (hdrtonemapvertexshader) [
    @arg2
    uniform sampler2DRect tex1;
    uniform sampler2DMS tex0;
    @(hdrtonemapdefs)
    layout(location = 0) out vec4 fragcolor;
    void main(void)
    {
        vec3 bloom = texture2DRect(tex1, texcoord1).rgb*hdrparams.w;
        vec3 resolved = vec3(0.0);
        for(int sampleidx = 0; sampleidx < @msaasamples; sampleidx++)
        {
            vec3 color = texelFetch(tex0, ivec2(texcoord0), sampleidx).rgb*2.0;
            color += bloom;
            @(hdrgammadecode color)
            @(hdrtonemapfrag color)
            @(hdrgammaencode color)
            resolved += color;
        }
        fragcolor.rgb = resolved * @(divf 1 $msaasamples);
        @arg4
        @(? $arg3 $arg3 [fragcolor.a = 0.0;])
    }
  ]
]

msaasplitshaders = [
  lazyshader 0 [msaatonemapsplit@arg1] (hdrtonemapvertexshader) [
    @arg2
    uniform sampler2DRect tex1;
    uniform sampler2DMS tex0;
    @(hdrtonemapdefs)
    @(loopconcat i $msaasamples [result [
        layout(location = @i) out vec4 fragcolor@i;
    ]])
    void main(void)
    {
        vec3 bloom = texture2DRect(tex1, texcoord1).rgb*hdrparams.w;
        @arg4
        @(loopconcat i $msaasamples [result [
            vec3 color@i = texelFetch(tex0, ivec2(texcoord0), @i).rgb*2.0 + bloom;
            @(hdrgammadecode [color@i])
            @(hdrtonemapfrag [color@i])
            @(hdrgammaencode [color@i])
            fragcolor@i.rgb = color@i;
            @(if $arg3 [result [
                @(strreplace $arg3 [fragcolor] [fragcolor@i])
            ]] [result [
                fragcolor@i.a = 0.0;
            ]])
        ]])
    }
  ]
]

hdrtonemapshaders ""
hdrtonemapshaders "luma" [] [fragcolor.a = dot(fragcolor.rgb, vec3(@lumweights));]
hdrtonemapshaders "stencil" [] [fragcolor.a = 1.0;]
hdrtonemapshaders "masked" (if (= $gdepthformat 1) [
    gfetchdefs tex3
] [
    gfetchdefs tex4 $msaasamples
]) [ 
    fragcolor.a = mask;
] (if (= $gdepthformat 1) [result [
    float mask = gfetch(tex3, texcoord0).a;
]] [result [
    float mask = gfetch(tex4, texcoord0).a;
    @(? $msaasamples [mask = step(0.75, mask);])
]])

