#version 430

layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D texWave;
layout(binding=2) uniform sampler2D texEnv;
layout(binding=3) uniform sampler2D texSpaceDirX;
layout(binding=4) uniform sampler2D texSpaceDirY;
layout(binding=5) uniform sampler2D texDepth;
layout(binding=6) uniform sampler2D texSpaceNormal;
layout(binding=7) uniform sampler2D texPrevBlurFrame;
layout(binding=8) uniform sampler2D texPrevNorm;
layout(binding=9) uniform sampler2D texBg;


layout(binding=0, rgba32f) uniform image2D triangleInfo;
layout(binding=1, rgba32f) uniform image2D triangleIds;
layout(binding=2, r32i) uniform iimage2D edgeGridHeadPointers;
layout(binding=3, rgba32f) uniform image2D edgeDataCenter;
layout(binding=4, rgba32f) uniform image2D edgeDataIds;
layout(binding=5, rgba32f) uniform image2D texSpace;
layout(binding=6, r32f) uniform image2D texWaveFeed;
//layout(binding=7, rgba32f) uniform image2D texSpaceDirY;

in vec4 posG;
in vec4 posOrigG;
in vec3 normalG;
in vec3 normalWSG;
in vec2 uvG;
in vec2 uvnG;
in vec3 tangentG;
in vec3 colorG;
in vec4 posW;
in float brightG;
in float triangleIdG;

layout(location = 0) out vec4 frag;
layout(location = 1) out vec4 frag2;
layout(location = 2) out vec4 frag3; // emit buf amounts


uniform float g_quadsPerRow = 128;
uniform float g_texW;
uniform float g_texH;

uniform float g_triangleTexDim;

uniform float g_bright;

#define PI 3.1415926

uniform float g_time;

uniform float g_uvOfsX = 0.0;
uniform float g_uvScale = 1.0;
uniform float g_uvScaleY = 1.0;
uniform float g_uvOfsY = 0.0;

uniform float g_texBrightness = 1.0;
uniform float g_texAmbient = 0.0;
uniform float g_prevAmount = 0.0;
uniform float g_prevBlurAmount = 0.0;
uniform float g_bump = 0.0;

uniform vec4 g_color = vec4(1.0);


uniform mat4 modelViewMatrix;
uniform mat4 modelViewInvMatrix;
uniform mat4 viewInvMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 projectionInvMatrix;

uniform float g_windowWidth = 1280.0;
uniform float g_windowHeight = 720.0;

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

vec3 rotateXY3(vec3 p, float a) {
  return rotateXY(vec4(p, 0.0), a).xyz;
}
vec2 rotateXY2(vec2 p, float a) {
  return rotateXY(vec4(p, 0.0, 0.0), a).xy;
}

// google glsl rand gave this, thanks and credit flies to
// http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

const float zFar = 1.0;
const float zNear = 0.0;

float getPointDist(float z) {
    float clipA = zFar / (zFar - zNear);
    float clipB = zFar*zNear / (zNear - zFar);
    return clipB/(z-clipA);
}
float getPointZ(float d) {
    float clipA = zFar / (zFar - zNear);
    float clipB = zFar*zNear / (zNear - zFar);
    return (clipB + d*clipA)/d;
}

