#version 430

in vec2 uv;

layout(location = 0) out vec4 frag;

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


// TODO #include "noise.h"


uniform float noiseOct = 4.0;
uniform float noiseOctMul = 3.0;
uniform float noiseOctAmp = 0.75;
uniform float noiseSplineEnabled = 1.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<int(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 r=0.0;
        float s=0.5;
        for (int i=0;i<int(noiseOct);i++) {
                r+=s*(perlin4(c));
                c*=noiseOctMul;
                s*=noiseOctAmp;
        }
        return r;
}

// end of "noise.h"


uniform float noisePos = 0.0;
uniform float noiseOfsX = 0.0;
uniform float noiseOfsY = 0.0;
uniform float noiseFreq = 1.0;

uniform float dispImgAmp = 0.0;
layout(binding=0) uniform sampler2D texHeight;

uniform float dispAmp = 1.0;
uniform float dispSub = 0.0;
uniform float dispExp = 1.0;
uniform float dispMinLim = 0.0;
uniform float dispMaxLim = 999.0;
uniform float dispSmooth = 0.0;

layout(binding=1, rgba32f) uniform image2D mesherVertPos;
layout(binding=2, rgba32f) uniform image2D mesherVertNorm;


float deg2pi = 2.0*3.141592/360.0;

uniform float div = 1.0;

void main() {
    ivec2 uvs = ivec2(gl_FragCoord.xy);

    vec4 screen = vec4(0.0);

    ivec2 triBufSize = imageSize(mesherVertPos);

//    imageStore(mesherVertPos, uvs, vec4(0.0));


    int divi = int(div);

    if (divi == 0) return;

    int pid = uvs.x+uvs.y*triBufSize.x;

    if (pid > (divi+1)*(divi+1)) { discard; return; }

    int vid = pid;
    vec3 tvp = vec3(0.0f);
    int vpr = (divi+1);
    int vr = vid/vpr;
    int vx = vid-vr*vpr;
    float vprf = float(divi);
    tvp.xy = vec2(float(vx)*2.0/vprf-1.0, float(vr)*2.0/vprf-1.0);

    float no = 0.0;


    vec4 vp = imageLoad(mesherVertPos, uvs);
  //  vec4 vp = vec4(0.0);
    vec4 vn = imageLoad(mesherVertNorm, uvs);

    vn.xyz = normalize(vn.xyz);

//    vn.z = -vn.z;


   //  tvp.xyz = vp.xyz;
    // noise
    no = turb4(vec4(tvp.xyz*noiseFreq+vec3(noiseOfsX, noiseOfsY, 0.0), noisePos));
    no = abs(no);

    tvp.xyz = vp.xyz;

    vec3 tvpm = tvp;
    vec2 dotPos = vec2(floor(tvpm.x)+0.5, floor(tvpm.y)+0.5);


    // spikes
//    float frk = noiseFreq;
//    tvpm.xy *= frk;
//    vec3 dd = (vec3(tvpm.xy, 0.0)-vec3(dotPos, 0.0))*2.0;
//    no = length(dd)*1.0;

    // balles
//    float frk = noiseFreq;
//    tvpm.xy *= frk;
//    vec3 dd = (vec3(tvpm.xy, 0.0)-vec3(dotPos, 0.0))*2.0;
//    float def = dot(dd, dd);
//    if (def<1.0) {
//        no = sqrt(1.0-def);
//    } else {
//        no = 0.0;
//    }
//    no = 1.0-no;

    // modulos
//    no = 1.0-no;
//    float notu = turb4(vec4((dotPos.xy+tvp.xy*0.5)*noiseFreq+vec2(noiseOfsX, noiseOfsY), 0.0, noisePos));
//    no *= notu;
//    no = 1.0-no;

//    no = abs(no);


    no *= dispAmp;


    if (abs(dispImgAmp) > 0.0001) {
      float noImg = 0.0;
      vec3 imgVal = texture2D(texHeight, tvp.xy*noiseFreq+vec2(noiseOfsX, noiseOfsY)).rgb;
      noImg = dot(vec3(0.333), imgVal);

      no += noImg*dispImgAmp;

//      noImg = (sign(noImg)*pow(abs(noImg), dispExp)-dispSub);

//      if (dispSmooth < 0.5) {
//          noImg = clamp(noImg, dispMinLim, dispMaxLim);
//      } else {
//          noImg = -smoothstep(dispMinLim, dispMaxLim, -noImg)*(dispMaxLim-dispMinLim)-dispMinLim;
//      }

    //  tvp.xyz += noImg*dispImgAmp*vn.xyz;


    }


    no = (sign(no)*pow(abs(no), dispExp)-dispSub);

    if (dispSmooth < 0.5) {
        no = clamp(no, dispMinLim, dispMaxLim);
    } else {
        no = -smoothstep(dispMinLim, dispMaxLim, -no)*(dispMaxLim-dispMinLim)-dispMinLim;
    }

    no *= 1.0;

//    tvp.z = no*dispAmp;
    tvp.xyz += no*vn.xyz;



//    tvp.xyz = vec3(0.0);
    imageStore(mesherVertPos, uvs, vec4(tvp, 0.0));

    discard;

    screen.a = 1.0;
    frag = screen;


}
