#version 430

in vec2 uv;
in float br;

in vec2 puv;

// in float foc;

in vec3 pw;
in vec3 pv;

in vec3 prevPw;

in vec3 pView;

in float maxAge;

in vec4 ain;

layout(location = 0) out vec4 frag;
layout(location = 1) out vec4 frag2;
layout(location = 2) out vec4 frag3;
layout(location = 3) out vec4 frag4;

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 projectionMatrix;
uniform mat4 viewInvMatrix;

uniform mat4 projSecond;
uniform mat4 viewSecond;

uniform mat4 prevViewMatrix;
uniform mat4 viewMatrix;


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

uniform float drawAlpha = 0.650;
uniform float drawAlphaZero = 0.05;
uniform float drawAlphaSmooth = 0.5;

uniform float shadowDebug = 0.0;

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

layout(binding=3) uniform sampler2D texDepthLight;


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

uniform float shadowEnabled = 0.0;

uniform float puffEnabled = 0.0;
uniform float puffFreq = 1.0;

uniform float lightExp = 1.0;
uniform float bright = 1.0;

uniform float depthWrite = 0.0;

uniform float lighterShadow = 1.0;
uniform float lighterShadowAmbient = 0.2;

float zn = 0.0;
float zf = 1.0;

uniform mat4 projSecond2;
uniform mat4 projInvSecond2;
uniform mat4 viewSecond2;
uniform mat4 viewInvSecond2;
vec4 CalcEyeFromLight(in vec3 windowSpace) {
    vec3 ndcPos;
    vec2 texSize = textureSize(texDepthLight, 0).xy;
    vec4 viewport = vec4(0.0, 0.0, texSize.x, texSize.y);
    ndcPos.xy = ((2.0*windowSpace.xy)-(2.0 * viewport.xy))/(viewport.zw)-1;
    ndcPos.z = (2.0*windowSpace.z-zn-zf)/(zf-zn);
    vec4 clipPos;
    clipPos.w = projSecond2[3][2]/(ndcPos.z-(projSecond2[2][2]/projSecond2[2][3]));
    clipPos.xyz = ndcPos*clipPos.w;
    return projInvSecond2*clipPos;
}

void getLightShadows(vec4 wp, inout vec4 wpLight, inout vec2 tcLight) {
  vec4 projLight = projSecond2*viewSecond2*wp;
  tcLight = (projLight.xy/projLight.w*0.5+vec2(0.5));
  vec2 tcLightScreen = tcLight*textureSize(texDepthLight, 0).xy;
  vec3 dLight = texelFetch(texDepthLight, ivec2(tcLightScreen), 0).xyz;
  vec4 eyeLight = CalcEyeFromLight(vec3(tcLightScreen, dLight.r));
  wpLight = viewInvSecond2*eyeLight;
//  wpLight /= wpLight.w;
}


layout(binding=2) uniform sampler2D texAgePal1;
layout(binding=4) uniform sampler2D texAgePal2;

uniform float agePal1Amp = 1.0;
uniform float agePal1Freq = 0.0;
uniform float agePal1Base = 0.0;
uniform float agePal1Op = 0.0;

uniform float agePal2Amp = 0.0;
uniform float agePal2Freq = 0.0;
uniform float agePal2Base = 0.0;
uniform float agePal2Op = 0.0;

uniform float motionVel = 1.0;

