

uniform samplerBuffer u_bone_matrices;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;

in vec3 attrib_position;
in vec3 attrib_normal;
in vec2 attrib_uv;
in ivec4 attrib_bones;
in vec4 attrib_bone_weights;
in mat4 attrib_matrix;
in vec4 attrib_tint;
in vec4 attrib_highlight;
in int attrib_bone_offset;
in int attrib_tint_offset;

out vec3 v_normal;
out vec2 v_uv;
out vec4 v_tint;
out vec4 v_highlight;
out vec3 v_fragpos;
flat out int v_tint_offset;

mat4 bone_matrix(int id) {
    return mat4(
        texelFetch(u_bone_matrices, (attrib_bone_offset * 4) + (id * 4)),
        texelFetch(u_bone_matrices, (attrib_bone_offset * 4) + (id * 4) + 1),
        texelFetch(u_bone_matrices, (attrib_bone_offset * 4) + (id * 4) + 2),
        texelFetch(u_bone_matrices, (attrib_bone_offset * 4) + (id * 4) + 3)
    );
}

void main() {
    mat4 bone_matrix = bone_matrix(attrib_bones.x) * attrib_bone_weights.x
                     + bone_matrix(attrib_bones.y) * attrib_bone_weights.y
                     + bone_matrix(attrib_bones.z) * attrib_bone_weights.z
                     + bone_matrix(attrib_bones.w) * attrib_bone_weights.w;
    vec4 pos = bone_matrix * vec4(attrib_position, 1.0);
    gl_Position = (
        projection_matrix * view_matrix * attrib_matrix * pos
    );
    vec4 fpos = view_matrix * attrib_matrix * pos;
    v_fragpos = fpos.xyz / fpos.w;
    #if !defined shadow_pass
        vec4 normal = bone_matrix * vec4(attrib_normal, 0.0);
        v_normal = (transpose(inverse(attrib_matrix)) * normal).xyz;
    #endif
    v_uv = attrib_uv;
    v_highlight = attrib_highlight;
    v_tint = attrib_tint;
    v_tint_offset = attrib_tint_offset;
}