vec4 CalcEyeFromWindow(in vec3 windowSpace) {
    vec3 ndcPos;
    vec4 viewport = vec4(0.0, 0.0, g_windowWidth, g_windowHeight);
    ndcPos.xy = ((2.0 * windowSpace.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
//    ndcPos.z = (2.0 * windowSpace.z - zNear - zFar) / (zFar - zNear);
    ndcPos.z = (2.0 * windowSpace.z - zNear - zFar) / (zFar - zNear);
    vec4 clipPos;
    clipPos.w = projectionMatrix[3][2]/(ndcPos.z-(projectionMatrix[2][2]/projectionMatrix[2][3]));
    clipPos.xyz = ndcPos * clipPos.w;
    return projectionInvMatrix * clipPos;
}

vec2 getBump(vec2 uv) {
    vec2 d = vec2(0.01, 0.0);
    return vec2(texture2D(tex, uv+d.xy).g-texture2D(tex, uv-d.xy).g,
                texture2D(tex, uv+d.yx).g-texture2D(tex, uv-d.yx).g);
}


float atanSafe(float y, float x) {
    float ret=0.0;
    if (x!=0.0) {
        if (x>0.0) {
            ret=atan(y/x);
        } else	{
            ret=atan(y/x)+3.141592;
        }
    } else {
        if (y>=0.0) {
            ret=0.5*3.141592;
        } else {
            ret=-0.5*3.141592;
        }
    }
    return ret;
}

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

float turb(vec3 c) {
        float r=0.0;
        float s=0.5;
        c*=1.0;
        for (int i=0;i<8;i++) {
                //if (i<2) continue;
                r+=s*(perlin(c)*1.0+0.0);
                c*=3.0;
                s*=0.55;
        }
        return r;
}

vec3 texStripes(vec3 p) {
    float sw = 0.20;
    float sf = 40.0;
    float res = clamp((sin(p.z*sf+p.x*sf)-1.0+sw)/sw, -1.0, 1.0)+clamp((sin((p.z*sf+p.x*sf)*0.1)-1.0+sw)/sw, 0.0, 1.0);
    return -vec3(res*1.25, res*1.1, res*1.05)+vec3(2.0);
}

vec3 texStripesRad(vec3 p) {
    float sw = 2.0;
    float sf = 32.0;
    float pk = sqrt(dot(p.xy, p.xy))+atanSafe(p.y, p.x)/sf;
    float res = clamp((sin(pk*sf)-1.0+sw)/sw, -1.0, 1.0);
    return (vec3(res*1.25, res*1.1, res*1.05)*1.0+vec3(0.20));
}


vec4 getCol(float freq, vec2 ofs) {
    vec4 d;
    vec4 diffuse;
    float kalkutta, kalkuttas, kf;
    float pi = 3.141592;
    vec2 uv;


    float overlaps = g_uvScale;
    float dots = dot(vec3(0.0, 1.0, 0.0),normalize(posW.xyz));
    float dotter = (0.50+0.45*dots)*g_uvScaleY+g_uvOfsY*freq;
    kalkutta = (atanSafe(posW.x, posW.z)+0.5*pi)/(2.0*pi)*overlaps*2.0;
    overlaps = fract((overlaps-0.01)*2.0)*0.5;
    kf = fract(kalkutta);
    uv = vec2(kalkutta, dotter)*1.0;
    d = texture2D(tex, uv*freq+ofs);
    d *= d;
    diffuse = d*(smoothstep(0.0, overlaps, kf))*(1.0-smoothstep(overlaps, overlaps*2.0, kf));

    overlaps = g_uvScale*1.5;
    kalkutta = ((atanSafe(posW.z, posW.x)+0.50*pi)/(2.0*pi)+0.0)*overlaps*2.0;
    overlaps = fract((overlaps-0.01)*2.0)*0.5;
    kf = fract(kalkutta);
    uv = vec2(kalkutta, dotter)*1.0;
    d = texture2D(tex, uv*freq+ofs);
    d *= d;
    diffuse += d*(smoothstep(0.0, overlaps, kf))*(1.0-smoothstep(overlaps, overlaps*2.0, kf));

    return diffuse*brightG;
}

vec3 tonemapUC2(vec3 x) {
    x = clamp(x, 0.0, 10000.0);
    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;
}

vec4 getTex(sampler2D t, vec2 c) {
//    vec2 cs = vec2(c.x*(g_texW), c.y*(g_texH));
//    vec2 csi = floor(cs)+0.5*vec2(1.0, 1.0);

//    cs = rotateXY2(cs-csi, -0.0)+csi;

//    vec4 res = texelFetch(t, ivec2(cs), 0);
//    return res;
    vec2 ct = vec2(c.x*g_texW, c.y*g_texH);
//    vec2 ctf = fract(ct);
    return texelFetch(t, ivec2(ct), 0);
}


int getOtherTriangleId(uint thisTriangleId, uint thisTriangleEdge) {
    uint tid = thisTriangleId*3;
    uint tidy = tid/(3*int(g_triangleTexDim));
    ivec2 tidUV = ivec2(tid-uint(tidy*3*int(g_triangleTexDim))+thisTriangleEdge, tidy);
    vec4 tidi = imageLoad(triangleIds, tidUV);
    return int(round(tidi.x));
}

vec3 getTriangleVertex(uint tid, uint edge) {
    uint tid3 = tid*3;
    uint tidy = tid3/(3*int(g_triangleTexDim));
    ivec2 tidUV = ivec2(tid3-uint(tidy*3*int(g_triangleTexDim))+edge, tidy);
    vec4 tidi = imageLoad(triangleInfo, tidUV);
    return tidi.xyz;
}

vec2 getTriangleVertexUV(uint tid, uint edge) {
    uint quadIndex = tid;
    uint quadHalf = 1;

    float quadSize = g_texW/g_quadsPerRow;
    float pid = float(quadIndex);
    float pidf = pid/g_quadsPerRow;
    float quadX = fract(pidf);
    float quadY = floor(pidf);

    // to target texture coordinates 0.0 - 1.0x
    float quadSW = quadSize/g_texW;
    float quadSH = quadSize/g_texH;
    quadY *= quadSH;

    vec2 result = vec2(0.0);

    if (quadHalf==0) {
        if (edge==0) {
            result = vec2(quadX, quadY);
        } else if (edge==1) {
            result = vec2(quadX+quadSW, quadY);
        } else if (edge==2) {
            result = vec2(quadX, quadY+quadSH);
        }
      //    uvG = vec2(0.0);
    } else {
        if (edge==0) {
            result = vec2(quadX+quadSW, quadY+quadSH);
        } else if (edge==1) {
            result = vec2(quadX, quadY+quadSH);
        } else if (edge==2) {
            result = vec2(quadX+quadSW, quadY);
        }
    }

    return result;
}

float distToLine(vec3 p, vec3 v0, vec3 v1) {
//    vec3 pv0 = p-v0;
//    vec3 line = (v1-v0);
//    vec3 proj = dot(pv0, line)*line/sqrt(dot(line,line));

//    vec3 res = pv0-proj;
//    return sqrt(dot(res,res));

    vec3 d = v1-v0;
    float lambda = (dot(p, d)-dot(v0, d))/dot(d, d);
    vec3 k = p-(v0+lambda*d);
    return sqrt(dot(k,k));
}

int getClosestEdge(int otid, vec3 pos) {
//    if (edgeG.x <= 0.1) {
//       return 2;
//    } else if (edgeG.y <= 0.1) {
//       return 0;
//    } else if (abs(edgeG.x-edgeG.y) <= 0.1) {
//      return 1;
//    }


//    if (edgeIntG.x <= edgeIntG.y && edgeIntG.x <= edgeIntG.z) {
//        return 1;
//    }
//    if (edgeIntG.y <= edgeIntG.z && edgeIntG.y <= edgeIntG.z) {
//        return 0;
//    }
//    if (edgeIntG.z < edgeIntG.x && edgeIntG.z < edgeIntG.y) {
//        return 2;
//    }

//    if (edgeIntG.y <= edgeEps) {
//       return 0;
//    } else if (edgeIntG.z <= edgeEps) {
//       return 1;
//    } else if (edgeIntG.x <= edgeEps) {
//      return 2;
//    }

//    return -1;

    if (otid < 0) {
        return -1;
    }

    int closestEdge = -1;
    float closestEdgeDist = 100000.0;
    float d;

    vec3 otv0 = vec3(0.0);
    vec3 otv1 = vec3(0.0);
    vec3 otv2 = vec3(0.0);

    float eps = 1.5;
    // eps = 0.002;

    otv0 = getTriangleVertex(otid, 0);
    otv1 = getTriangleVertex(otid, 1);
    otv2 = getTriangleVertex(otid, 2);

    d = distToLine(pos, otv0, otv1);
    if (d<closestEdgeDist && d<eps) {
            closestEdgeDist = d;
            closestEdge = 0;
    }

    d = distToLine(pos, otv1, otv2);
    if (d<closestEdgeDist && d<eps) {
            closestEdgeDist = d;
            closestEdge = 1;
    }

    d = distToLine(pos, otv2, otv0);
    if (d<closestEdgeDist && d<eps) {
            closestEdgeDist = d;
            closestEdge = 2;
    }

    return closestEdge;
}

vec3 getEdgeCen(int otid, int edge) {
    vec3 otv0 = getTriangleVertex(otid, 0);
    vec3 otv1 = getTriangleVertex(otid, 1);
    vec3 otv2 = getTriangleVertex(otid, 2);

    if (edge==0) {
        return (otv0+otv1)*0.5;
    }
    if (edge==1) {
        return (otv1+otv2)*0.5;
    }
    if (edge==2) {
        return (otv2+otv0)*0.5;
    }
}

vec2 getTexCoord(vec2 c) {
    vec2 ct = vec2(c.x*g_texW, c.y*g_texH);
    return ct;
}

float getRot(int oted, int closestEdge) {
    float rot = 1.0*3.141592;

    if (oted == 0 && closestEdge == 0) {
        rot = -3.141592;
    }
    if (oted == 0 && closestEdge == 1) {
        rot = -0.25*3.141592;
    }
    if (oted == 0 && closestEdge == 2) {
        rot = 0.5*3.141592;
    }

    if (oted == 1 && closestEdge == 0) {
        rot = 0.25*3.141592;
    }
    if (oted == 1 && closestEdge == 1) {
        rot = -3.141592;
    }
    if (oted == 1 && closestEdge == 2) {
        rot = -0.25*3.141592;
    }

    if (oted == 2 && closestEdge == 0) {
        rot = -0.5*3.141592;
    }
    if (oted == 2 && closestEdge == 1) {
        rot = 0.50*3.141592;
    }
    if (oted == 2 && closestEdge == 2) {
        rot = 3.141592;
    }

    return rot;
}

// projection factor of a on b (projection = factor*b)
float getProjFactor(vec3 a, vec3 b) {
    float res;
   // a = a/sqrt(dot(a,a));

  //  res = dot(a,b)/dot(b,b);
    res = dot(a,b)/dot(b,b);

    return res;
}

float getEdgeInterpolant(int tid, int edge, vec3 pos) {

    vec3 v0 = getTriangleVertex(tid, 0);
    vec3 v1 = getTriangleVertex(tid, 1);
    vec3 v2 = getTriangleVertex(tid, 2);

    vec3 e0 = v1-v0;
    vec3 e1 = v2-v1;
    vec3 e2 = v0-v2;

    if (edge==0) {
        return getProjFactor(pos-v0, e0);
    }
    if (edge==1) {
        return getProjFactor(pos-v1, e1);
    }
    if (edge==2) {
        return fract(getProjFactor(pos-v2, e2)*10.0);
    }

    return 0.0;
}

vec2 guv = vec2(0.0);


vec2 getOtuv(int tid, int otid, int oted, int closestEdge, int flip, vec3 pos) {
    float edgeInt = 0.0;
//    float edgeInt2 = 0.0;
//    if (oted == 0) {
//        edgeInt2 = 1.0-edgeIntG.x;
//    } else if (oted == 1) {
//        edgeInt2 = 1.0-edgeIntG.y;
//    } else if (oted == 2) {
//        edgeInt2 = 1.0-edgeIntG.z;
//    }
    edgeInt = 1.0-getEdgeInterpolant(tid, oted, pos);
  //  edgeInt = (edgeInt+edgeInt2)*0.5;
    if (flip == 1) {
        edgeInt = 1.0-edgeInt;
    }
    vec2 uv0 = getTriangleVertexUV(tid, 0);
    vec2 uv1 = getTriangleVertexUV(tid, 1);
    vec2 uv2 = getTriangleVertexUV(tid, 2);

    if (oted == 2) {
       edgeInt = fract((guv.y-uv0.y)/(uv2.y-uv0.y)*1.0);
    }
//    if (oted == 1) {
//       edgeInt = 1.0-fract((guv.x-uv0.x)/(uv1.x-uv0.x)*1.0);
//    }
    if (oted == 0) {
       edgeInt = 1.0-fract((guv.x-uv0.x)/(uv1.x-uv0.x)*1.0);
    }

    vec2 otuv0 = getTriangleVertexUV(otid, 0);
    vec2 otuv1 = getTriangleVertexUV(otid, 1);
    vec2 otuv2 = getTriangleVertexUV(otid, 2);

    vec2 otuv = vec2(0.0);
    if (closestEdge==0) {
        otuv = otuv0*(1.0-edgeInt)+otuv1*(edgeInt);
    } else if (closestEdge==1) {
        otuv = otuv1*(1.0-edgeInt)+otuv2*(edgeInt);
    } else if (closestEdge==2) {
        otuv = otuv2*(1.0-edgeInt)+otuv0*(edgeInt);
    }


    if (oted == 2) {
        if (closestEdge==2) {
     //       return rotateXY2(guv-uv0+vec2(0.5, 0.5), 0.0)+otuv0;
     //       return vec2(0.0, 0.0);
        }
    }

    return vec2(otuv);
}

int getClosestVertex(int tid, vec3 pos) {
    float d, d2;
    vec3 dd;
    int closest = 0;

    vec3 v0 = getTriangleVertex(tid, 0);
    vec3 v1 = getTriangleVertex(tid, 1);
    vec3 v2 = getTriangleVertex(tid, 2);

    dd = v0-pos;
    d = dot(dd, dd);
    dd = v1-pos;
    d2 = dot(dd,dd);
    if (d2<d) {
        d = d2;
        closest = 1;
    }
    dd = v2-pos;
    d2 = dot(dd,dd);
    if (d2<d) {
        d = d2;
        closest = 2;
    }
    return closest;
}


vec4 getTexBi(sampler2D t, vec2 cp) {
    guv = cp;
    vec2 ct = vec2(cp.x*g_texW-0.5, cp.y*g_texH-0.5);
    vec2 cb = vec2(cp.x*g_texW-0.0, cp.y*g_texH-0.0);
  //  ct = cb;
  //  ct = cb;
    vec2 ctf = fract(ct+0.0*vec2(0.50));

    vec4 base = texelFetch(t, ivec2(cb), 0);

    vec4 a = texelFetch(t, ivec2(ct)+ivec2(0, 0), 0);
    a.a = texelFetch(tex, ivec2(ct)+ivec2(0, 0), 0).a;
    vec4 b = texelFetch(t, ivec2(ct)+ivec2(1, 0), 0);
    b.a = texelFetch(tex, ivec2(ct)+ivec2(1, 0), 0).a;
    vec4 c = texelFetch(t, ivec2(ct)+ivec2(0, 1), 0);
    c.a = texelFetch(tex, ivec2(ct)+ivec2(0, 1), 0).a;
    vec4 d = texelFetch(t, ivec2(ct)+ivec2(1, 1), 0);
    d.a = texelFetch(tex, ivec2(ct)+ivec2(1, 1), 0).a;

    float triangleId = round(triangleIdG);
    int thisTid = int(triangleId)-1;

    int oted;
    int closestEdge = -1;
    vec2 otuv = vec2(0.0);
    int otid;
    float rot;
    vec2 rh;


    oted = getClosestEdge(thisTid, posOrigG.xyz);
    otid = getOtherTriangleId(thisTid, oted);
    int otido = otid;
    if (oted < 0) {
        otid = -1;
    }

//    if (!(thisTid == 4015 || otid == 4015)) {
//       return vec4(0.0, 0.0, 0.0, 0.0);
//    }

    closestEdge = getClosestEdge(otid, posOrigG.xyz);

    if (otid >= 0) {
        if (otid == thisTid) {
            return vec4(0.0, 0.0, 1.0, 0.0);
        }
        otuv = getOtuv(thisTid, otid, oted, closestEdge, 0, posOrigG.xyz);


      //  return vec4(edgeIntG, 0.0);
      //  return vec4(closestEdge*0.3+0.3);
      //  return vec4(oted*0.3+0.3);
       //return vec4(closestEdgeDist);
    //    return vec4(otuv, 0.0, 0.0);
    }

  //  vec3 v0 = getTriangleVertex(thisTid, 0);
  //  return vec4(posOrigG.xyz-v0, 0.0);

    rot = getRot(oted, closestEdge);
    rh = rotateXY2(vec2(-0.50, -0.50), rot);

    int otid2;
    int oted2;

    if (abs(a.a-triangleId) > 0.5) {
 //       return vec4(0.0, 0.0, 0.0, 0.0);
    }


    int closestVertex;
    int ttt;

    vec2 otuv22;
    float rot2;


    // vec4 kob = imageLoad(texSpaceDirX, ivec2(cb));

//  base = vec4(kob.x); // texelFetch(t, ivec2(kob.xy), 0);
//    base = texelFetch(t, ivec2(kob.xy), 0);

//    return base;


    if (abs(a.a-triangleId) > 0.5) {
        a = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, -0.50),rot)), 0);
        a.a = texelFetch(tex, ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, -0.50),rot)), 0).a;
        if (abs(a.a-otid-1) > 0.5) {
// return vec4(1.0, 0.0, 0.0, 0.0);
            oted2 = 1;
            if (oted2 == 3) oted2 = 0;
            if (oted2 < 0) oted2 = 2;
            otid2 = getOtherTriangleId(thisTid, oted2);
            closestEdge = getClosestEdge(otid2, posOrigG.xyz); // getEdgeCen(thisTid, oted2));
            otuv22 = getOtuv(thisTid, otid2, oted2, closestEdge, 0, posOrigG.xyz);
            rot2 = getRot(oted2, closestEdge);
            a = texelFetch(t, ivec2(getTexCoord(otuv22)+rotateXY2(vec2(-0.50, -0.50),rot2)), 0);
            a.a = texelFetch(tex, ivec2(getTexCoord(otuv22)+rotateXY2(vec2(-0.50, -0.50),rot2)), 0).a;
            if (abs(a.a-otid2-1) > 0.5) {
                oted2 = getClosestVertex(otid2, posOrigG.xyz)-1;
                if (oted2 == 3) oted2 = 0;
                if (oted2 < 0) oted2 = 2;
                int tidedi = otid2;
                otid2 = getOtherTriangleId(otid2, oted2);
                closestVertex = getClosestVertex(otid2, posOrigG.xyz);
                otuv22 = getTriangleVertexUV(otid2, closestVertex);

                ttt = otid2;

                vec2 otuv0 = getTriangleVertexUV(ttt, 0);
                vec2 otuv1 = getTriangleVertexUV(ttt, 1);
                vec2 otuv2 = getTriangleVertexUV(ttt, 2);
                vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                otuv22 = (otuv22-otuvc)*0.99+otuvc;

                a = texelFetch(t, ivec2(getTexCoord(otuv22)-vec2(0.50, 0.50)*0.0+0.0*rotateXY2(vec2(-0.50, -0.50),rot2))+0*ivec2(-1, -1), 0);
                a.a = texelFetch(tex, ivec2(getTexCoord(otuv22)-vec2(0.50, 0.50)*0.0+0.0*rotateXY2(vec2(-0.50, -0.50),rot2))+0*ivec2(-1, -1), 0).a;
                if (abs(a.a-otid2-1) > 0.5) {
                  return vec4(1.0, 0.0, 0.0, 0.0);
               }
            }
        }
    }

    if (abs(b.a-triangleId) > 0.5) {
      //  return vec4(1.0, 0.0, 0.0, 0.0);
        b = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, -0.50),rot)), 0);
        b.a = texelFetch(tex, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, -0.50),rot)), 0).a;
        if (abs(b.a-otid-1) > 0.5) {
      //      return vec4(1.0, 0.0, 0.0, 0.0);
//            oted2 = 2;
//            if (ctf.x < 0.5)
//                oted2 = 1; // getClosestVertex(thisTid, posOrigG.xyz)-1;
//            if (ctf.y < 0.5)
//                oted2 = 2;

//            // oted2 = getClosestEdge(thisTid, posOrigG.xyz);
//            if (oted2 == 3) oted2 = 0;
//            if (oted2 < 0) oted2 = 2;
//            otid2 = getOtherTriangleId(thisTid, oted2);
//            closestEdge = getClosestEdge(otid2, posOrigG.xyz); // getEdgeCen(thisTid, oted2));
//            otuv22 = getOtuv(thisTid, otid2, oted2, closestEdge, 0, posOrigG.xyz);
//            rot2 = getRot(oted2, closestEdge);
//            b = texelFetch(t, ivec2(getTexCoord(otuv22)+rotateXY2(vec2(0.50, -0.50),rot2)), 0);


            otid2 = thisTid;
            oted2 = getClosestVertex(otid2, posOrigG.xyz);
         //   oted2 = 2;
            if (oted2 == 3) oted2 = 0;
            if (oted2 < 0) oted2 = 2;
            int tidedi = otid2;
            otid2 = getOtherTriangleId(otid2, oted2);
            closestVertex = getClosestVertex(otid2, posOrigG.xyz);
            if (closestVertex < 0) closestVertex = 2;
            closestEdge = getClosestEdge(otid2, posOrigG.xyz);

         //   closestVertex = 1;
            otuv22 = getTriangleVertexUV(otid2, closestVertex);

            rot2 = getRot(oted2, closestEdge);
            ttt = otid2;

            vec2 otuv0 = getTriangleVertexUV(ttt, 0);
            vec2 otuv1 = getTriangleVertexUV(ttt, 1);
            vec2 otuv2 = getTriangleVertexUV(ttt, 2);
            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
            otuv22 = (otuv22-otuvc)*0.999+otuvc;

            b = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
            b.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;

            if (abs(b.a-otid2-1) > 0.5) {
            //    return vec4(1.0, 0.0, 0.0, 0.0);
                oted2 = getClosestVertex(otid2, posOrigG.xyz)-1;
                if (oted2 == 3) oted2 = 0;
                if (oted2 < 0) oted2 = 2;
                int tidedi = otid2;
                otid2 = getOtherTriangleId(otid2, oted2);
                closestVertex = getClosestVertex(otid2, posOrigG.xyz);
                closestEdge = getClosestEdge(otid2, posOrigG.xyz);
                otuv22 = getTriangleVertexUV(otid2, closestVertex);

                rot2 = getRot(oted2, closestEdge);
                ttt = otid2;

                vec2 otuv0 = getTriangleVertexUV(ttt, 0);
                vec2 otuv1 = getTriangleVertexUV(ttt, 1);
                vec2 otuv2 = getTriangleVertexUV(ttt, 2);
                vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                otuv22 = (otuv22-otuvc)*0.999+otuvc;

                b = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
                b.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;
                if (abs(b.a-otid2-1) > 0.5) {
                  return vec4(1.0, 0.0, 0.0, 0.0);
               }
            }
        }
    }


    if (abs(c.a-triangleId) > 0.5) {
       c = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, 0.50),rot)), 0);
       c.a = texelFetch(tex, ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, 0.50),rot)), 0).a;
        if (abs(c.a-otid-1) > 0.5) {
// return vec4(1.0, 0.0, 0.0, 0.0);
//            if (ctf.x > 0.5)
//                oted2 = 0; // getClosestVertex(thisTid, posOrigG.xyz)-1;
//            if (ctf.y > 0.5)
//                oted2 = 1;
//            if (oted2 == 3) oted2 = 0;
//            if (oted2 < 0) oted2 = 2;
//            otid2 = getOtherTriangleId(thisTid, oted2);
//            closestEdge = getClosestEdge(otid2, posOrigG.xyz); // getEdgeCen(thisTid, oted2));
//            otuv22 = getOtuv(thisTid, otid2, oted2, closestEdge, 0, posOrigG.xyz);
//            rot2 = getRot(oted2, closestEdge);
//            c = texelFetch(t, ivec2(getTexCoord(otuv22)+rotateXY2(vec2(-0.50, 0.50),rot2)), 0);

            otid2 = thisTid;
            oted2 = getClosestVertex(otid2, posOrigG.xyz);
         //   oted2 = 2;
            if (oted2 == 3) oted2 = 0;
            if (oted2 < 0) oted2 = 2;
            int tidedi = otid2;
            otid2 = getOtherTriangleId(otid2, oted2);
            closestVertex = getClosestVertex(otid2, posOrigG.xyz);
            if (closestVertex < 0) closestVertex = 2;
            closestEdge = getClosestEdge(otid2, posOrigG.xyz);

         //   closestVertex = 1;
            otuv22 = getTriangleVertexUV(otid2, closestVertex);

            rot2 = getRot(oted2, closestEdge);
            ttt = otid2;

            vec2 otuv0 = getTriangleVertexUV(ttt, 0);
            vec2 otuv1 = getTriangleVertexUV(ttt, 1);
            vec2 otuv2 = getTriangleVertexUV(ttt, 2);
            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
            otuv22 = (otuv22-otuvc)*0.999+otuvc;

            c = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
            c.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;
            if (abs(c.a-otid2-1) > 0.5) {
                oted2 = getClosestVertex(otid2, posOrigG.xyz)-1;
                if (oted2 == 3) oted2 = 0;
                if (oted2 < 0) oted2 = 2;
                int tidedi = otid2;
                otid2 = getOtherTriangleId(otid2, oted2);
                closestVertex = getClosestVertex(otid2, posOrigG.xyz);
                otuv22 = getTriangleVertexUV(otid2, closestVertex);

                ttt = otid2;

                vec2 otuv0 = getTriangleVertexUV(ttt, 0);
                vec2 otuv1 = getTriangleVertexUV(ttt, 1);
                vec2 otuv2 = getTriangleVertexUV(ttt, 2);
                vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                otuv22 = (otuv22-otuvc)*0.99+otuvc;

                c = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
                c.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;
                if (abs(c.a-otid2-1) > 0.5) {
                  return vec4(1.0, 0.0, 0.0, 0.0);
               }
            }
        }
    }

    if (abs(d.a-triangleId) > 0.5) {
       d = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, 0.50),rot)), 0);
       d.a = texelFetch(tex, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, 0.50),rot)), 0).a;
        if (abs(d.a-otid-1) > 0.5) {
// return vec4(1.0, 0.0, 0.0, 0.0);
//            if (ctf.x > 0.5)
//                oted2 = 0; // getClosestVertex(thisTid, posOrigG.xyz)-1;
//            if (ctf.y > 0.5)
//                oted2 = 0;
//            if (oted2 == 3) oted2 = 0;
//            if (oted2 < 0) oted2 = 2;
//            otid2 = getOtherTriangleId(thisTid, oted2);
//            closestEdge = getClosestEdge(otid2, posOrigG.xyz); // getEdgeCen(thisTid, oted2));
//            otuv22 = getOtuv(thisTid, otid2, oted2, closestEdge, 0, posOrigG.xyz);
//            rot2 = getRot(oted2, closestEdge);
//            d = texelFetch(t, ivec2(getTexCoord(otuv22)+rotateXY2(vec2(0.50, 0.50),rot2)), 0);

            otid2 = thisTid;
            oted2 = getClosestVertex(otid2, posOrigG.xyz);
            //oted2 = 0;
            if (oted2 == 3) oted2 = 0;
            if (oted2 < 0) oted2 = 2;
            int tidedi = otid2;
            otid2 = getOtherTriangleId(otid2, oted2);
            closestVertex = getClosestVertex(otid2, posOrigG.xyz);
            if (closestVertex < 0) closestVertex = 2;
            closestEdge = getClosestEdge(otid2, posOrigG.xyz);

         //   closestVertex = 1;
            otuv22 = getTriangleVertexUV(otid2, closestVertex);

            rot2 = getRot(oted2, closestEdge);
            ttt = otid2;

            vec2 otuv0 = getTriangleVertexUV(ttt, 0);
            vec2 otuv1 = getTriangleVertexUV(ttt, 1);
            vec2 otuv2 = getTriangleVertexUV(ttt, 2);
            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
            otuv22 = (otuv22-otuvc)*0.999+otuvc;

            d = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
            d.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;
            if (abs(d.a-otid2-1) > 0.5) {
                oted2 = getClosestVertex(otid2, posOrigG.xyz)-1;
                if (oted2 == 3) oted2 = 0;
                if (oted2 < 0) oted2 = 2;
                int tidedi = otid2;
                otid2 = getOtherTriangleId(otid2, oted2);
                closestVertex = getClosestVertex(otid2, posOrigG.xyz);
                otuv22 = getTriangleVertexUV(otid2, closestVertex);

                ttt = otid2;

                vec2 otuv0 = getTriangleVertexUV(ttt, 0);
                vec2 otuv1 = getTriangleVertexUV(ttt, 1);
                vec2 otuv2 = getTriangleVertexUV(ttt, 2);
                vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                otuv22 = (otuv22-otuvc)*0.99+otuvc;

                d = texelFetch(t, ivec2(getTexCoord(otuv22)), 0);
                d.a = texelFetch(tex, ivec2(getTexCoord(otuv22)), 0).a;
                if (abs(d.a-otid2-1) > 0.5) {
                  return vec4(1.0, 0.0, 0.0, 0.0);
               }
            }
        }
    }

    float f0 = 1.0-ctf.x;
    float f1 = ctf.x;
    float f2 = 1.0-ctf.y;
    float f3 = ctf.y;


   // return base;

