#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;
//layout (location=4) in vec3 vertexOrigCenter;
//layout (location=5) in vec4 vertexGenInfo;
//layout (location=6) in vec4 vertexEmitInfo;
//layout (location=7) in vec4 vertexBranchInfo;

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 normal;
out vec2 uv;
out vec3 tangent;
out vec4 origPos;
out vec3 origCenter;
out vec4 genInfo;
out vec4 emitInfo;
out vec4 branchInfo;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

uniform float g_time;

uniform float g_bright = 1.0;
uniform float g_uvScale = 1.0;


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

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

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


vec3 rotAroundAxis(vec3 vec, vec3 axis, float alpha) {
  float ca = cos(alpha);
  float sa = sin(alpha);
  float u = axis.x;
  float v = axis.y;
  float w = axis.z;
  vec3 rot;
  rot.x = u*(u*vec.x+v*vec.y+w*vec.z)*(1.0-ca)+vec.x*ca+(-w*vec.y+v*vec.z)*sa;
  rot.y = v*(u*vec.x+v*vec.y+w*vec.z)*(1.0-ca)+vec.y*ca+(w*vec.x-u*vec.z)*sa;
  rot.z = w*(u*vec.x+v*vec.y+w*vec.z)*(1.0-ca)+vec.z*ca+(-v*vec.x+u*vec.y)*sa;
  return rot;
}

// rotate vector p towards v
vec3 rotateTowardsVec(vec3 p, vec3 v) {

    float r = 1.0; // sqrt(dot(v, v));
    float t = atanSafe(v.y, v.x);
    float tz = acos(v.z/r);

    float kul = t+1.50*3.141592;
    p = rotAroundAxis(p, vec3(0.0, 0.0, 1.0), kul);
    vec3 cu = vec3(0.0, 1.0, 0.0);
    cu = rotAroundAxis(cu, vec3(0.0, 0.0, 1.0), kul);
    p = rotAroundAxis(p, cu, tz+0.250*3.141592);

    return p;
}


void main() {

    vec3 vertexPosition = up3(vertexPositionI);
    vec3 vertexNormal = up3(vertexNormalI);
    vec2 vertexUV = up2(vertexUVI);
    vec3 vertexTangent = up3(vertexTangentI);
    vec3 vertexOrigCenter = up3(vertexOrigCenterI);
    vec4 vertexGenInfo = up4(vertexGenInfoI);
    vec4 vertexEmitInfo = up4(vertexEmitInfoI);
    vec4 vertexBranchInfo = up4(vertexBranchInfoI);


    vec3 dir = normalize(vertexBranchInfo.xyz);

//    vec3 p = vertexPosition-vertexOrigCenter*1.0;
//    vec3 upVec = vec3(0.0, 0.0, 1.0);
//    float dote = dot(dir, upVec);
//    upVec = upVec-dote*dir;

//    vec3 ta = cross(dir, upVec);
//    float dotsi = dot((ta), vec3(0.0, 0.0, 1.0));
//    float ang = acos(dotsi)+3.141592*1.0;
//    p = rotAroundAxis(p, ta, ang);
//    vertexNormal = rotAroundAxis(vertexNormal, ta, ang);
//    vertexTangent = rotAroundAxis(vertexTangent, ta, ang);
//    p += vertexOrigCenter*1.0;
//    vertexPosition = p;

    vertexPosition = rotateTowardsVec(vertexPosition-vertexOrigCenter, dir)+vertexOrigCenter;
    vertexNormal = rotateTowardsVec(vertexNormal, dir);
    vertexTangent = rotateTowardsVec(vertexTangent, dir);



    gl_Position = vec4(vertexPosition, 1.0);
    origPos = gl_Position;
    normal = vertexNormal;
    uv = vertexUV;
    tangent = vertexTangent;
    origCenter = vertexOrigCenter;
    genInfo = vertexGenInfo;
    genInfo.x = genInfo.x+g_bright;
    branchInfo = vertexBranchInfo;
    emitInfo = vertexEmitInfo;


}
