#version 430

layout(binding=0) uniform sampler2D tex;
in vec3 color;
out vec4 frag;

uniform float g_time;
precision highp float;
varying highp vec2 coord;
layout(binding=0) uniform sampler2D src;
layout(binding=1) uniform sampler2D srcBlur;
layout(binding=2) uniform sampler2D srcBlur2;
layout(binding=3) uniform sampler2D srcTex;
layout(binding=4) uniform sampler2D srcTex2;
layout(binding=5) uniform sampler2D srcEnv;
uniform vec2 mPos = vec2(640.0, 360.0);
uniform float g_time;

vec2 getBump(sampler2D sampler, vec2 texCoord) {
    vec2 ofsX = vec2(1.0/1280.0, 0.0)*1.0+vec2(0.5/1280.0, 0.0)*1.0;
    vec2 ofsY = vec2(0.0, 1.0/720.0)*1.0+vec2(0.0, 0.5/720.0)*1.0;
    float texX = texture2D(sampler, texCoord+ofsX.xy).g;
    float texY = texture2D(sampler, texCoord+ofsY.xy).g;
    float texBumpBrightX = texture2D(sampler, texCoord-ofsX.xy*0.0).g;
    float texBumpBrightY = texture2D(sampler, texCoord-ofsY.xy*0.0).g;
    vec2 result = vec2(texX-texBumpBrightX, texY-texBumpBrightY);
    return result;
}

float timeWave(float v, float timma) {
   return sin(v+timma); // sin(v*(cos(timma+0.231)+1.2)+3.0*cos(v*(sin(timma)+1.0)+0.123))+sin(timma);
}

vec2 getBumpWave(sampler2D sampler, vec2 texCoord, float timma) {
    vec2 ofsX = vec2(1.0/1280.0, 0.0)*1.0+vec2(0.5/1280.0, 0.0)*1.0;
    vec2 ofsY = vec2(0.0, 1.0/720.0)*1.0+vec2(0.0, 0.5/720.0)*1.0;
//                    float texX = sin(texture2D(sampler, texCoord+ofsX.xy).g+timma);
//                    float texY = sin(texture2D(sampler, texCoord+ofsY.xy).g+timma);
//                    float texBumpBrightX = sin(texture2D(sampler, texCoord-ofsX.xy*0.0).g+timma);

    float texX = timeWave(texture2D(sampler, texCoord+ofsX.xy).g, timma)+timeWave(texture2D(sampler, texCoord+vec2(0.32,0.2)+ofsX.xy).g, timma+0.921);
    float texY = timeWave(texture2D(sampler, texCoord+ofsY.xy).g, timma)+timeWave(texture2D(sampler, texCoord+vec2(0.32,0.2)+ofsY.xy).g, timma+0.921);
    float texBumpBrightX = timeWave(texture2D(sampler, texCoord-ofsX.xy*0.0).g, timma)+timeWave(texture2D(sampler, texCoord+vec2(0.32,0.2)).g, timma+0.921);

  //  float texBumpBrightY = texture2D(sampler, texCoord-ofsY.xy*0.0).g;
    vec2 result = vec2(texX-texBumpBrightX, texY-texBumpBrightX);
    return result;
}

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

vec3 tonemapUC2(vec3 x) {
    float A = 0.15;
    float B = 0.50;
    float C = 0.10;
    float D = 0.20;
    float E = 0.02;
    float F = 0.30;
    return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}

vec3 rotateYZ(vec3 p, float a) {
  vec3 r = p;
  r.y = cos(a)*p.y - sin(a)*p.z;
  r.z = sin(a)*p.y + cos(a)*p.z;
  return r;
}

vec3 rotateXZ(vec3 p, float a) {
  vec3 r = p;
  r.x = cos(a)*p.x - sin(a)*p.z;
  r.z = sin(a)*p.x + cos(a)*p.z;
  return r;
}

vec3 rotateXY(vec3 p, float a) {
  vec3 r = p;
  r.x = cos(a)*p.x - sin(a)*p.y;
  r.y = sin(a)*p.x + cos(a)*p.y;
  return r;
}

float camFromPlaneDist = 0.50;
float heightMul = 1.0;

int hitObjIndex = 0;
int rayInObjIndex = 0;