vec3 getAgePal(vec3 c) {

  float ageLeft = br;
  float agePos = 1.0-ageLeft/maxAge;

  if (abs(agePal1Amp) > 0.001) {
    vec3 ap1 = texture2D(texAgePal1, vec2(agePos*agePal1Freq, 0.0)).rgb;
    if (agePal1Op < 0.5) {
      c += clamp(vec3(agePal1Base)+ap1*agePal1Amp, 0.0, 10000.0);
    } else {
      c *= clamp(vec3(agePal1Base)+ap1*agePal1Amp, 0.0, 10000.0);
    }
  }

  if (abs(agePal2Amp) > 0.0001) {
    vec3 ap2 = texture2D(texAgePal2, vec2(agePos*agePal2Freq, 0.0)).rgb;
    if (agePal2Op < 0.5) {
      c += clamp(vec3(agePal2Base)+ap2*agePal2Amp, 0.0, 10000.0);
    } else {
      c *= clamp(vec3(agePal2Base)+ap2*agePal2Amp, 0.0, 10000.0);
    }
  }

  c = clamp(c, 0.0, 10000.0);

 // c = vec3(agePos*agePos)*10.0;

  return c;
}


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

  float ne = 10.0;

  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;
  }

  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;

  vec3 pwm = pw;

 // pwm.y += (g_time-177.0)*32.0;
 // pwm.y += ain.x;

  pwm.y = ain.y;

  float turbsu = 1.0;
  if (puffEnabled > 0.5) {
    float det = clamp(1.0+pv.z*0.001, 0.0, 1.0);
    // det = 1.0;
   // turbsu = turb4((vec4(puv, 0.0, 0.0)*0.750+vec4(uvn)*0.20+vec4(pwm.xyz, 0.0)*0.05)*puffFreq+vec4(pv.xyz, 0.0)*0.0+vec4(0.0, 0.0, 0.0, g_time*0.1), det);
    turbsu = turb4((vec4(puv, 0.0, 0.0)*0.750+vec4(uvn)*0.20+vec4(pwm.xyz, 0.0)*0.05)*puffFreq+vec4(0.0, 0.0, 0.0, g_time*0.1), det);
  }

 // turbsu = 1.0;

  pc *= abs(turbsu);
  r.rgb *= vec3(colorR, colorG, colorB)*pow(puv.y, lightExp)*bright;


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


  vec4 wpLight = vec4(0.0);
  vec2 tcLight = vec2(0.0);


  float shadow = 0.0;

  vec4 pkv = viewInvMatrix*vec4(pView, 1.0);

  vec4 kk = vec4(0.0);

  if (lighterShadow > 0.5) {
    kk = pkv;
    getLightShadows(pkv, wpLight, tcLight);
  }


  //pkv /= pkv.w;
  pkv = viewSecond*pkv;
  //pkv


  int baseDimi = int(baseDim);
  int baseDimi2 = baseDimi*baseDimi;

  // 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*(baseDim*baseDim-1.0); // 0 to 255 range xy
  p2ds = clamp(p2ds, 0.0, (baseDim*baseDim-1.0));
  // int zLevel = int(-480.0-pv.z*10.0);
  int zLevel = int(shadowZOfs+pkvLi.z*shadowZScale);
  zLevel = clamp(zLevel-1, 0, baseDimi2-1);
  int zLevelY = zLevel/baseDimi;
  int zLevelX = zLevel-zLevelY*baseDimi;
  ivec2 zLevel2 = ivec2(zLevelX, zLevelY)*baseDimi2;

  float transmitEnabled = shadowEnabled;

  float transmit = 1.0;
  if (transmitEnabled > 0.5) {
    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);

    transmit = mix(t12, t34, biy);

    transmit = clamp(transmit, 0.0, 1.0);
    r.rgb *= vec3(transmit);
  }

  if (lighterShadow > 0.5) {
    vec4 camLightPos = vec4(viewInvSecond2[3][0], viewInvSecond2[3][1], viewInvSecond2[3][2], viewInvSecond2[3][3]);

    float eyeCamDist = sqrt(dot((kk.xyz-camLightPos.xyz), (kk.xyz-camLightPos.xyz)));
    float lightCamDist = sqrt(dot((wpLight.xyz-camLightPos.xyz), (wpLight.xyz-camLightPos.xyz)));
    float shadowFactor = clamp((eyeCamDist-lightCamDist)*1.0-0.025, 0.0, 1.0);
    r.rgb *= ((1.0-shadowFactor)*(1.0-lighterShadowAmbient)+lighterShadowAmbient);
  }

  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 *= 2.0*(1.0-clamp(br*br, 0.0, 0.80));

  r.a = clamp(drawAlpha*clamp(br*2.0, 0.0, 1.0)*(pow(pc*1.0, drawAlphaSmooth)-drawAlphaZero), 0.0, 1.0);

  r.rgb = getAgePal(r.rgb);

  r.a = clamp(r.a, 0.0, 1.0);


  // pardex mask
  if (depthWrite > 0.5) {
    frag3 = vec4(0.0, 0.0, 0.0, 0.0);
  } else {
    frag3 = vec4(1.0, 1.0, 1.0, r.a);
  }

  if (r.a < 0.01) discard;

 // discard;

  // world space normal
  frag2 = vec4((viewInvMatrix*vec4(0.0, 0.0, 1.0, 0.0)).xyz, r.a);

  frag2.xyz = normalize(frag2.xyz);


  vec4 psNow = projectionMatrix*viewMatrix*vec4(pw, 1.0);
  psNow /= psNow.w;
  vec4 psPrev = projectionMatrix*prevViewMatrix*vec4(prevPw, 1.0);
  psPrev /= psPrev.w;

  vec2 vel2D = 25.0*motionVel*(psPrev-psNow).xy;
  frag4.r = 0.0;
  frag4.gb = vel2D;
  frag4.a = 1.0;




//  r.rgb = vec3(wpLight.xyz*0.01);
//  r.rgb = vec3(dot(wpLight.xyz, wpLight.xyz));
//  r.rgb = vec3(dot(pw.xyz, pw.xyz));
//  r.rgb = kk.xyz;

  frag = r;

 // frag.rgb = vec3(vel2D, 0.0);

}

