/*
====================================================================================================

    Copyright (C) 2020 RRe36

    All Rights Reserved unless otherwise explicitly stated.


    By downloading this you have agreed to the license and terms of use.
    These can be found inside the included license-file
    or here: https://rre36.com/copyright-license

    Violating these terms may be penalized with actions according to the Digital Millennium
    Copyright Act (DMCA), the Information Society Directive and/or similar laws
    depending on your country.

====================================================================================================
*/

shadowData getShadowSubsurface(bool diffLit, vec3 scenePos, vec3 viewDir, vec3 albedo, float opacity) {
    const float bias    = 0.08*(2048.0/shadowMapResolution);
    float warp          = 1.0;

    shadowData data     = shadowData(1.0, vec3(1.0), vec3(0.0));

    #ifdef shadowVPSEnabled
    vec3 pos        = scenePos + vec3(bias) * lightvec;
    float a         = length(pos);
        pos         = viewMAD(shadowModelView, pos);
        pos         = projMAD(shadowProjection, pos);

        pos.z      *= 0.2;
        pos.z      -= 0.0012*(saturate(a/256.0));

    vec2 posUnwarped = pos.xy;

        pos.xy      = shadowmapWarp(pos.xy, warp);
        pos         = pos * 0.5 + 0.5;
    #else
        vec3 pos    = getShadowmapPos(scenePos, bias, warp);
    #endif

    if (diffLit) {
        #ifdef shadowVPSEnabled
            float sigma     = shadowVPSSigma(shadowtex1, pos, posUnwarped, warp);

            vec4 shadow     = shadowSharp15(pos, sigma);

            data.shadow     = shadow.w;
            data.color      = shadow.rgb;
        #else
            float s0        = getShadowSoft(shadowtex0, pos);
            float s1        = getShadowSoft(shadowtex1, pos);

            bool translucent = distance(s0, s1)>0.1;

            data.shadow   = s1;

            if (translucent) {
                float s0depth = texture(shadowtex0, pos.xy).x;
                float dist  = distance(s0depth, pos.z) * 2.0 * 256.0 * rcp(0.2);
                data.color  = getShadowcol(shadowcolor0, pos.xy);
            }
        #endif
    }

    if (opacity < (0.5 / 255.0)) return data;

    float bluenoise     = ditherBluenoise();
    float sssRad        = 0.001 * sqrt(opacity);
    vec3 sssShadow      = vec3(0.0);
    
    #define sssLoops 5

    float rStep         = rcp(float(sssLoops));
    float offsetMult    = rStep;
    vec2 noise          = vec2(sin(bluenoise * pi), cos(bluenoise * pi));
    
    for (int i = 0; i < sssLoops; i++) {
        vec3 offset         = vec3(noise, -bluenoise) * offsetMult;
        float falloff       = sqr(rcp(1.0 + length(offset)));
            offset.xy      *= rcp(warp);
            offset         *= sssRad;

        float sssShadowTemp = textureShadowPCF(shadowtex1, pos + vec3(offset.xy, offset.z));
            sssShadowTemp  += textureShadowPCF(shadowtex1, pos + vec3(-offset.xy, offset.z));
            sssShadowTemp  *= falloff;

            sssShadow      += vec3(sssShadowTemp);
            offsetMult     += rStep;
    }

    sssShadow   = saturate(sssShadow * rStep * 1.2);

    vec3 albedoNorm     = normalize(albedo) * (v3avg(albedo) * 0.5 + 0.5);
    vec3 scattering     = mix(albedoNorm * normalize(albedo), mix(albedoNorm, vec3(0.8), sssShadow * 0.7), sssShadow) * sssShadow;
        scattering     *= mix(mieHG(dot(viewDir, lightvecView), 0.65), 1.2, 0.4);  //eyeballed to look good because idk the accurate version

    data.subsurfaceScatter = scattering * sqrt2 * rpi * opacity;

    return data;
}