//    a=vec4(0.0);
//    b=vec4(0.0);
//    c=vec4(0.0);
//    d=vec4(0.0);

    vec2 mcb = cb;

//    kob = imageLoad(texSpaceDirX, ivec2(mcb));

//    if (f2 > 0.5) {
//   //     return vec4(0.0);
//        if (f0 > 0.5) {
//        a = texelFetch(t, ivec2(mcb), 0);
//        b = texelFetch(t, ivec2(kob.zw), 0);

//        kob = imageLoad(texSpaceDirY, ivec2(mcb));
//        c = texelFetch(t, ivec2(kob.xy), 0);
//      //  c = imageLoad(triangleIds, ivec2(kob.xy));
//        kob = imageLoad(texSpaceDirX, ivec2(mcb));
//        d = imageLoad(texSpaceDirY, ivec2(kob.zw));
//        d = texelFetch(t, ivec2(d.xy), 0);

////        k = a;
////        a = b;
////        b = c;
////        c = d;
////        d = k;

////        k = c;
////        c = d;
////        d = k;
//   //     a = vec4(0.0);
//   //     b = vec4(0.0);
//   //
//        } else {
//            return vec4(0.0);
//            if (f0 <= 0.5) {
//            a = texelFetch(t, ivec2(kob.xy), 0);
//            b = base; // texelFetch(t, ivec2(kob.zw), 0);

