#include "/lib/shadow/warp.glsl"

//const bool shadowtex1Mipmap = true;

#include "bokeh.glsl"

#ifdef fastShadows
float shadowFilter0(in sampler2DShadow shadowtex, in vec3 wPos) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    float shade     = shadow2DLod(shadowtex, vec3(wPos.xy+offset, wPos.z), 0).x;
        shade      += shadow2DLod(shadowtex, vec3(wPos.xy-offset, wPos.z), 0).x;
        shade      += shadow2DLod(shadowtex, wPos.xyz, 0).x*0.5;
    return shade*0.4;
}
vec4 shadowcolFilter0(in sampler2DShadow shadowtex, in vec3 wPos) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    vec4 shade     = shadow2D(shadowtex, vec3(wPos.xy+offset, wPos.z));
        shade      += shadow2D(shadowtex, vec3(wPos.xy-offset, wPos.z));
        shade      += shadow2D(shadowtex, wPos.xyz)*0.5;
    return shade*0.4;
}

vec3 getShadowCoordinate2D(in vec3 screenpos, in float bias, out float distortion) {
	vec3 position 	= screenpos;
		position   += vec3(bias)*vec.light;
		position 	= viewMAD(gbufferModelViewInverse, position);
		position 	= viewMAD(shadowModelView, position);
		position 	= projMAD(shadowProjection, position);
		position.z *= 0.2;

    distortion      = 1.0;
    warpShadowmap(position.xy, distortion);

	return position*0.5+0.5;
}

#else
float getTexshadow(sampler2D shadowtex, vec2 coord, float cd) {
    return 1.0-saturate((cd-textureLod(shadowtex, coord, 0).x*256)*10.0-0.06);
}

float shadowFilter0(in sampler2D shadowtex, in vec3 wPos, in float cd) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    float shade     = getTexshadow(shadowtex, wPos.xy+offset, cd);
        shade      += getTexshadow(shadowtex, wPos.xy-offset, cd);
        shade      += getTexshadow(shadowtex, wPos.xy, cd)*0.5;
    return shade*0.4;
}
vec4 shadowcolFilter0(in sampler2D shadowtex, in vec3 wPos) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    vec4 shade     = texture(shadowtex, wPos.xy+offset);
        shade      += texture(shadowtex, wPos.xy-offset);
        shade      += texture(shadowtex, wPos.xy)*0.5;
    return shade*0.4;
}

#include "filter.glsl"

vec3 getShadowCoordinate(in vec3 screenpos, in float bias, out float distortion, out float cdepth) {
	vec3 position 	= screenpos;
		position   += vec3(bias)*vec.light;
		position 	= viewMAD(gbufferModelViewInverse, position);
		position 	= viewMAD(shadowModelView, position);
		position 	= projMAD(shadowProjection, position);
		position.z *= 0.2;

    distortion      = 1.0;
    warpShadowmap(position.xy, distortion);

    vec3 tpos   = position;
        tpos.xy *= distortion;
        tpos    = projMAD(shadowProjectionInverse, tpos);

    cdepth      = -tpos.z;

	return position*0.5+0.5;
}

#include "vps.glsl"
#endif

#if (defined s_sss || defined s_fakeGI)
    #include "indirect.glsl"
#endif

#ifndef shadowBias
    #define shadowBias 0.08
#endif

void getDirectLight(bool diffuseLit) {
    float bias          = shadowBias*(3072.0/shadowMapResolution);
    float distortion    = 0.0;
    vec3 viewpos        = pos.view;

    #ifdef temporalAA
        viewpos = getViewpos(depth.depth, taaJitter(gl_FragCoord.xy/vec2(viewWidth, viewHeight), -0.5));
    #endif

    #ifdef fastShadows
        vec3 scoord         = getShadowCoordinate2D(viewpos, bias, distortion);
    #else
        float cd    = 0.0;

        vec3 scoord         = getShadowCoordinate(viewpos, bias*0.25, distortion, cd);
    #endif

    float shade         = 1.0;
    vec4 shadowcol      = vec4(1.0);
    bool translucencyShadow = false;

    #ifdef translucentPass
        const float translucencyDelta = 0.2;
    #else
        const float translucencyDelta = 0.07;
    #endif

    if (diffuseLit) {
        #ifdef fastShadows
            shade       = shadowFilter0(shadowtex1, scoord);
            float temp1 = shadowFilter0(shadowtex0, scoord);
            translucencyShadow = temp1<shade;

            if (translucencyShadow) shadowcol   = shadowcolFilter0(shadowcolor0, scoord);
        #else
            #ifdef s_vps
                float sigma = getVPSSigma(scoord, cd, distortion);
            #else
                float sigma = 0.00014/distortion;
            #endif
            #if s_shadowfilter==0
                shade       = shadowFilter0(shadowtex1, scoord, cd);
                float temp1 = shadowFilter0(shadowtex0, scoord, cd);
                translucencyShadow = temp1<shade;

                if (translucencyShadow) shadowcol   = shadowcolFilter0(shadowcolor0, scoord);
            #elif s_shadowfilter==1
                shade       = shadow15(shadowtex1, scoord, cd, sigma);
                float temp1 = shadow15(shadowtex0, scoord, cd, sigma);
                translucencyShadow = (shade-temp1)>translucencyDelta;

                if (translucencyShadow) shadowcol   = shadowcol15(shadowcolor0, scoord, sigma);
            #elif s_shadowfilter==2
                shade       = shadow30(shadowtex1, scoord, cd, sigma);
                float temp1 = shadow30(shadowtex0, scoord, cd, sigma);
                translucencyShadow = (shade-temp1)>translucencyDelta;

                if (translucencyShadow) shadowcol   = shadowcol15(shadowcolor0, scoord, sigma);
            #endif
        #endif
    }
    sdata.shadow    = shade;
    sdata.shadowcolor = translucencyShadow ? mix(vec3(1.0), shadowcol.rgb, shadowcol.a) : vec3(1.0);

    #if (defined s_sss || defined s_fakeGI)
        if (min(sdata.shadow, sdata.diffuse)<0.99 && isEyeInWater==0) {
            float fade  = 1.0-sstep(length(pos.world-pos.camera), 80.0, 100.0);
            if (fade>0.0) {
                #ifdef fastShadows
                    #ifdef s_fakeGI
                        float indirectLight = shadowGI(shadowtex1, scoord, 0.01/distortion)*sqrt(sdata.diffuse);
                    #endif

                    #ifdef s_sss
                        vec3 sss    = sssGradient(scoord, distortion);
                    #endif
                #else
                    #ifdef s_fakeGI
                        float indirectLight = shadowGI(shadowtex1, scoord, cd, 0.01/distortion)*sqrt(sdata.diffuse);
                    #endif

                    #ifdef s_sss
                        vec3 sss    = sssGradient(scoord, distortion, cd);
                    #endif
                #endif

                float lit           = min(sdata.shadow, sdata.diffuse);

                #ifdef s_fakeGI
                    sdata.indirect     += indirectLight*0.2*fade*(1.0-lit)*mix(vec3(1.0), pow2(scene.albedo), sqrt(pbr.sss)*0.66);
                #endif

                #ifdef s_sss
                    float phase         = pow3(linStep(dot(vec.view, vec.light), 0.6, 1.0))*0.7+0.3;
                    sdata.indirect     += sss*fade*(1.0-lit)*pbr.sss*phase*16.0;
                #endif
            }
        }
    #endif
}