#version 430

layout (location=0) in uvec2 vertexPositionI;
layout (location=1) in uvec2 vertexNormalI;
layout (location=2) in uint vertexUVI;
layout (location=3) in uvec2 vertexTangentI;
layout (location=4) in uvec2 vertexOrigCenterI;
layout (location=5) in uvec2 vertexGenInfoI; // x: bright, y: age since birth
layout (location=6) in uvec2 vertexEmitInfoI; // x: birth time (root is 0.0), y: emit time counter, z: emit type being 0.0 = main branch & > 1.0 side branch, w: number of times processed with emit
layout (location=7) in uvec2 vertexBranchInfoI; // xyz: branch main dir, w: branch time counter

out vec3 position;
out vec3 normal;
out vec2 uv;
out vec3 tangent;
out vec4 origCenter;
out vec4 genInfo;
out vec4 emitInfo;
out vec4 branchInfo;

uniform float g_time;
uniform float g_timeStep=0.0;
uniform float g_emit = 1.0;
uniform float g_uvScale = 1.0;
uniform float g_bright = 1.0;

uniform float g_zoomAmount = 1.03;

uniform mat4 modelMatrix;

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

uniform vec4 g_zoomAcc;
uniform vec4 g_zoomRot;

uniform float g_zoomRotMax=0.0;


vec3 movePos(vec3 p, vec3 oc, vec4 bi, vec4 ei) {
    //  float d = dot(oc, oc);
    //  return p*pow(1.03, g_timeStep/0.05)+vec3(0.0, 1.0*sin(sqrt(d)*0.5), 0.0);
    // return p*pow(g_zoomAmount, g_timeStep/0.05); // +vec3(0.0, 1.0*sin(sqrt(d)*0.5), 0.0);

    //  p-=oc;
    //  p.z+=1.01*pow(0.1, g_timeStep/0.05);

      p.xyz += (ei.w*g_timeStep*g_zoomAcc.xyz)*g_zoomAcc.a;

      float zorro = clamp(ei.w, 0.0, g_zoomRotMax);
      p.xyz = rotateXZ3(p.xyz, (zorro*g_timeStep*g_zoomRot.y*0.01)*g_zoomAcc.a);
      p.xzy = rotateXZ3(p.xzy, (zorro*g_timeStep*g_zoomRot.z*0.01)*g_zoomAcc.a);
      p.zxy = rotateXZ3(p.zxy, (zorro*g_timeStep*g_zoomRot.x*0.01)*g_zoomAcc.a);
    // p+=oc;

  //    return p*pow(g_zoomAmount, g_timeStep/0.05)+(g_zoomAmount-1.0)/0.07*vec3(0.0, 1.0*(1.0+sqrt(d)*0.001)*sin(log(d)*2.0), 0.0);

    return p*pow(g_zoomAmount, g_timeStep/0.05);
}

vec3 doRot(vec3 p, vec3 oc, vec4 bi) {
    //    float d = sqrt(dot(p, p));
    //d = abs(oc.x)*10.0;
    //  p-=oc;


    //    p.x*=pow(1.0+0.05*(g_zoomAmount-1.0)/0.07, g_timeStep/0.05);
    //    p.y*=pow(1.0-0.01*(g_zoomAmount-1.0)/0.07, g_timeStep/0.05);
    //    p.z*=pow(1.0-0.01*(g_zoomAmount-1.0)/0.07, g_timeStep/0.05);
    //  //  p+=oc;
    //    p = rotateXZ3(p.xzy, (g_zoomAmount-1.0)/0.07*g_timeStep*15.50*sin(d*0.01)).xzy;
    // p = rotateXZ3(p.xyz, g_timeStep*0.250*sin(d*0.15)).xyz;

    //  p = rotateXZ3(p, bi.x);

    return p;
}

vec4 up4(uvec2 v) {
    vec4 r;
    r.xy = unpackHalf2x16(v.x);
    r.zw = unpackHalf2x16(v.y);
    return r;
}
vec3 up3(uvec2 v) {
    return up4(v).xyz;
}
vec2 up2(uint v) {
    return unpackHalf2x16(v);
}

uint p2(vec2 v) {
    return packHalf2x16(v);
}
uvec2 p4(vec4 v) {
    uvec2 r;
    r.x = packHalf2x16(v.xy);
    r.y = packHalf2x16(v.zw);
    return r;
}
uvec2 p3(vec3 v) {
    uvec2 r;
    r.x = packHalf2x16(v.xy);
    r.y = packHalf2x16(vec2(v.z, 0.0));
    return r;
}

void main() {

    position = up3(vertexPositionI);
    normal  = up3(vertexNormalI);
    uv = up2(vertexUVI);
    tangent = up3(vertexTangentI);
    origCenter = up4(vertexOrigCenterI);
    genInfo = up4(vertexGenInfoI);
    branchInfo = up4(vertexBranchInfoI);
    emitInfo = up4(vertexEmitInfoI);

    gl_Position = vec4(position, 1.0);

    if (g_emit < 0.5) {
        position = movePos(position, origCenter.xyz, branchInfo, emitInfo);
        origCenter.xyz = movePos(origCenter.xyz, origCenter.xyz, branchInfo, emitInfo);
        position -= origCenter.xyz;
        position = doRot(position, origCenter.xyz, branchInfo);
        normal = doRot(normal, origCenter.xyz, branchInfo);
        tangent = doRot(tangent, origCenter.xyz, branchInfo);
        position += origCenter.xyz;
    } else {
        // emit a new
        //  position = vertexPosition+vec3(0.1, 0.0, 0.0);
        position = (modelMatrix*vec4(position, 1.0)).xyz;
        origCenter.xyz = (modelMatrix*vec4(0.0, 0.0, 0.0, 1.0)).xyz;
        origCenter.w = 0.0;
        emitInfo = vec4(0.0);
        genInfo = vec4(0.0);
        genInfo.x = g_bright;
        uv = vec2(position.x*1.1+position.z*0.05, position.x*0.1+position.z*1.07+position.y*0.23)*g_uvScale;
        branchInfo = vec4(0.0);
        branchInfo.xyz = vec3(0.0, 1.0, 0.0); // grow main dir
    }

}

