#version 430


layout (location=0) in vec3 vertexPosition;
layout (location=1) in vec3 vertexNormal;
layout (location=2) in vec2 vertexUV;
layout (location=3) in vec3 vertexTangent;

out vec3 normal;
out vec2 uv;
out vec3 tangent;
out vec4 origPos;
out vec3 mirrorInfo;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

uniform float g_time;



layout(binding=8) uniform sampler2D texNoise;

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

vec3 rotateXZ3(vec3 p, float a) {
    return rotateXZ(vec4(p, 0.0), a).xyz;
}

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

vec4 rotateYZ(vec4 p, float a) {
    vec4 r = p;
    r.y = cos(a)*p.y - sin(a)*p.z;
    r.z = sin(a)*p.y + cos(a)*p.z;
    return r;
}
vec3 rotateYZ3(vec3 p, float a) {
    vec3 r = p;
    r.y = cos(a)*p.y - sin(a)*p.z;
    r.z = sin(a)*p.y + cos(a)*p.z;
    return r;
}


float rnd(vec2 co) {
  return (fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453));
}

float rndc(vec2 co) {
        return rnd(co)*2.0-1.0;
}

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



vec4 turbVert(vec2 tc, int fr) {
  vec4 r = vec4(0.0, 0.0, 0.0, 0.0);
  float m = 0.50;
  for (int i=0; i<fr; i++) {
    r += (texture2D(texNoise, vec2(tc.x, tc.y))*2.0-1.0)*m;
    tc *= 2.0;
    m *= 0.5;
  }
  return r;
}


uniform float g_particleIndexOffset = 0.0f;

uniform vec4 rsty_xz = vec4(0.1, 0.1, 0.5, 0.0);
uniform vec4 rsty_yz = vec4(0.0, 0.1, 0.5, 0.0);
uniform vec4 rsty_xy = vec4(0.0, 0.1, 0.2, 0.0);
uniform vec4 rcObj = vec4(32.0, 32.0, 2.0, 0.0);
uniform vec4 scale = vec4(1.0, 1.0, 1.0, 1.0);
uniform vec4 repMov = vec4(1.0, 1.0, 0.0, 0.00);
uniform vec4 repGroup = vec4(0.0, 0.0, 0.0, 0.0); // .x repGroupCount, .y repGroupGap
uniform vec4 objParams = vec4(1.0, 0.0, 0.0, 0.0); // .x mirror
uniform vec4 objParams2 = vec4(0.0, 0.0, 0.0, 0.0); // .x mirrorClip

uniform vec4 pos = vec4(0.0, 0.0, 0.0, 0.0);
uniform vec4 prePos = vec4(0.0, 0.0, 0.0, 0.0);

// .x clamp height on, .y clamp offset, .z clamp min, .w clamp max
uniform vec4 genHeight = vec4(0.0, 0.0, -1.0, 1.0);

// .x exponent of height -1
uniform vec4 genHeight2 = vec4(0.0, 0.0, 0.0, 0.0);

uniform vec4 repRand = vec4(0.0, 0.0, 0.0, 0.0);
uniform vec4 repRand2 = vec4(0.0, 0.0, 0.0, 0.0);

uniform vec4 genCurve = vec4(0.0, 0.0, 0.0, 0.0);
uniform vec4 genCurve2 = vec4(0.0, 0.0, 0.0, 0.0);

uniform vec4 walker = vec4(0.0, 0.0, 0.0, 0.0); // .x legLen1, .y legLen2, .z legDist, .w legLift,
uniform vec4 walker2 = vec4(0.0, 0.0, 0.0, 0.0); // .x legRad1, .y legRad2, z. bodyLift, w. bodyLiftVar
uniform vec4 walker3 = vec4(0.0, 0.0, 0.0, 0.0); // .x bodyLiftVFreq1, y. bodyLiftVar2, .z bodyLiftVFreq2, .w bodyLiftRepVar
uniform vec4 walker4 = vec4(0.0, 0.0, 0.0, 0.0); // .x legPhaseRep

uniform vec4 g_bump = vec4(0.0, 0.0, 0.0, 0.0);

uniform vec4 g_texCoordScale = vec4(1.0, 1.0, 1.0, 1.0);