//            kob = imageLoad(texSpaceDirY, ivec2(mcb));
//            d = texelFetch(t, ivec2(kob.xy), 0);
//          //  c = imageLoad(triangleIds, ivec2(kob.xy));
//            kob = imageLoad(texSpaceDirX, ivec2(mcb));
//            c = imageLoad(texSpaceDirY, ivec2(kob.xy));
//            c = texelFetch(t, ivec2(c.xy), 0);

//            } else {
//                return vec4(0.0);
//            }
//        }
//    } else {
//        return vec4(0.0);
//        if (f0 > 0.5) {
//        c = base; // texelFetch(t, ivec2(kob.xy), 0);
//        d = texelFetch(t, ivec2(kob.zw), 0);

//        kob = imageLoad(texSpaceDirY, ivec2(mcb));
//        a = texelFetch(t, ivec2(kob.zw), 0);
//      //  c = imageLoad(triangleIds, ivec2(kob.xy));
//        kob = imageLoad(texSpaceDirX, ivec2(mcb));
//        b = imageLoad(texSpaceDirY, ivec2(kob.zw));
//        b = texelFetch(t, ivec2(b.zw), 0);
//    //return vec4(0.0);
//        } else {
//            if (f0 <= 0.5) {
//            d = base; // texelFetch(t, ivec2(kob.zw), 0);
//            c = texelFetch(t, ivec2(kob.xy), 0);

