#version 450
#extension GL_ARB_separate_shader_objects : enable

struct Bone
{
  mat4 trans;
};

layout(std140, binding = 0) uniform Transform
{
    mat4 viewProj;
    mat4 model;
    vec3 viewPos;
} transform;

layout(std140, binding = 1) uniform Skin
{
    Bone skeleton[255];
} skin;

layout(location = 0) in vec3 vPos;
layout(location = 1) in vec3 vNorm;
layout(location = 2) in vec2 vUV;
layout(location = 3) in vec3 vTan;
layout(location = 4) in vec3 vBiTan;
layout(location = 5) in uvec4 bones;
layout(location = 6) in vec4 weights;

layout(location = 0) out vec4 fVertPos;
layout(location = 1) out vec3 fTanPos;
layout(location = 2) out vec2 fUV;
layout(location = 3) out vec3 fViewPos;
layout(location = 4) out mat3 fTBN;

void main()
{
    vec4 totalPos = vec4(0.0f);

    for (uint i = 0; i < 4; ++i)
    {
        if (weights[i] == 0.0f)
            continue;

        totalPos += skin.skeleton[bones[i]].trans * vec4(vPos, 1.0f) * weights[i];
    }

    fVertPos = transform.model * totalPos;
    fUV = vUV;

    vec3 T = normalize(vec3(transform.model * vec4(vTan, 0.0f)));
    vec3 B = normalize(vec3(transform.model * vec4(vBiTan, 0.0f)));
    vec3 N = normalize(vec3(transform.model * vec4(vNorm, 0.0f)));

    T = normalize(T - dot(T, N) * N);

    fTBN = transpose(mat3(T, B, N));

    fTanPos = fTBN * fVertPos.xyz;
    fViewPos = fTBN * transform.viewPos;

    gl_Position = transform.viewProj * transform.model * totalPos;
}