float obj(sampler2D objSampler, vec3 r) {
//    r.z -= camFromPlaneDist;
//    r = rotateXZ(r, 0.1);
//    r.z += camFromPlaneDist;

    float thickness = 2.0;
    vec4 tt = texture2D(objSampler, r.xy+vec2(0.5, 0.5));
    float bright = dot(tt.rgb, vec3(0.344, 0.5, 0.156));

    if (bright < 0.02) {
        rayInObjIndex = 1;
    } else {
        rayInObjIndex = 2;
    }
   // bright += 0.2+getBumpWave(srcTex2, r.xy*0.1, time)*0.2;
   // bright += 0.2+0.2*sin(r.x*36.0+time*2.0)+0.0*cos(r.y*32.0+time*1.23);

    if (abs(tt.r-tt.g)+abs(tt.r-tt.g)+abs(tt.g-tt.b) < 0.12 && bright > 0.1) {
//        float boxing = 50.0;
//        r.xy = r.xy*boxing;
//        r.xy = (r.xy - fract(r.xy))/boxing;
//        tt = texture2D(objSampler, r.xy+vec2(0.5, 0.5));
        rayInObjIndex = 3;
     //   tt *= 0.0;
    }

    bright = dot(tt.rgb, vec3(0.344, 0.5, 0.156));
    bright = bright*1.0+0.0;

    float height = (camFromPlaneDist+(1.0-bright)*heightMul);
    return height-r.z;
}