//            kob = imageLoad(texSpaceDirY, ivec2(mcb));
//            b = texelFetch(t, ivec2(kob.zw), 0);
//          //  c = imageLoad(triangleIds, ivec2(kob.xy));
//            kob = imageLoad(texSpaceDirX, ivec2(mcb));
//            a = imageLoad(texSpaceDirY, ivec2(kob.xy));
//            a = texelFetch(t, ivec2(a.zw), 0);

//            } else {
//                return vec4(0.0);
//            }
//        }
//    }



//      kob = imageLoad(texSpaceDirX, ivec2(cb));

//          if (int(kob.x)==0 && int(kob.y)==0) {
//              return vec4(1.0, 0.0, 0.0, 0.0);
//          }
//          if (int(kob.z)==0 && int(kob.w)==0) {
//              return vec4(1.0, 0.0, 0.0, 0.0);
//          }

//     //     kob = imageLoad(texSpaceDirY, ivec2(cb));

//              if (int(kob.x)==0 && int(kob.y)==0) {
//                  return vec4(1.0, 0.0, 0.0, 0.0);
//              }
//              if (int(kob.z)==0 && int(kob.w)==0) {
//                  return vec4(1.0, 0.0, 0.0, 0.0);
//              }
//      c = texelFetch(t, ivec2(kob.xy), 0);

