#version 430

layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D tex2;
layout(binding=2) uniform sampler2D tex3;
layout(binding=3) uniform sampler2D tex4;
layout(binding=4) uniform sampler2D texPrevBlurFrame;
layout(binding=5) uniform sampler2D texPrevNorm;


in vec4 posG;
in vec3 normalG;
in vec3 normalWSG;
in vec2 uvG;
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;


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

// 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 spreadSpec3(vec3 c, float sp) {
    sp = fract(sp);
    c.r *= smoothstep(1.0, 0.0, (1.0-sp)*1.0);
    c.g *= smoothstep(1.0, 0.0, abs((sp-0.5)*2.0));
    c.b *= smoothstep(1.0, 0.0, sp*1.0);
    return c;
}

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.30+sw)/sw, -1.0, 1.0);
    vec3 r = (vec3(res*1.3, res*1.1, res*1.0)*20.0+vec3(0.0));
    vec3 rr = vec3(0.0);
    for (int i=0; i<32; i++) {
        rr += spreadSpec3(r, pk*i*0.1+i/16.0);
    }
    return rr/32.0;
}


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

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




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



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 texSpaceDirX;
layout(binding=6, rgba32f) uniform image2D texSpaceDirY;
layout(binding=7, rgba32f) uniform image2D texSpace;


uniform float g_texW = 1280;
uniform float g_texH = 720;
uniform float g_quadsPerRow = 128;
uniform float g_triangleTexDim;

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

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