float getPlaneNV(float rows, float cols) {
    return (rows*cols*6.0);
}
// id: vertex id number
vec4 getPlane(float id, float rows, float cols, inout vec4 n, inout vec2 tc, inout vec4 ta) {
    float id3 = fract(id/3.0)*3.0; // index of the vertex in a triangle 0,1,2
    float idv = floor((id/3.0-fract(id/3.0))+0.5); // triangle index 0,1,2,3,...
    float idvq = floor((id/6.0-fract(id/6.0))+0.5); // quad index 0,1,2,3,...
    float idv2 = fract(idv/2.0)*2.0; // every second triangle 0 and 1

    vec4 vp = vec4(0.0, 0.0, 0.0, 0.0);

    float triScale = 1.0;
    float gap = 1.0;

    if (idv2 < 0.5) {
        if (id3 < 0.50) {
            vp = vec4(0.0, 0.0, 0.0, 1.0);
        } else if (id3 < 1.5) {
            vp = vec4(1.0, 0.0, 0.0, 1.0);
        } else if (id3 < 2.5) {
            vp = vec4(0.0, 1.0, 0.0, 1.0);
        }
    } else {
        if (id3 < 0.50) {
            vp = vec4(1.0, 0.0, 0.0, 1.0);
        } else if (id3 < 1.5) {
            vp = vec4(1.0, 1.0, 0.0, 1.0);
        } else if (id3 < 2.5) {
            vp = vec4(0.0, 1.0, 0.0, 1.0);
        }
    }
    vp *= triScale;

    n = vec4(0.0, 0.0, -1.0, 0.0);
    ta = vec4(1.0, 0.0, 0.0, 0.0);


    float col = fract(idvq/cols)*cols;
    float row = floor(idvq/cols);

    vp.x += col*triScale*gap-cols*0.5*triScale;
    vp.y += row*triScale*gap-rows*0.5*triScale;

    vp.x /= cols;
    vp.y /= rows;

    tc = vec2(vp.x+0.5, vp.y+0.5);

    if (row > rows) vp *= 0.0;
    //  vp.xyz += vec3(sin(2.3*idv), cos(3.4*idv), sin(cos(idv*2.1)*1.5+idv*1.7));

    vp.w = 1.0;

    return vp;
}

float getCubeNV(float rows, float cols) {
    return (rows*cols*6.0*6.0);
}
vec4 getCube(float id, float rows, float cols, inout vec4 n, inout vec2 tc, inout vec4 ta) {
    float idc = floor(id/(rows*cols*6.0)-fract(id/(rows*cols*6.0))+0.5);
    float ids = id-idc*rows*cols*6.0; // vertex in cube side
    vec4 vp = getPlane(ids, rows, cols, n, tc, ta);
    vp.z = -0.5;

    if (idc < 0.5) {
    } else if (idc < 1.5) {
        vp = rotateXZ(vp, 0.5*3.141592);
        n = rotateXZ(n, 0.5*3.141592);
        ta = rotateXZ(ta, 0.5*3.141592);
    } else if (idc < 2.5) {
        vp = rotateXZ(vp, 3.141592);
        n = rotateXZ(n, 3.141592);
        ta = rotateXZ(ta, 3.141592);
    } else if (idc < 3.5) {
        vp = rotateXZ(vp, 1.5*3.141592);
        n = rotateXZ(n, 1.5*3.141592);
        ta = rotateXZ(ta, 1.5*3.141592);
    } else if (idc < 4.5) {
        vp = rotateYZ(vp, 0.5*3.141592);
        n = rotateYZ(n, 0.5*3.141592);
        ta = rotateYZ(ta, 0.5*3.141592);
    } else if (idc < 5.5) {
        vp = rotateYZ(vp, -0.5*3.141592);
        n = rotateYZ(n, -0.5*3.141592);
        ta = rotateYZ(ta, -0.5*3.141592);
    } else {
        vp = vec4(0.0, 0.0, 0.0, 1.0);
    }

    vp.w = 1.0;

    return vp;
}