//      if (abs(c.a-triangleId)>0.5) {
//      //    return vec4(1.0, 0.0, 0.0, 0.0);
//      }


//     return c;
//    return base;

 //   c = vec4(0.0);
//    b = vec4(0.0);
 //   d = vec4(0.0);

 //   return c;
 //   return base;
 //   return (a+b+c+d)*0.25;

 //   return vec4(fract(c.a*0.1));

//    if (abs(b.a-triangleId) > 0.5) {
//        b = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, -0.50),rot)), 0);
//        if (abs(b.a-otid-1) > 0.5) {
//            return vec4(1.0, 0.0, 0.0, 0.0);
//        }
//    }
//    if (abs(c.a-triangleId) > 0.5) {
//        c = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, 0.50),rot)), 0);
//        if (abs(c.a-otid-1) > 0.5) {
//            return vec4(1.0, 0.0, 0.0, 0.0);
//        }
//    }
//    if (abs(d.a-triangleId) > 0.5) {
//        d = texelFetch(t, ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, 0.50),rot)), 0);
//        if (abs(d.a-otid-1) > 0.5) {
//            return vec4(1.0, 0.0, 0.0, 0.0);
//        }
//    }


    //return d;

  //  return base;



    if (closestEdge < 0) {
  //      return vec4(0.0, 1.0, 0.0, 0.0);
    }
    if (oted < 0) {
   //     return vec4(0.0, 1.0, 0.0, 0.0);
    }

    if (otido < 0) {
   //    return vec4(1.0, 0.0, 0.0, 0.0);
    }

  //  return vec4(oted*0.5);
  //  return base;

    return (a*f0+b*f1)*f2+
           (c*f0+d*f1)*f3;
}