int getClosestEdge(int otid, vec3 pos) {

    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 = 0.5;

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


int getClosestVertex(int tid, vec3 pos) {
    float d, d2;

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

    vec3 dd;
    int closest = 0;

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




vec2 guv = vec2(0.0);


vec2 getOtuv(int tid, int otid, int oted, int closestEdge) {
    float edgeInt = 0.0;
    vec2 uv0 = getTriangleVertexUV(tid, 0);
    vec2 uv1 = getTriangleVertexUV(tid, 1);
    vec2 uv2 = getTriangleVertexUV(tid, 2);

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

    //  edgeInt = 1.0-edgeInt;

    //  edgeInt = 0.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);
    }

    return vec2(otuv);
}

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


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;


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

    // float nAmp = 0.5;

    // p.y += turb(p*0.20)*nAmp;
    // p.x += turb(p.yzx*0.3747)*nAmp;

    // diffuse.rgb = vec3(texStripesRad(p));

    int tid = int(round(triangleIdG))-1;

    vec4 pb = vec4(gl_FragCoord.xy, gl_FragCoord.xy);
    ivec2 ct = ivec2(gl_FragCoord.xy);

    // debug
    // vec4 dirx = vec4(0.0); // (pb+vec4(1.0, 0.0, -1.0, 0.0));
    // vec4 diry = vec4(0.0); // (pb+vec4(0.0, 1.0, 0.0, -1.0));

    // real deal
    vec4 dirx = (pb+vec4(-1.0, 0.0, 1.0, 0.0));
    vec4 diry = (pb+vec4(0.0, 1.0, 0.0, -1.0));

    guv = vec2(ct.x, ct.y)+0.0*vec2(0.5, 0.5);
    guv.x = guv.x/g_texW;
    guv.y = guv.y/g_texH;


//    vec4 tLeft = imageLoad(texSpace, ct+ivec2(-1, 0));
//    if (abs(tLeft.a-triangleIdG)>0.5) {
//        //  int otid = getOtherTriangleId(tid, 1);
//        //  int closestEdge = getClosestEdge(otid, getEdgeCen(tid, 1));
//        //  vec2 otuv = getOtuv(tid, otid, 1, closestEdge);
//        //  float rot = getRot(1, closestEdge);
//        //  ivec2 vt = ivec2(getTexCoord(otuv)+0.0*rotateXY2(vec2(0.0, 1.0), rot));

//        int oted = 1;
//        int otid = getOtherTriangleId(tid, oted);
//        int closestEdge = getClosestEdge(otid, getEdgeCen(tid, oted));
//        vec2 otuv = getOtuv(tid, otid, oted, closestEdge);
//        float rot = getRot(oted, closestEdge);
//        ivec2 vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, -0.50), rot));
////        if (closestEdge==2) {
////            vt.y -= 1; // 1->2
////        }
////        if (closestEdge==0) {
////            vt.x += 1;
////        }
//        vt.x -= 1;
//        tLeft = imageLoad(texSpace, vt);
//        dirx.xy = vt;
//        if (abs(tLeft.a-otid-1)>0.5) {
//         //   vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, 0.50), rot));
//          //  vt.x -= 1;
//            if (closestEdge==2) {
//                vt.y += 1;
//            }
//            if (closestEdge==0) {
//                vt.x -= 1;
//            }

//      //      oted = 2;
//           // vt.y += 1;
//            dirx.xy = vt;
//            dirx.xy = vec2(0.0, 0.0);
//            tLeft = imageLoad(texSpace, vt);
//            if (abs(tLeft.a-otid-1)>0.5) {
//                vt.x -= 1;
//              //  vt.y -= 1;
//                dirx.xy = vt;
//                dirx.xy = vec2(0.0, 0.0);
//                tLeft = imageLoad(texSpace, vt);
//                if (abs(tLeft.a-otid-1)>0.5) {
//                    vt.x += 1;
//                    vt.y -= 1;
//                    dirx.xy = vt;
//                    dirx.xy = vec2(0.0, 0.0);
//                 //    dirx.xy = vec2(0.0, 0.0);
//                    tLeft = imageLoad(texSpace, vt);
//                    if (abs(tLeft.a-otid-1)>0.5) {

//             //     dirx.xy = ct;
//                    dirx.xy = vec2(0.0, 0.0);
//                    }
//                }

//            }
//            dirx.xy = vec2(0.0, 0.0);

//        }

//    //    dirx.xy = ct;
//    //    dirx.xy = vec2(0.0, 0.0);
//    }

    vec4 tLeft = imageLoad(texSpace, ct+ivec2(-1, 0));
    if (abs(tLeft.a-triangleIdG)>0.5) {
        //  int otid = getOtherTriangleId(tid, 1);
        //  int closestEdge = getClosestEdge(otid, getEdgeCen(tid, 1));
        //  vec2 otuv = getOtuv(tid, otid, 1, closestEdge);
        //  float rot = getRot(1, closestEdge);
        //  ivec2 vt = ivec2(getTexCoord(otuv)+0.0*rotateXY2(vec2(0.0, 1.0), rot));

        int oted = 1;
        int otid = getOtherTriangleId(tid, oted);
        int closestEdge = getClosestEdge(otid, getEdgeCen(tid, oted));
        vec2 otuv = getOtuv(tid, otid, oted, closestEdge);
        float rot = getRot(oted, closestEdge);
        ivec2 vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(-1.50, 0.50), rot));
        if (closestEdge==2) {
            vt.y -= 1; // 1->2
        }
        if (closestEdge==0) {
            vt.x += 1;
        }
       // vt.x += 1;
        tLeft = imageLoad(texSpace, vt);
        dirx.xy = vt;
        if (abs(tLeft.a-otid-1)>0.5) {
         //   vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(-0.50, 0.50), rot));
          //  vt.x -= 1;
          //  vt.y -= 1;

      //      oted = 2;
            oted = closestEdge+1;
            if (oted > 2) oted = 0;
            if (oted < 0) oted = 2;

            int otid2 = getOtherTriangleId(otid, oted);
            vec3 closestOrigPos = getTriangleVertex(tid, 1);
            closestEdge = getClosestVertex(otid2, closestOrigPos);
            vec2 otuv0 = getTriangleVertexUV(otid2, 0);
            vec2 otuv1 = getTriangleVertexUV(otid2, 1);
            vec2 otuv2 = getTriangleVertexUV(otid2, 2);
            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
            vec2 otuv22 = otuv2;
            if (closestEdge == 0) {
                otuv22 = otuv0;
            }
            if (closestEdge == 1) {
                otuv22 = otuv1;
            }
            if (closestEdge == 2) {
                otuv22 = otuv2;
            }
            otuv22 = (otuv22-otuvc)*0.999+otuvc;
            vt = ivec2(getTexCoord(otuv22));
           // vt.y += 1;
            dirx.xy = vt;
            //dirx.xy = vec2(0.0, 0.0);
            tLeft = imageLoad(texSpace, vt);
            if (abs(tLeft.a-otid2-1)>0.5) {
                vt.x -= 1;
              //  vt.y -= 1;
                dirx.xy = vt;
              //   dirx.xy = vec2(0.0, 0.0);
                tLeft = imageLoad(texSpace, vt);
                if (abs(tLeft.a-otid-1)>0.5) {
                    vt.x += 1;
                    vt.y -= 1;
                    dirx.xy = vt;
                 //    dirx.xy = vec2(0.0, 0.0);
                    tLeft = imageLoad(texSpace, vt);
                    if (abs(tLeft.a-otid-1)>0.5) {

             //     dirx.xy = ct;
                    dirx.xy = vec2(-1.0, -1.0);
                    }
                }
            }
        }

    //    dirx.xy = ct;
    //    dirx.xy = vec2(0.0, 0.0);
    }


    vec4 tRight = imageLoad(texSpace, ct+ivec2(1, 0));
    if (abs(tRight.a-triangleIdG)>0.5) {
        int oted = 2;
        int otid = getOtherTriangleId(tid, oted);
        int closestEdge = getClosestEdge(otid, getEdgeCen(tid, oted));
        vec2 otuv = getOtuv(tid, otid, oted, closestEdge);
        float rot = getRot(oted, closestEdge);
        ivec2 vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, 0.50), rot));
        tRight = imageLoad(texSpace, vt);
        dirx.zw = vt;
        if (abs(tRight.a-otid-1)>0.5) {
          //  vt.y -= 1;

            oted = 0;
            oted = closestEdge-1;
            if (oted > 2) oted = 0;
            if (oted < 0) oted = 2;
            int otid2 = getOtherTriangleId(otid, oted);
            vec3 closestOrigPos = getTriangleVertex(tid, 0);
            closestEdge = getClosestVertex(otid2, closestOrigPos);
            vec2 otuv0 = getTriangleVertexUV(otid2, 0);
            vec2 otuv1 = getTriangleVertexUV(otid2, 1);
            vec2 otuv2 = getTriangleVertexUV(otid2, 2);
            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
            vec2 otuv22 = otuv2;
            if (closestEdge == 0) {
                otuv22 = otuv0;
            }
            if (closestEdge == 1) {
                otuv22 = otuv1;
            }
            if (closestEdge == 2) {
                otuv22 = otuv2;
            }
            otuv22 = (otuv22-otuvc)*0.999+otuvc;
            vt = ivec2(getTexCoord(otuv22));


            dirx.zw = vt;
           // if (oted == 1) {
           //    dirx.zw = vec2(0.0, 0.0);
           // }
            tRight = imageLoad(texSpace, vt);
            if (abs(tRight.a-otid2-1)>0.5) {
                vt.y += 1;
                vt.x -= 1;
                dirx.zw = vt;
              //  dirx.zw = vec2(0.0, 0.0);
                tRight = imageLoad(texSpace, vt);
                if (abs(tRight.a-otid-1)>0.5) {
           //    dirx.zw = ct;
                dirx.zw = vec2(-1.0, -1.0);
            //        dirx.zw = ct;
                }
            }
         //   dirx.zw = vec2(0.0, 0.0);
        }
     //   dirx.zw = vec2(0.0, 0.0);

    //    dirx.zw = vec2(0.0, 0.0);
       //  dirx.zw = vec2(0.0, 0.0);
     //   dirx.zw = ct;
   }

    vec4 tUp = imageLoad(texSpace, ct+ivec2(0, 1));
    if (abs(tUp.a-triangleIdG)>0.5) {
        int oted = 0;
        int otid = getOtherTriangleId(tid, oted);
        int closestEdge = getClosestEdge(otid, getEdgeCen(tid, oted));
        vec2 otuv = getOtuv(tid, otid, oted, closestEdge);
        float rot = getRot(oted, closestEdge);
        ivec2 vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.750, 0.50), rot));
        tUp = imageLoad(texSpace, vt);
     //   vt.y -= 1;
        diry.xy = vt;
    //   diry.xy = vec2(0.0, 0.0);
        if (abs(tUp.a-otid-1)>0.5) {
           // vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.0, 1.0), rot));
           // vt.x -= 1;
            vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.0, 0.50), rot));