float getBallNV(float rows, float cols) {
    return (rows*cols*6.0);
}
vec4 getBall(float id, float rows, float cols, inout vec4 n, inout vec2 tc, inout vec4 ta) {
    vec4 vp = getPlane(id, rows, cols, n, tc, ta);
    vp.x += 0.5; // 0 .. 1 range
    vp.y *= 2.0; // -1 .. 1 range
    vp.z = 0.0;

    float rad = 1.0;

    // y^2+yr^2 = rad^2
    // yr^2 = rad^2-y^2;
    float yr = sqrt(rad*rad-vp.y*vp.y);

    vec4 vpr = vec4(yr*cos(vp.x*2.0*3.141592), vp.y, yr*sin(vp.x*2.0*3.141592), 1.0);
    n.xyz = vpr.xyz;

    ta = rotateXZ(n, tc.x*2.0*3.141592);
    ta.y = 0.0;

    vpr.xyz *= 0.5;

    return vpr;
}

float getTorusNV(float rows, float cols) {
    return (rows*cols*6.0);
}
vec4 getTorus(float id, float rows, float cols, inout vec4 n, inout vec2 tc, inout vec4 ta) {
    vec4 vp = getPlane(id, rows, cols, n, tc, ta);
    vec4 vpr = vec4(0.0, cos(tc.x*2.0*3.141592), sin(tc.x*2.0*3.141592)+2.0, 1.0);
    n.xyz = vpr.xyz-vec3(0.0, 0.0, 2.0);

    vpr = rotateXZ(vpr, tc.y*2.0*3.141592);
    n = rotateXZ(n, tc.y*2.0*3.141592);

    ta = vec4(1.0, 0.0, 0.0, 0.0);
    ta = rotateXZ(ta, tc.y*2.0*3.141592);
    vpr.xyz *= 0.5*0.33333;

    return vpr;
}

float getTri(float v) {
    return sign(fract(v*0.5)-0.50)*(fract(v)-0.5)*2.0;
}

void getIK(vec2 p, float l1, float l2, inout float lza1, inout float lza2) {
    lza2 = acos((dot(p,p)-l1*l1-l2*l2)/(2.0*l1*l2));
    lza1 = -p.x*l2*sin(lza2)+p.y*(l1+l2*cos(lza2));
    lza1 = -lza1/(p.y*l2*sin(lza2)+p.x*(l1+l2*cos(lza2)));
}

vec2 getCurve(float p) {
    p *= 0.2;
    vec2 r = vec2(genCurve.y*cos(p*genCurve2.x), genCurve.z*sin(p*genCurve.w));
    r = rotateXZ(vec4(r.x, 0.0, r.y, 0.0), p).xz;

    r = genCurve2.y*vec2(0.0, p*(genCurve.y+genCurve.z))+(1.0-genCurve2.y)*r;

    return r;
}

//vec2 getCurve(float p) {
//	return vec2(0.0, p);
//}

void calcIdo(inout float id, inout float ido, inout float idoSub, inout float objMirror, float numVert, float genObs) {
    float mirror = objParams.x;
    float numVertMirror = numVert*(floor(mirror));
    float idom = floor(id/numVertMirror); // object id mirrored
    float idm = id-idom*numVertMirror; // vertex id mirrored

    ido = floor(id/numVert);
    id = id-ido*numVert;

    objMirror = floor(idm/numVert);

    float idoC = floor(idom/genObs); // object id combining all sub objects a single object consists of
    idoSub = idom-idoC*genObs;
    ido = idoC;
}

float getBodyLift(float idoo, float t) {
    return 0.5+walker2.z+walker2.w*(sin(idoo*0.58*walker3.w+t*walker3.x)*(1.0+walker3.y*cos(idoo*0.78*walker3.w+t*walker3.z)))*0.5;
}