void main() {

  vec3 normal = normalG;
  vec2 uv = uvG;
  vec3 tangent = tangentG;
  vec3 color = colorG;
  float sk = 0.2;


  vec4 diffuse = vec4(1.0);
//  vec4 diffuse = getCol(1.0, vec2(0.0, 0.0));
//  diffuse *= (getCol(1.5, vec2(0.07, 0.069))+vec4(0.450));
//  diffuse *= (getCol(0.50, vec2(0.02, -0.069))+vec4(0.450));
//  diffuse *= g_texBrightness*1.0;

  vec2 k = vec2(gl_FragCoord.xy);
  float d = texelFetch(texDepth, ivec2(k), 0).x;
  vec4 pos3D = CalcEyeFromWindow(vec3(k, d));
  vec4 mpos3D = projectionInvMatrix*posG;


// diffuse.rgb = posW.rgb;
// diffuse.rgb *= color.rgb;
 vec3 p = posW.rgb;

 float nAmp = 0.05;

 // uv -= (0.5/g_texW, 0.5/g_texH);

 vec4 t = getTexBi(tex, uv);

 float triangleId = round(triangleIdG);
 int thisTid = int(triangleId)-1;

 ivec2 tuv = ivec2(getTexCoord(uvnG));

 vec4 baseTex = texelFetch(texWave, tuv, 0);
 vec4 cx = texelFetch(texSpaceDirX, tuv, 0);
 vec4 cy = texelFetch(texSpaceDirY, tuv, 0);

// ivec2 test0 = ivec2(getTexCoord(uv));
// ivec2 test1 = ivec2(getTexCoord(uv+vec2(0.50/g_texW, 0.0)));
// ivec2 test2 = ivec2(getTexCoord(uv+vec2(0.0, 0.50/g_texH)));

// vec4 tx = getTexBi(texWave, uv+vec2(0.50/g_texW, 0.0));
// vec4 ty = getTexBi(texWave, uv+vec2(0.0, 0.5/g_texH));
 vec4 tx = texelFetch(texWave, ivec2(cx.zw), 0);
 vec4 ty = texelFetch(texWave, ivec2(cy.xy), 0);

// float tid = t.a;



//// t.rgb += vec3(0.25);

// float per = baseTex.r;
 float per = getTexBi(texWave, uv).r;

// float bx = tx.r-per;
// float by = ty.r-per;

 //vec3 normD = texelFetch(texSpaceNormal, tuv, 0).rgb;
 vec3 normD = getTexBi(texSpaceNormal, uv).rgb;

// normD = normalWSG;

 normD = normalize(normD);

// vec3 bita = cross(normD, tangentG);
// float bs = 16.0;
 //normD = normD-tangentG*bx*bs-bita*by*bs;

// normD = normalize(normD);

 float dd = dot(normD,normalize(vec3(-0.50,-1.20,-1.30)));
 dd = clamp(dd, 0.0, 1.0);

 dd = pow(dd, 512.0)*2.0+pow(dd, 2.0)*0.0;

// dd = bx;

 //t.rgb *= t.rgb;
 t.rgb = clamp(t.rgb, 0.0, 10.0);
 t.rgb = (t.rgb*0.00+0.0)+vec3(dd);
// t.rgb = pow(t.rgb, vec3(0.5));
// t.rgb = vec3(dd);
// if (abs(baseTex.a-thisTid-1)>0.5) {
//     t.rgb = vec3(1.0, 0.0, 0.0);
// }

// if (test1.x != test0.x) {
////     t.rgb = vec3(1.0, 0.0, 0.0);
// }

 vec2 enviBase = (vec2(gl_FragCoord.x/g_windowWidth, gl_FragCoord.y/g_windowHeight)-vec2(0.5, 0.5));

 vec2 refr;

 // get normal to view space
 normD = (viewMatrix*vec4(normD, 0.0)).xyz;

 refr = pow(abs(normD.xy), vec2(4.0))*sign(normD.xy);


 vec2 enviUv = enviBase*1.0-refr*0.2+vec2(0.5,0.5);
 vec4 envi = texture2D(texEnv, enviUv);

 vec2 enviUvs = vec2(enviUv.x*g_windowWidth, enviUv.y*g_windowHeight);

 vec4 envPos3D = CalcEyeFromWindow(vec3(enviUvs, texelFetch(texDepth, ivec2(enviUvs), 0).x));

// float distEnv =  abs(mpos3D.z-envPos3D.z);
// float distEnvFac = clamp(1.0-distEnv*0.30, 0.0, 1.0);

 float distEnvFac = envi.a;

 if (envPos3D.z >= mpos3D.z) {
     envi.rgb = texture2D(texBg, enviUv).rgb;
     //distEnvFac = 0.0;
 }

 envi *= distEnvFac*0.50;


 // reflect fake env
 vec4 enviBg;
 refr = pow(abs(normD.xy), vec2(2.0))*sign(normD.xy);
 enviUv = enviBase*0.20-refr*0.5+vec2(0.5,0.5);
 enviBg = texture2D(texBg, enviUv)*0.80;
 envi += (1.0-distEnvFac)*enviBg;

 refr = pow(abs(normD.xy), vec2(3.0))*sign(normD.xy);
 enviUv = enviBase*1.0+refr*0.5+vec2(0.5,0.5);

 envPos3D = CalcEyeFromWindow(vec3(enviUvs, texelFetch(texDepth, ivec2(enviUvs), 0).x));
 enviBg = texture2D(texBg, enviUv);
 float reflFake = 0.20;
 if (envPos3D.z >= mpos3D.z) {
     envi += texture2D(texEnv, enviUv)*reflFake;
 } else {
     envi += enviBg*reflFake;
 }

// envi *= 0.0;


 t.rgb += envi.rgb*pow((abs(normD.z+0.0)*0.5+0.5),1.0)*1.0;

 //t.rgb = vec3(baseTex.r);

// t.rgb = texelFetch(texSpaceNormal, tuv, 0).rgb;
// t.rgb = normD;

// t.rg = normD.xy;
// t.rgb = vec3(per)*0.1;
 diffuse.rgb = t.rgb; // *color.rgb;

// diffuse.rgb = color.rgb;

// if (abs(tid-triangleIdG) > 0.5) {
//     diffuse.rgb *= 0.0;
// }

 // diffuse.rgb *=diffuse.rgb*g_texBrightness;
 // diffuse.rgb += vec3(g_texAmbient);
// diffuse.rgb *= color.rgb;
//  diffuse.rgb = vec3(0.2);



 frag.rgb = diffuse.rgb*g_bright;
// frag.rgb = tonemapUC2(frag.rgb);
// frag.rgb = pow(frag.rgb, vec3(0.50));
  frag.a = 1.0;
//  if (g_texW > 4095.0) frag.rgb = vec3(1.0, 0.0, 0.0);

  frag2.rgb = normalize(normD).xyz;
  frag2 = clamp(frag2, -1.0, 1.0);
  frag2.a = 1.0;


  frag3.rgb = vec3(0.0);
  frag3.a = 1.0;

  // emit new waves if something close in depth

 // float md = texelFetch(texMainDepth, ivec2(k), 0).x;
 // vec4 mpos3D = CalcEyeFromWindow(vec3(k, md));


  vec3 disto = mpos3D.rgb-pos3D.rgb;

  float dis = clamp(1.0-dot(disto, disto)*32.0, 0.0, 1.0);
//  dis = pow(dis, 16.0)*1.0;

//  frag.rgb = mpos3D.rgb;

  if (dis > 0.0) {
       frag.rgb += 0.0*vec3(dis);
      imageStore(texWaveFeed, ivec2(getTexCoord(uvnG)), vec4(2.0));
  }


}