void main() {
    vec2 di = vec2(coord-mPos);
    float dist = clamp(1.0-sqrt(dot(di,di)), 0.0, 1.0);
    vec2 coordC = coord-vec2(0.5, 0.5);
    vec3 xof = -vec3(mPos-vec2(0.5, 0.5), 0.0);

    vec3 lookAt = vec3(0.0, 0.0, 0.3750);

    vec3 ray = vec3(coordC*1.0, 1.0);
    vec3 rayOrigin = vec3(0.0, 0.0, -0.450);

    ray -= lookAt;
    rayOrigin -= lookAt;

    float maxAngle = 0.95;


    ray = rotateXZ(ray, -xof.x*maxAngle*3.141592);
    ray = rotateYZ(ray, -xof.y*maxAngle*3.141592);

    rayOrigin = rotateXZ(rayOrigin, -xof.x*maxAngle*3.141592);
    rayOrigin = rotateYZ(rayOrigin, -xof.y*maxAngle*3.141592);


    ray += lookAt;
    rayOrigin += lookAt;

    vec4 res = vec4(0.0);
    float dd = pow(dist, 40.0)*1.0;
    dist = (pow(dist, 16.0)*1.0+pow(dist, 1.0)*1.0)*1.0;
    int i=0;
    int hitText=0;
    float hitH = 0.0;
    float hito = 0.50;

    heightMul = 0.3;

    // make the rays to start from the top of the plane
    float rayCorrect = (camFromPlaneDist-rayOrigin.z)/ray.z;
    ray *= rayCorrect;

    ray += rayOrigin;
    vec3 rayDir = (ray-rayOrigin);
    vec3 eye = ray;

    float ykke = heightMul*1.05/rayDir.z;

    float scrLimitX = 0.5;
    float scrLimitY = 0.5;

    vec3 light = vec3((mPos-vec2(0.5, 0.5)), camFromPlaneDist-0.25);
    light.xy /= camFromPlaneDist*1.250;

    float lighter = 0.0;

    vec3 normal = vec3(0.0, 0.0, 1.0);


    float loops = 32.0;
    float depth = 1.0/loops*1.0;

    vec3 rayP;
    vec3 hp = vec3(0.0);

    float dof = 0.0;
    float focusZ = camFromPlaneDist+0.0;

    vec3 rayDof = vec3(0.0, 0.0, 0.0);
    vec3 rayPreDof = ray;

    vec4 color = vec4(0.0);
    vec3 hitRay = vec3(0.0);
    vec4 hitColor = vec4(0.0);
    vec3 hitNormal = vec3(0.0);

    for (int iii=0; iii<2; iii++) {
        res = vec4(0.0);
        hitText = 0;
        hitObjIndex = -1;
        rayInObjIndex = -1;
        if (iii==0) {
            loops = 8.0;
        }
        if (iii==1) {
            vec3 rdn = normalize(ray-rayOrigin);
            vec3 refn = reflect(rdn, hitNormal);
            rayDir = refn*0.50;
            rayPreDof = hitRay-rayDir*ykke*depth*0.8;
            loops = 4.0;
        }

        depth = 1.0/loops*1.0;

        for (i=0; float(i)<loops; i++) {
            ray = rayPreDof;
            rayP = ray;
            ray += rayDir*depth*ykke;
            rayPreDof = ray;

            vec3 rayForDof = ray;
            rayForDof -= rayOrigin;
            rayForDof /= rayCorrect;
            float dofS = dof*abs(rayForDof.z-focusZ);

            ray.xy += vec2(rand(coordC+g_time*0.001)*0.01*dofS, rand(coordC*2.32+g_time*0.001)*0.01*dofS);

            vec3 lightToRay = light-ray;
            float distToLight = sqrt(dot(lightToRay, lightToRay));
            lighter += pow(1.0/(0.50+distToLight*12.0), 4.0)*3.0;

            vec2 rayC = ray.xy + vec2(0.5,0.5);
            if (ray.x < -scrLimitX || ray.x > scrLimitX) {
                continue;
            }
            if (ray.y < -scrLimitY || ray.y > scrLimitY) {
                continue;
            }
            if (obj(srcBlur, ray) < 0.0) {
                // hit
                // do binary search
                float refLoops = 8.0;
                float rayD = -0.50;
                float ik = 0.0;

                for (int ii=0; float(ii)<refLoops; ii++) {
                    ray += rayD*rayDir*depth*ykke;
                    ik += rayD/loops;
                    if (obj(srcBlur, ray) < 0.0) {
                        if (rayD <= 0.0) {
                            rayD *= 0.5;
                        } else {
                            rayD *= -0.5;
                        }
                    } else {
                        if (rayD <= 0.0) {
                            rayD *= -0.5;
                        } else {
                            rayD *= 0.5;
                        }
                    }
                }
                float eps = 0.0025;

                vec2 kor = vec2(0.5/1280.0, 0.5/720.0)*0.0;

                hitObjIndex = rayInObjIndex;

                float n1a = obj(srcBlur, vec3(ray.xy+vec2(0.0+eps, 0.0)+kor, ray.z));
                float n1b = obj(srcBlur, vec3(ray.xy+vec2(0.0-eps, 0.0)+kor, ray.z));
                float n2a = obj(srcBlur, vec3(ray.xy+vec2(0.0, 0.0+eps)+kor, ray.z));
                float n2b = obj(srcBlur, vec3(ray.xy+vec2(0.0, 0.0-eps)+kor, ray.z));

                normal = vec3((n1b-n1a)*1.0, (n2b-n2a)*1.0, 8.0*eps);

                hitH = ray.z;
                hito = ray.z*2.0;
                hitText = 1;
                res.a = 1.0;
                i = int(loops);
                break;
            }
        }

        lighter /= float(i)+1.0;

        if (iii==0) {
            if (ray.x < -scrLimitX || ray.x > scrLimitX) {
                discard;
            }
            if (ray.y < -scrLimitY || ray.y > scrLimitY) {
                discard;
            }
        }

        if (hitText != 0) {
            hitText = hitObjIndex;
        }

        normal = normalize(normal);

        if (hitText==1) {
            ray.xy *= 0.1;
            res.rgb = vec3(0.50)*0.0+0.050*dist*texture2D(srcTex2, ray.xy*0.10+vec2(0.5,0.5)).rgb;
            res.rgb -= vec3(0.50)*0.0+0.050*dist*texture2D(srcTex2, ray.xy*1.0+vec2(0.5,0.5)).rgb;
            res.rgb += vec3(0.50)*0.0+0.050*dist*texture2D(srcTex2, ray.xy*10.0+vec2(0.5,0.5)).rgb;
            ray.xy *= 10.0;
            res.a = 1.0;
        }

        vec4 texCol = vec4(0.0);

        if (hitText==2) {
            ray.xy *= 0.1;
            float kba = clamp((abs(normal.z)-0.3)*100.0, 0.0, 1.0);
            res.rgb += vec3(0.50)*0.0+0.30*dist*kba*texture2D(srcBlur, (ray.xy*10.0+vec2(0.5,0.5))).rgb;
            kba = 1.0-kba;
            res.rgb += vec3(0.50)*0.+dist*0.30*kba*texture2D(srcBlur, vec2(abs(ray.x)*100.0, hito*1.0+ray.x*0.0)).rgb;
            ray.xy *= 10.0;
            texCol = res;
        }

        if (hitText==3) {
            float kba = clamp((abs(normal.z)-0.3)*100.0, 0.0, 1.0);
            res.rgb += vec3(0.50)*0.0+0.10*dist*kba*texture2D(srcBlur, (ray.xy*1.0+vec2(0.5,0.5))).rgb;
            kba = 1.0-kba;
            res.rgb += vec3(0.50)*0.0+dist*0.10*kba*texture2D(srcBlur, vec2(abs(ray.x)*10.0, hito*1.0)).rgb;
            texCol = res;
        }

        light -= ray;
        float dh = light.z;

        vec2 dir = light.xy;

        vec2 lp = ray.xy - dir*0.0;
        light = normalize(light);

        vec2 hup;
        loops=32.0;
        if (iii>0) {
            loops = 0.0;
        }
        float notInShadow = 1.0;
        for (i=0; float(i)<loops; i++) {
            float ik = pow(float(i)/loops+rand(coord)*1.0/loops, 2.0);
            hup = lp+dir*ik;
            float hei = ray.z+dh*ik;
            vec3 rayS = vec3(hup, hei+0.1*ik);
            if (-obj(src, rayS) > 0.02) {
                vec4 kkk = texture2D(srcBlur2, hup+vec2(0.5,0.5));
                notInShadow -= kkk.g*kkk.g*1.50;
                if (notInShadow < 0.02) {
                    notInShadow = 0.0;
                    i = int(loops);
                    break;
                }
            }
        }
        notInShadow = clamp(notInShadow, 0.0, 1.0);

        res.rgb *= res.rgb;
        res.rgb *= 0.0+20.0*notInShadow*clamp(pow(dot(normal, -light)*1.0, 1.0)*1.0, 0.0, 1.0);

        light.z += 0.5;
        vec3 ref = reflect(light, normal);
        ref = normalize(ref);
        vec3 rayDirNorm = normalize(ray-rayOrigin);
        vec3 ref2 = reflect(rayDirNorm, normal);
        float lightS = pow(clamp(dot(rayDirNorm, ref), 0.0, 1.0), 40.0)*1.0;

        res.rgb += 0.50*dist*lightS*notInShadow;

//       vec4 texEnv = texture2D(srcEnv, vec2(ref2.x*0.2+0.5, ref2.y*0.2+0.5));
//       texEnv *= texEnv;
//       vec4 env = texEnv*3.038*dist*(notInShadow*0.5+0.5);
//       res.rgb *= 0.00+env.rgb;

//        if (hitText || 1) {
//            // vec4 tt = texture2D(objSampler, r.xy+vec2(0.5, 0.5));
//            float bright = dot(texCol.rgb, vec3(0.344, 0.5, 0.156));
//         //   if (abs(texCol.r-texCol.g)+abs(texCol.r-texCol.g)+abs(texCol.g-texCol.b) > 0.01) {
//          //      res.rgb *= texEnv.rgb*4.03*dist*(notInShadow*0.5+0.5);
//         //   }
//        }

        hitRay = ray;
        hitColor = res;
        hitNormal = normal;

        if (iii==0) {
            color += res*0.50;
        } else {
            // reflection
            color += res*0.50;
        }
    }

    color *= 2.0;

    float vignette = clamp((1.0-sqrt(dot(coordC, coordC))*1.350), 0.0, 1.0)+rand(coord)*0.0125;
    vignette *= vignette;
    color *= vignette;
    color.rgb = tonemapUC2(color.rgb*6.0);
    color = pow(color, vec4(0.50*1.0))*1.50;
    color = clamp(color, 0.0, 1.0);

    color.a = 1.0;

    gl_FragColor = vec4(color) * qt_Opacity;
}
