#version 430

in vec2 uv;
in float br;

in vec2 puv;

// in float foc;

in vec3 pw;
in vec3 pv;

in vec3 pView;

layout(location = 0) out vec4 frag;
// layout(location = 1) out vec4 frag2;

uniform float g_time;


vec2 rotateXY2(vec2 p, float a) {
  vec2 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 deg2pi = 2.0*3.141592/360.0;



layout(binding=0) uniform sampler2D tex;



// TODO #include "noise.h"


uniform float noiseOct = 5.0;
uniform float noiseOctMul = 2.50;
uniform float noiseOctAmp = 0.7;
uniform float noiseSplineEnabled = 0.0;

// from pouet raymarching thread by las of mercury
float perlin(vec3 p) {
    vec3 i = floor(p);
    vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
    vec3 f = cos((p-i)*3.14159265)*(-.5)+.5;
    a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
    a.xy = mix(a.xz, a.yw, f.y);
    return mix(a.x, a.y, f.z)-0.0;
}
float turb3(vec3 c) {
        float r=0.0;
        float s=0.5;
        for (int i=0;i<noiseOct;i++) {
                r+=s*(perlin(c));
                c*=noiseOctMul;
                s*=noiseOctAmp;
        }
        return r;
}

vec3 posd(float pw) {
    return vec3(sin(pw)*17.0, cos(pw*1.7)*13.0, sin(pw*0.78+cos(pw*0.4))*11.0)*32.0;
}

float getSplineValue(float t, float p0, float pt0, float p1, float pt1) {
    float t2 = t*t;
    float t3 = t*t*t;
    float p = (2.0*t3-3.0*t2+1.0)*p0+(t3-2.0*t2+t)*pt0+(-2.0*t3+3.0*t2)*p1+(t3-t2)*pt1;
    return p;
}

float perlin4(vec4 p) {
//    vec4 pf1 = floor(p);
//    vec4 pf2 = floor(p+vec4(1.0));

    float p1 = perlin(p.xyz+posd(floor(p.w)+1.0));
    float p2 = perlin(p.xyz+posd(floor(p.w)+2.0));

    if (noiseSplineEnabled > 0.5) {
        float p0 = perlin(p.xyz+posd(floor(p.w)));
        float p3 = perlin(p.xyz+posd(floor(p.w)+3.0));
        float ki = fract(p.w);
        return getSplineValue(ki, p1, p2-p0, p2, p3-p1);
    } else {
        float ki = smoothstep(0.0, 1.0, fract(p.w));
        return p1*(1.0-ki)+p2*(ki);
    }
}

float turb4(vec4 c, float det) {
        float r=0.0;
        float s=0.5;

        // det = 1.0;
        float no = clamp(det*noiseOct, 1.0, noiseOct);

        for (int i=0;i<no;i++) {
                r+=s*(perlin4(c));
                c*=noiseOctMul;
                s*=noiseOctAmp;
        }
        return r;
}

// end of "noise.h"

uniform mat4 viewInvMatrix;

uniform mat4 viewSecond;
uniform mat4 projectionMatrix;
uniform mat4 projSecond;

uniform float colorR = 1.5;
uniform float colorG = 1.1;
uniform float colorB = 0.6;

uniform float drawAlpha = 0.650;

uniform float shadowDebug = 0.0;

layout(binding=2, r32f) uniform image2D pardexTransmittance;


uniform float shadowZOfs = -150.0;
uniform float shadowZScale = -5.0;

void main() {
    vec2 uvS = uv;
    uvS.y = 1.0-uvS.y;

    float ne = 10.0;
    //uvS += vec2((g_time*ne)*0.01, (g_time*ne)*0.02);

    vec4 r = texture2D(tex, uvS);

    vec2 pm = (puv-vec2(0.5))*2.0;
    float pc = dot(pm, pm);

    if (pc < 1.0) {
        pc = (1.0-pc);
    } else {
        pc = 0.0;
    }

   // pc = pow(pc, 0.1);
//    pc = pow(pc, 0.010+clamp(foc*0.01, 0.0, 2.0));

    float det = clamp(1.0+pv.z*0.001, 0.0, 1.0);
    //float det = 1.0;

    ne = 5.0;
    vec4 uvn = vec4(uv*1.0, (g_time*ne)*0.01-uv.x, (g_time*ne)*0.0034-uv.x);

    uvn.xy += uvn.zw*0.050;

   // det = 1.0;
    float turbsu = 1.0;
  //  turbsu = turb4(vec4(puv, 0.0, 0.0)*0.750+vec4(uvn)*0.20+vec4(pw.xyz, 0.0)*0.05+vec4(pv.xyz, 0.0)*0.0+vec4(0.0, 0.0, 0.0, g_time*0.1), det);


     pc *= abs(turbsu);
    // pc *= turbsu;

  //  pc = sqrt(pc);

     //r.rgb *= r.rgb;
     r.rgb += vec3(0.0);
    // r.rgb *= vec3(pow(pc, 0.5))*1.50;
     //r.rgb *= vec3(1.5, 1.1, 0.6)*pow(puv.y, 1.50)*2.5;
  //   r.rgb *= vec3(1.5, 1.1, 1.6)*pow(puv.y, 1.50)*2.5;
  //   r.rgb *= vec3(1.5, 1.1, 0.6)*pow(puv.y, 1.0)*2.0;
     // r.rgb *= vec3(colorR, colorG, colorB)*pow(puv.y, 2.50)*1.50;
     r.rgb *= vec3(colorR, colorG, colorB)*pow(puv.y, 0.50)*0.50;

     r.rgb = clamp(r.rgb*1.0, 0.0, 100.0);


     float shadow = 0.0;

     vec4 pkv = viewInvMatrix*vec4(pView, 1.0);
     //pkv /= pkv.w;
     pkv = viewSecond*pkv;
     //pkv

     // pkv = vec4(pView, 1.0);
     vec3 pkvLi = pkv.xyz;
   //  pkv = projectionMatrix*pkv;
     pkv = projSecond*pkv;
     pkv /= pkv.w;
     vec2 p2ds = (pkv.xy+vec2(1.0))*0.50*255.0; // 0 to 255 range xy

     p2ds = clamp(p2ds, 0.0, 255.0);

    // int zLevel = int(-480.0-pv.z*10.0);
     int zLevel = int(shadowZOfs+pkvLi.z*shadowZScale);
     zLevel = clamp(zLevel-1, 0, 255);
     int zLevelY = zLevel/16;
     int zLevelX = zLevel-zLevelY*16;
     ivec2 zLevel2 = ivec2(zLevelX, zLevelY)*256;

     float t1 = float(imageLoad(pardexTransmittance, ivec2(p2ds)+zLevel2).x);
     float t2 = float(imageLoad(pardexTransmittance, ivec2(p2ds)+ivec2(1,0)+zLevel2).x);
     float t3 = float(imageLoad(pardexTransmittance, ivec2(p2ds)+ivec2(0,1)+zLevel2).x);
     float t4 = float(imageLoad(pardexTransmittance, ivec2(p2ds)+ivec2(1,1)+zLevel2).x);


     float bix = fract(p2ds.x);
     float biy = fract(p2ds.y);

     float t12 = mix(t1, t2, bix);
     float t34 = mix(t3, t4, bix);

      float transmit = mix(t12, t34, biy);
//      transmit = t1;

      //shadow = clamp(1.0-float(transmit)/256.0*0.05, 0.0, 1.0);

      //shadow = clamp(1.0/(float(transmit)/256.0*0.35+0.001), 0.0, 1.0);

      //transmit = pow(transmit, 1.0);
      shadow = clamp(transmit, 0.0, 1.0);

      // shadow = shadow*0.9+0.1;

      r.rgb *= vec3(shadow);

      if (shadowDebug > 0.5) {

          if (zLevel == 0) r.rgb = vec3(1.0, 0.0, 0.0);
          if (zLevel == 255) r.rgb = vec3(1.0, 0.0, 0.0);
          if (p2ds.x < 1.0) r.rgb = vec3(0.0, 1.0, 0.0);
          if (p2ds.y < 1.0) r.rgb = vec3(0.0, 1.0, 0.0);
          if (p2ds.x > 254.0) r.rgb = vec3(0.0, 1.0, 0.0);
          if (p2ds.y > 254.0) r.rgb = vec3(0.0, 1.0, 0.0);
      }
   //   r.rgb = vec3(p2ds/1.0, 0.0);

    //  if (r.r > 0.5) r.rgb = vec3(1.0);

   //   r.rgb = pow(r.rgb, vec3(0.5));

//    r.rgb *= br*(1.0+pc);
   // r.a = clamp(0.250*(pc-0.01), 0.0, 1.0);
     r.a = clamp(drawAlpha*br*(pow(pc, 1.0)-0.05), 0.0, 1.0);
    frag = r;
}