void main() {
    vec4 vp = vec4(vertexPosition, 1.0);
    vec4 vpT = vec4(0.0);


    float id = float(gl_VertexID)+g_particleIndexOffset;
    float rows = rcObj.x;
    float cols = rcObj.y;
    float obj = rcObj.z;

    vec2 tc;
    vec4 ta;
    vec4 vpN = vec4(0.0);

    float numVert = 0.0;
    float ido = 0.0;

    float genObs = 1.0;

    float sk = 1.0;
    float skXY = 1.0;
    float skYZ = 1.0;
    vec3 pk = vec3(0.0);
    float rX = 0.0;
    float rY = 0.0;
    float rZ = 0.0;
    vec3 rc = vec3(0.0);
    vec3 ppr = vec3(0.0);

    float la1 = 0.0;
    float lza1 = 0.0;
    float lza2 = 0.0;
    float ra1 = 0.0;
    float rza1 = 0.0;
    float rza2 = 0.0;

    float idoSub = 0.0;
    float objMirror = 0.0;

    //
    if (obj < 0.5) {
        numVert = getPlaneNV(rows, cols);
        calcIdo(id, ido, idoSub, objMirror, numVert, genObs);
        vp = getPlane(id, rows, cols, vpN, tc, ta);
    } else if (obj < 1.5) {
        numVert = getCubeNV(rows, cols);
        calcIdo(id, ido, idoSub, objMirror, numVert, genObs);
        vp = getCube(id, rows, cols, vpN, tc, ta);
    } else if (obj < 2.5) {
        numVert = getBallNV(rows, cols);
        calcIdo(id, ido, idoSub, objMirror, numVert, genObs);
        vp = getBall(id, rows, cols, vpN, tc, ta);
    } else if (obj < 3.5) {
        numVert = getTorusNV(rows, cols);
        calcIdo(id, ido, idoSub, objMirror, numVert, genObs);
        vp = getTorus(id, rows, cols, vpN, tc, ta);
    } else if (obj < 7.5) { // walker
        //walker obs - 0: head, 1:body, 2:tail, 3:legLeft1, 4:legLeft2, 5:legRight1, 6:legRight2
        genObs = 7.0;
        numVert = getBallNV(rows, cols);
        calcIdo(id, ido, idoSub, objMirror, numVert, genObs);
        if (obj < 4.5) {
            vp = getBall(id, rows, cols, vpN, tc, ta);
        } else if (obj < 5.5) {
            vp = getCube(id, rows/3, cols/2, vpN, tc, ta);
        } else if (obj < 6.5) {
            vp = getPlane(id, rows, cols, vpN, tc, ta);
        } else if (obj < 7.5) {
            vp = getTorus(id, rows, cols, vpN, tc, ta);
        }
    }

    float idoo = ido;

    vec4 mys = scale;

    float scaleVar = (1.0+repRand2.z*sin(idoo*234.567));

    mys.w *= scaleVar;


    vec3 rep = vec3(0.0);

    float repx = repMov.x;
    float repz = repMov.y;
    float movx = repMov.z;
    float movz = repMov.w;

    float idor = floor(ido/repx);
    ido = ido-idor*repx;

    // repeat moves
    rep.x += ido*movx;
    rep.x -= 0.5*movx*(repx-1.0);
    rep.z += idor*movz;
    rep.z -= 0.5*movz*(repz-1.0);
    rep.z += floor(idor/max(1.0, repGroup.x))*repGroup.y;

    // repeat random moves
    // if (abs(repRand.x) > 0.001) {
    rep.x += repRand.x*rndc(vec2(ido,idor));
    // }
    // if (abs(repRand.y) > 0.001) {
    rep.y += repRand.y*rndc(vec2(ido,idor));
    // }
    // if (abs(repRand.z) > 0.001) {
    rep.z += repRand.z*rndc(vec2(ido,idor));
    // }

    vec4 myPos = pos;
  //  myPos.z += g_time;
    myPos.xyz += rep.xyz;
    float ma = myPos.z;

    // parametrize position along ma
    // circle

    // myPos.xz = vec2(cos(ma), sin(ma));

    vec2 kd = vec2(0.0, -0.01);
    float kdd = 0.01;

    if (genCurve.x < 0.5) {
        myPos.xz = vec2(myPos.x, ma);
    } else if (genCurve.x < 1.5) {
        myPos.xz = getCurve(ma);
        kd = getCurve(ma-0.01)-myPos.xz;
        vec2 kd2 = getCurve(1.01)-getCurve(1.0);
        kdd = sqrt(dot(kd2, kd2));
    }
    float legPhase = myPos.z*0.50/mys.w*kdd/0.01;
    legPhase += idoo*(0.58+walker4.x);

    float legDist = 1.50+walker.z;
    float zetor = getTri(legPhase);
    float legLen1 = 1.5+walker.x;
    float legLen2 = 1.0+walker.y;
    float legLift = 0.6+walker.w;
    float bodyLift = getBodyLift(idoo, g_time);

    float ldb = legDist;

    if (obj > 3.50) { // walker etc
        if (idoSub>2.5 && idoSub<4.5) {
            // left leg
            float puk = sqrt(bodyLift*bodyLift+legDist*legDist);
            float legLiftMin = clamp(legLen1+legLen2-puk, -1.0, 0.0);
            float ll = legLift*clamp(sin(legPhase*3.141592+3.141592), legLiftMin, 1.0);
            float kb = clamp((bodyLift-ll+legDist)/(legLen1+legLen2), 1.0, 256.0);
            vec2 xt = vec2(sqrt(zetor*zetor+ldb*ldb), bodyLift-ll);
            la1 = asin(zetor/ldb);
            //  la1 = asin(zetor*0.9);
            float ll1 = legLen1;
            float ll2 = legLen2;
            getIK(xt, legLen1*kb, legLen2*kb, lza1, lza2);
        }

        if (idoSub>4.5 && idoSub<6.5) {
            // right leg
            float puk = sqrt(bodyLift*bodyLift+legDist*legDist);
            float legLiftMin = clamp(legLen1+legLen2-puk, -1.0, 0.0);
            float ll = legLift*clamp(sin(legPhase*3.141592), legLiftMin, 1.0);
            float kb = clamp((bodyLift-ll+legDist)/(legLen1+legLen2), 1.0, 256.0);
            vec2 xt = vec2(sqrt(zetor*zetor+ldb*ldb), bodyLift-ll);
            ra1 = asin(zetor/ldb);
            //  ra1 = asin(zetor*0.9);
            //getIK(xt, legLen1, legLen2, rza1, rza2);
            float ll1 = legLen1;
            float ll2 = legLen2;
            getIK(xt, legLen1*kb, legLen2*kb, rza1, rza2);
        }

        if (idoSub<0.5) { // body
            sk = 1.5;
            float bodyLiftDelta = bodyLift-getBodyLift(idoo, g_time-0.01);
            float bodyLiftAngle = -atanSafe(bodyLiftDelta, 0.01)+0.5*3.141592;
            rX = bodyLiftAngle*0.5;
        } else if (idoSub<1.5) { // head
            sk = 0.75;
            pk = vec3(0.0, 0.5*sk, 0.5*sk);
        } else if (idoSub<2.5) { // tail
            sk = 2.0;
            skXY = 0.5/sk;
            pk = vec3(0.0, 0.0, -0.5-sk*0.5);
        } else if (idoSub<3.5) { // legLeft1
            sk = legLen1;
            skYZ = 0.1+walker2.x;
            pk = vec3(1.50, 0.0, 0.0);
            rc = vec3(-1.0, 0.0, 0.0);
            ppr = vec3(-0.50*legLen1, 0.0, 0.0);
            rY = la1;
            rZ = lza1;
        } else if (idoSub<4.5) { // legLeft2
            sk = legLen2;
            skYZ = 0.1+walker2.y;
            vec4 te = vec4(legLen1, 0.0, 0.0, 0.0);
            te = rotateXY(te, lza1);
            te = rotateXZ(te, la1);
            pk = te.xyz;
            rc = vec3(0.5, 0.0, 0.0);
            rY = la1+3.141592;
            rZ = -lza1+lza2;
        } else if (idoSub<5.5) { // legRight1
            sk = legLen1;
            skYZ = 0.1+walker2.x;
            pk = vec3(-1.5, 0.0, 0.0);
            rc = vec3(1.0, 0.0, 0.0);
            ppr = vec3(0.50*legLen1, 0.0, 0.0);
            rY = ra1;
            rZ = -rza1;
        } else if (idoSub<6.5) { // legRight2
            sk = legLen2;
            skYZ = 0.1+walker2.y;
            vec4 te = vec4(-legLen1, 0.0, 0.0, 0.0);
            te = rotateXY(te, -rza1);
            te = rotateXZ(te, ra1);
            pk = te.xyz;
            rc = vec3(-0.5, 0.0, 0.0);
            rY = ra1+3.141592;
            rZ = -(-rza1+rza2);
        }
    }

    vp.xyz += prePos.xyz;


    float scaleYRnd = 0.0;
    if (abs(repRand.w)>0.001) {
        scaleYRnd = repRand.w*rndc(vec2(ido,idor));
    }


    vp.x *= mys.x;
    vp.y *= (mys.y+scaleYRnd);
    vp.z *= mys.z;
    vp.xyz *= mys.w;

    vpN.x /= mys.x;
    vpN.y /= mys.y;
    vpN.z /= mys.z;

    ta.x /= mys.x;
    ta.y /= mys.y;
    ta.z /= mys.z;

    //  vpN.xyz += vp.xyz;
    //  ta.xyz += vp.xyz;

    ta  =  rotateYZ(ta, 3.141592*2.0*rsty_yz.x+g_time*rsty_yz.y+rsty_yz.z*cos(rsty_yz.w+idoo*0.1)*sin(vp.y*8.0+rsty_yz.w+idoo*7.13));
    vpN = rotateYZ(vpN, 3.141592*2.0*rsty_yz.x+g_time*rsty_yz.y+rsty_yz.z*cos(rsty_yz.w+idoo*0.1)*sin(vp.y*8.0+rsty_yz.w+idoo*7.13));
    vp   = rotateYZ(vp, 3.141592*2.0*rsty_yz.x+g_time*rsty_yz.y+rsty_yz.z*cos(rsty_yz.w+idoo*0.1)*sin(vp.y*8.0+rsty_yz.w+idoo*7.13));

    ta  =  rotateXZ(ta, 3.141592*2.0*rsty_xz.x+g_time*rsty_xz.y+rsty_xz.z*(1.0+sin(idoo*0.4))*cos(rsty_xz.w+idoo*0.5)*sin(vp.y*8.0+rsty_xz.w+idoo*2.1));
    vpN = rotateXZ(vpN, 3.141592*2.0*rsty_xz.x+g_time*rsty_xz.y+rsty_xz.z*(1.0+sin(idoo*0.4))*cos(rsty_xz.w+idoo*0.5)*sin(vp.y*8.0+rsty_xz.w+idoo*2.1));
    vp   = rotateXZ(vp, 3.141592*2.0*rsty_xz.x+g_time*rsty_xz.y+rsty_xz.z*(1.0+sin(idoo*0.4))*cos(rsty_xz.w+idoo*0.5)*sin(vp.y*8.0+rsty_xz.w+idoo*2.1));

    ta  =  rotateXY(ta, 3.141592*2.0*rsty_xy.x+g_time*rsty_xy.y+rsty_xy.z*(1.0+sin(idoo*0.4))*cos(rsty_xy.w+idoo*0.5)*sin(vp.y*3.0+rsty_xy.w+idoo*1.1));
    vpN = rotateXY(vpN, 3.141592*2.0*rsty_xy.x+g_time*rsty_xy.y+rsty_xy.z*(1.0+sin(idoo*0.4))*cos(rsty_xy.w+idoo*0.5)*sin(vp.y*3.0+rsty_xy.w+idoo*1.1));
    vp   = rotateXY(vp, 3.141592*2.0*rsty_xy.x+g_time*rsty_xy.y+rsty_xy.z*(1.0+sin(idoo*0.4))*cos(rsty_xy.w+idoo*0.5)*sin(vp.y*3.0+rsty_xy.w+idoo*1.1));

    // vp   = rotateXY(vp, 3.141592*2.0*rsty_xy.x+g_time*rsty_xy.y+rsty_xy.z*(1.0)*cos(rsty_xy.w)*sin(vp.y*3.0+rsty_xy.w));

    // vpN.xyz -= vp.xyz;
    // ta.xyz -= vp.xyz;

    vp.xyz -= rc*mys.w*mys.xyz;
    vp.xyz *= sk;
    vp.xyz += rc*mys.w*mys.xyz;

    vp.yz *= skYZ;
    vpN.yz *= 1.0/skYZ;
    ta.yz *= 1.0/skYZ;

    vp.xy *= skXY;
    vpN.xy *= 1.0/skXY;
    ta.xy *= 1.0/skXY;

    vpN.xyz = normalize(vpN.xyz);
    ta.xyz = normalize(ta.xyz);


    vec3 tb = cross(ta.xyz, vpN.xyz);


    if (abs(rcObj.w)>0.001) {
        vec2 tk1 = tc.xy*(g_texCoordScale.xy)*0.01+g_texCoordScale.zw*0.01;
        vec4 turbo = turbVert(tk1, 8);

        vec4 turboTA = turbVert(tk1+vec2(0.01*g_bump.y, 0.0), 8);
        vec4 turboTB = turbVert(tk1+vec2(0.0, 0.01*g_bump.y), 8);

     //   vpN.xyz += ta*(turboTA.x-turbo.x);
     //   vpN.xyz += tb*(turboTB.x-turbo.x);

        vpN.xyz = normalize(vpN.xyz);

        float vpND = 1.0;

        if (genHeight.x > 0.5) {
            vpND = clamp(turbo.x-genHeight.y, genHeight.z, genHeight.w);
        } else {
            vpND = turbo.x;
        }
        if (abs(genHeight2.x) > 0.0001) {
            vpND = pow(abs(vpND), genHeight2.x+1.0)*sign(vpND);
        }

        vp += vpN*vpND*rcObj.w;

    }



    //// flip normal to face the screen
    //vec3 ns = mul(vpN.xyz, (vec3x3)(g_mView));
    //if (ns.z < 0.0) {
    // vpN.xyz = -vpN.xyz;
    // ta.xyz = -ta.xyz;
    //}


    vp.xyz += ppr*mys.w*mys.xyz;

    if ((abs(rY)+abs(rZ)+abs(rX))>0.001) {
        vp.xyz -= rc*mys.w*mys.xyz; // *scale.xyz;
        vp = rotateYZ(vp, rX);
        vp = rotateXY(vp, rZ);
        vp = rotateXZ(vp, rY);
        vp.xyz += rc*mys.w*mys.xyz; // *scale.xyz;
    }


    vp.xyz += pk*mys.w*mys.xyz;
    // vp = rotateXZ(vp, g_time);



    //  vp = rotateXZ(vp, ma);
    // vp.xz += vec2(2.0, 8.0*sin(ma*1.0));
    float ata = atanSafe(kd.y, kd.x)+0.5*3.141592;
    vp = rotateXZ(vp, ata);
    vp.xyz += myPos.xyz;


    bodyLift = getBodyLift(idoo, g_time);
    vp.y += (scaleVar-1.0)*scale.w*0.5*0.0+(bodyLift-0.5)*1.1*scale.w;


    objMirror += objParams2.w;

    float mirrorSY = 1.0-fract(objMirror*0.5)*4.0;
    float mirrorSX = 1.0-fract(floor(objMirror*0.5)*0.5)*4.0;
    float mirrorSZ = 1.0-fract(floor(floor(objMirror*0.5)*0.5)*0.5)*4.0;
    vp.xyz -= objParams.yzw;

    vp.x *= mirrorSX;
    vp.y *= mirrorSY;
    vp.z *= mirrorSZ;
    vp.xyz += objParams.yzw;

    if (idor >= repz-0.1) vp.xyz*=0.0;

    // vp.z += 0.25*sin(idoo+g_time*4.0);

    vec4 vpVel = vec4(0.0, 0.0, 0.0, 0.0);

    // vec4 vpm = vp;
    // vpm.xyz -= objParams.yzw;
    // o.vPosWorld = vpm;

    //gl_Position = mul(vp, g_mWorldViewProjection);


//    if (id < 0.5) {
//        vp = vec4(0.0, 0.0, 0.0, 1.0);
//    } else if (id < 1.5) {
//        vp = vec4(1.0, 0.0, 0.0, 1.0);
//    } else if (id < 2.5) {
//        vp = vec4(1.0, 1.0, 0.0, 1.0);
//    }

 //   vp.xyz *= 0.0;


//    vp = getBall(id, rows, cols, vpN, tc, ta);

    gl_Position = vp;

    // o.vPosSS = o.vPosition;
    uv = tc;
    normal = vpN.xyz;

    vec3 normalResult;
    tangent = ta.xyz;

    //  o.vBiTangent = vec4(tb.x, tb.y, tb.z, 1.0);

    mirrorInfo = vec3(mirrorSX, mirrorSY, mirrorSZ);
    // o.vColor = vp; // mul(vp, g_mWorld);



 //   gl_Position = vec4(vertexPosition, 1.0);
//    origPos = gl_Position;
//    normal = vertexNormal;
//    tangent = vertexTangent;
//    uv = vertexUV;

    return;

    // o.Depth = v.Depth;

 //   return o;
}




/*
void main() {
  gl_Position = vec4(vertexPosition, 1.0);

  vec4 posse = gl_Position;
  origPos = posse;

  normal = vertexNormal;
  tangent = vertexTangent;
  uv = vertexUV;

}

*/
