#version 430

layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D texNoise;
layout(binding=2) uniform sampler2D texEmitShape;
layout(binding=3) uniform sampler2D texEnv;

in vec4 posG;
in vec2 uvG;
in vec2 uvOrig;
in float sharpnessG;
in vec4 posSS;
in float age;

in int gl_PrimitiveID;


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

layout(binding=0, offset=0) uniform atomic_uint ac;

layout(binding=0, r32ui) uniform uimage2D headPointers;
layout(binding=1, r32ui) uniform uimage2D nextPointers;
layout(binding=2, rgba16f) uniform image2D pixelListColors;
layout(binding=3, rgba32f) uniform image2D pixelListDepthNorm;

uniform float g_time;
uniform float g_partSize = 0.15;

uniform float zNear = 0.1;
uniform float zFar = 1000.0;
// convert from 0.0 to 1.0 depth sample ds to linear depth
float linearDepth(float ds) {
    ds = 2.0*ds-1.0;
    float zLinear = 2.0*zNear*zFar/(zFar+zNear-ds*(zFar-zNear));
    return zLinear;
}
// result suitable for assigning to gl_FragDepth
float depthSample(float linearDepth) {
    float nonLinearDepth = (zFar+zNear-2.0*zNear*zFar/linearDepth)/(zFar-zNear);
    nonLinearDepth = (nonLinearDepth+1.0)/2.0;
    return nonLinearDepth;
}


#define PI 3.1415926

vec2 latlong(vec3 v) {
  v = normalize(v);
  float theta = acos(v.z); // +z is up
  float phi = atan(v.y, v.x) + PI;
  return vec2(phi, theta)*vec2(.1591549, .6366198);
}


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


uniform float g_partMapX = 0;
uniform float g_partMapY = 0;


uniform float near = 0.1;
uniform float far = 1000.0;

void main() {
    vec2 myUv = uvG;
    myUv.y *= -1.0;
    float sharpness = sharpnessG*0.25;
    myUv *= 1.0/8.0;
    myUv.x += g_partMapX*1.0/8.0;
    myUv.y += g_partMapY*1.0/8.0;

    vec4 result; // = texture2D(tex, myUv+vec2(0.0, 0.0));
    // vec4 nois = texture2D(texNoise, myUv+vec2(0.0, 0.0));
    // vec4 emitShape = texture2D(texEmitShape, uvOrig);

    vec2 uvm = (uvG-vec2(0.5,0.5))*2.0;
    float dist = (dot(uvm,uvm));

    vec2 uvNorm = uvm/sqrt(dist);

    float circle = clamp(1.0-dist*1.0, 0.0, 1.0);

    sharpness = 1.0;
    float powe = 1.0;

   // circle = clamp(smoothstep(0.0, 1.0, pow(circle*sharpness, powe))/clamp(sharpness, 0.0, 100.0), 0.0, 1.0);
    circle = clamp(pow(circle*sharpness, powe), 0.0, 1.0);

    vec3 normal;

    normal.x = uvm.x;
    normal.y = uvm.y;
    normal.z = sqrt(1.0-dot(normal.xy, normal.xy));
    normal.z *= normal.z;

    normal = normalize(normal);

    normal *= circle;

    //circle = 1.0;
    result.rgb = vec3(circle);
    result.a = clamp(result.r*0.50, 0.0, 1.0);
    result.rgb *= 1.0;
//    if (g_partSize < 26.0) {
//        result.r *= 1.0;
//    }

   // float zeto = 1.0/(posG.z+0.10);
    //if (zeto < 0.3) discard;
   // result.rgb += vec3(pow(zeto, 16.0));
  //   result.rgb *= 40.0;
  //  result.rgb *= (0.001+vec3(pow(zeto*1.50, 8.0)))*2.0;
   // result.a = 1.0;

    //vec2 scrTexPos = posSS.xy/posSS.w*0.5+vec2(0.5, 0.5);
    // result.rg = scrTexPos;
    //result.rgb = posSS.xyz;

    //result.rg = gl_FragCoord.xy*vec2(1.0/1280.0, 1.0/720.0)*1.0;

    //result.b = 0.0;
    // result.b = posSS.z;
    // result.rgb = vec3(posSS.z/posSS.w);

//    result.rgb = vec3(result.a);
//    if (result.a < 0.01) {
//        discard;
//    }
//    result.a = 1.0;


    frag = result;

  //  if (frag.a < 0.01) {
  //      discard;
  //      return;
  //  }

    float depthi = (posG.z/posG.w);

    float ld = linearDepth(depthi);

    frag2.r = ld+result.a*5.0;
    frag2.gb = vec2(0.0);
    frag2.g = ld;
    frag2.b = 4.0+frag.a*3.0;
    frag2.a = 1.0;

   // normal *= pow(3.0-0.50*ld, 4.0);
   // float b = -gl_FragCoord.z * 0.9 + 1.0;
    float b = -posG.z/posG.w*1.0 + 1.0;

    /* If your scene has a lot of content very close to the far plane,
       then include this line (one rsqrt instruction):
       b /= sqrt(1e4 * abs(csZ)); */
    float w = clamp(1.0 * 1e8 * b * b * b, 1e-4, 3e2);

    float zeto = 1.0/(posG.z/posG.w*0.9-0.01);
    w = pow(zeto*1.50, 10.0)+0.0;

//    float zeto = 1.0/(posG.z-0.0);
//    w = pow(zeto*3.0, 5.0)+1.0;

//    float zeto = 1.0/(posG.z-0.60);
//    w = pow(zeto*3.0, 5.0)+0.0;


    // w = 10.0*(0.01+pow(1.0-0.95*depthi, 2));

    frag.rgb = normal.xyz*w*1.0; // *(10.0-2.0*ld);
   // frag.rgb = normal.xyz; // *(pow(depthi, 0.20));



   // float dd = (((far-near) * depthi) + near + far) / 2.0;
    depthi = linearDepth(depthi)-result.r*0.50;
    if (depthi < zNear) depthi = zNear;
    depthi = depthSample(depthi);
    float dd = (depthi+1.0)*0.5;

  //  gl_FragDepth = dd;

   // frag.rgb = frag2.rgb;
    if (result.a < 0.35) {
        discard;
    }

//    uint counter = atomicCounterIncrement(ac)+1;
//    uint cy = counter/(1280*4);
//    uint cx = counter-uint(cy*1280*4);
//    ivec2 listCoord = ivec2(cx,cy);
//    uint prevCounter = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), counter);
//    imageStore(nextPointers, listCoord, uvec4(prevCounter));
//    imageStore(pixelListColors, listCoord, frag);
//    imageStore(pixelListDepthNorm, listCoord, frag2);

//    discard;

//    uint counter = atomicCounterIncrement(ac);
//    frag.rgb = vec3(fract(float(counter)/(1280.0*720.0)));


//    if (result.a < 0.25) {
//        discard;
//    }

    int primID = gl_PrimitiveID;

    vec3 color;

    if ((primID&3)==0) {
        color.rgb = vec3(1.0);
    } else if ((primID&3)==1) {
        color.rgb = vec3(0.0, 0.0, 1.15);
    } else if ((primID&3)==2) {
        color.rgb = vec3(0.90, 0.0, 0.0);
    } else {
        color.rgb = vec3(0.2);
    }

    color.rgb = vec3(0.4+0.70*cos(age*0.5), 0.40*cos(age*0.62), 0.0+0.2*cos(age*0.52+sin(age*0.52)))+vec3(0.0);
    frag2 = vec4(color*0.45*result.a*w, result.a);

    frag.a = 0.0;
    frag2.a = 0.0;
}