//            vt.y -= 1;
            diry.xy = vt;
         //   diry.xy = vec2(0.0, 0.0);
            tUp = imageLoad(texSpace, vt);
            if (abs(tUp.a-otid-1)>0.5) {
//                vt.x += 2;
//                vt.y -= 1;
                oted = 1;
                int otid2 = getOtherTriangleId(otid, oted);
                vec3 closestOrigPos = getTriangleVertex(tid, 1);
                closestEdge = getClosestVertex(otid2, closestOrigPos);
                vec2 otuv0 = getTriangleVertexUV(otid2, 0);
                vec2 otuv1 = getTriangleVertexUV(otid2, 1);
                vec2 otuv2 = getTriangleVertexUV(otid2, 2);
                vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                vec2 otuv22 = otuv2;
                if (closestEdge == 0) {
                    otuv22 = otuv0;
                }
                if (closestEdge == 1) {
                    otuv22 = otuv1;
                }
                if (closestEdge == 2) {
                    otuv22 = otuv2;
                }
                otuv22 = (otuv22-otuvc)*0.999+otuvc;
                vt = ivec2(getTexCoord(otuv22));


                diry.xy = vt;
            //    diry.xy = vec2(0.0, 0.0);
             //   diry.xy = vec2(0.0, 0.0);
                tUp = imageLoad(texSpace, vt);
                if (abs(tUp.a-otid2-1)>0.5) {
                   //      diry.xy = ct;
                    diry.xy = vec2(-1.0, -1.0);
                }
            }
        }
      //  diry.xy = vec2(0.0, 0.0);

    //    diry.xy = ct;
       // diry.xy = vec2(0.0, 0.0);
    }

    vec4 tDown = imageLoad(texSpace, ct+ivec2(0, -1));
    if (abs(tDown.a-triangleIdG)>0.5) {
        int oted = 1;
        int otid = getOtherTriangleId(tid, oted);
        int closestEdge = getClosestEdge(otid, getEdgeCen(tid, oted));
        vec2 otuv = getOtuv(tid, otid, oted, closestEdge);
        float rot = getRot(oted, closestEdge);
        ivec2 vt;
        if (closestEdge == 1) {
            vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, -0.50), rot)); // 1 -> 2 (y -0.5 to 0.5)
        } else {
            vt = ivec2(getTexCoord(otuv)+rotateXY2(vec2(0.50, 0.50), rot)); // 1 -> 2 (y -0.5 to 0.5)
        }
        if (closestEdge != 0) {
            vt.x += 1;
        }
      //  vt.y += 1;
        tDown = imageLoad(texSpace, vt);
        diry.zw = vt;
        if (abs(tDown.a-otid-1)>0.5) {
            vt.x -= 2;

//            oted = closestEdge-1;
//            if (oted > 2) oted = 0;
//            if (oted < 0) oted = 2;
//          //  oted = 0;
//            int otid2 = getOtherTriangleId(otid, oted);
//            vec3 closestOrigPos = getTriangleVertex(tid, 0);
//            closestEdge = getClosestVertex(otid2, closestOrigPos);
//            vec2 otuv0 = getTriangleVertexUV(otid2, 0);
//            vec2 otuv1 = getTriangleVertexUV(otid2, 1);
//            vec2 otuv2 = getTriangleVertexUV(otid2, 2);
//            vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
//            vec2 otuv22 = otuv2;
//            if (closestEdge == 0) {
//                otuv22 = otuv0;
//            }
//            if (closestEdge == 1) {
//                otuv22 = otuv1;
//            }
//            if (closestEdge == 2) {
//                otuv22 = otuv2;
//            }
//            otuv22 = (otuv22-otuvc)*0.99+otuvc;
//            vt = ivec2(getTexCoord(otuv22));

            diry.zw = vt;
          //  diry.zw = vec2(0.0, 0.0);
            tDown = imageLoad(texSpace, vt);
            if (abs(tDown.a-otid-1)>0.5) {
                vt.y -= 1;
                vt.x += 1;
                diry.zw = vt;
              //  diry.zw = vec2(0.0, 0.0);
                tDown = imageLoad(texSpace, vt);
                if (abs(tDown.a-otid-1)>0.5) {
         //           diry.zw = ct;

                    oted = closestEdge-1;
                    if (oted > 2) oted = 0;
                    if (oted < 0) oted = 2;
                    //  oted = 0;
                    int otid2 = getOtherTriangleId(otid, oted);
                    vec3 closestOrigPos = getTriangleVertex(tid, 2);
                    closestEdge = getClosestVertex(otid2, closestOrigPos);
                    vec2 otuv0 = getTriangleVertexUV(otid2, 0);
                    vec2 otuv1 = getTriangleVertexUV(otid2, 1);
                    vec2 otuv2 = getTriangleVertexUV(otid2, 2);
                    vec2 otuvc = (otuv0+otuv1+otuv2)/3.0;
                    vec2 otuv22 = otuv2;
                    if (closestEdge == 0) {
                        otuv22 = otuv0;
                    }
                    if (closestEdge == 1) {
                        otuv22 = otuv1;
                    }
                    if (closestEdge == 2) {
                        otuv22 = otuv2;
                    }
                    otuv22 = (otuv22-otuvc)*0.99+otuvc;
                    vt = ivec2(getTexCoord(otuv22));
                    diry.zw = vt;
                 //   diry.zw = vec2(0.0, 0.0);
                    tDown = imageLoad(texSpace, vt);
                    if (abs(tDown.a-otid2-1)>0.5) {
                        diry.zw = vec2(-1.0, -1.0);
                    }
                }
            }
        }
        //diry.zw = ct;
    }


//    dirx = (pb+vec4(-1.0, 0.0, 1.0, 0.0));
//    diry = (pb+vec4(0.0, 1.0, 0.0, -1.0));



    // debug
    // imageStore(texSpaceDirX, ct, dirx/1024.0);
    // imageStore(texSpaceDirY, ct, diry/1024.0);

    // real deal
    imageStore(texSpaceDirX, ct, dirx);
    imageStore(texSpaceDirY, ct, diry);

    //  imageStore(texSpaceDirX, ct, tLeft);
    //  imageStore(texSpaceDirX, ct, vec4(1.0, 0.0, 0.0, 0.0));

    discard;

    return;



}

