#version 330

layout (location = 0) in vec4 in_Vertex;
layout (location = 1) in vec2 in_texCoord;
layout (location = 2) in vec3 in_Offset;
layout (location = 3) in vec3 in_Angle;

uniform mat4 modelviewProjection;

out vec2 texCoord;
flat out float texIndex;

// https://fr.wikipedia.org/wiki/Matrice_de_rotation#En_dimension_trois
// https://fr.wikipedia.org/wiki/Angles_d%27Euler

mat4 rotateX(float _angle) // why not angle ? // C, theta
{
    mat4 rot;
    rot[0] = vec4(1, 0, 0, 0);
    rot[1] = vec4(0, cos(_angle), -sin(_angle), 0);
    rot[2] = vec4(0, sin(_angle), cos(_angle), 0);
    rot[3] = vec4(0, 0, 0, 1);

    return rot;
}

mat4 rotateY(float _angle) // D, phi
{
    mat4 rot;
    rot[0] = vec4(cos(_angle), 0, sin(_angle), 0);
    rot[1] = vec4(0, 1, 0, 0);
    rot[2] = vec4(-sin(_angle), 0, cos(_angle), 0);

    /*rot[0] = vec4(cos(_angle), -sin(_angle), 0, 0);
    rot[1] = vec4(sin(_angle), cos(_angle), 0, 0);
    rot[2] = vec4(0, 0, 1, 0);*/

    rot[3] = vec4(0, 0, 0, 1);

    return rot;
}

mat4 rotateZ(float _angle) // B, roll
{
    mat4 rot;
    rot[0] = vec4(cos(_angle), -sin(_angle), 0, 0);
    rot[1] = vec4(sin(_angle), cos(_angle), 0, 0);
    rot[2] = vec4(0, 0, 1, 0);
    rot[3] = vec4(0, 0, 0, 1);

    return rot;
}

mat4 transpose(mat4 _mat)
{
    mat4 res;
    res[0] = vec4(_mat[0][0], _mat[1][0], _mat[2][0], _mat[3][0]);
    res[1] = vec4(_mat[0][1], _mat[1][1], _mat[2][1], _mat[3][1]);
    res[2] = vec4(_mat[0][2], _mat[1][2], _mat[2][2], _mat[3][2]);
    res[3] = vec4(_mat[0][3], _mat[1][3], _mat[2][3], _mat[3][3]);
    return res;
}

mat4 rotate(vec3 _angles)
{
    // bien en radians
    float theta = _angles.x, phi = _angles.y, roll = _angles.z, // sure ?
          cosTheta = cos(theta), sinTheta = sin(theta),
          cosPhi = cos(phi), sinPhi = sin(phi),
          cosRoll = cos(roll), sinRoll = sin(roll);
    mat4 rot;

    rot[0] = vec4(cosRoll * cosPhi - sinRoll * cosTheta * sinPhi,
                  -cosRoll * sinPhi - sinRoll * cosTheta * cosPhi,
                  sinRoll * sinTheta,
                  0);

    rot[1] = vec4(sinRoll * cosPhi + cosRoll * cosTheta * sinPhi,
                  -sinRoll * sinPhi + cosRoll * cosTheta * cosPhi,
                  -cosRoll * sinTheta,
                  0);

    rot[2] = vec4(sinTheta * sinPhi,
                  sinTheta * cosPhi,
                  cosTheta,
                  0);

    rot[3] = vec4(0, 0, 0, 1);


    return rot;
}

/*
xyz-bruh
xzy-bof
yzx-doesn't seem different from betterBetter
yxz-betterBetter
zxy-bad(original one)
zyx-better
*/

void main()
{
    //First rotate in_Vertex
    //mat4 Rot = /*rotate(in_Angle)*/rotateZ(in_Angle.z) * rotateX(in_Angle.x) * rotateY(in_Angle.y); // rotation matrix aren't commutative in 3D // used to reverse x and z

    mat4 Rot = rotateZ(in_Angle.z) * rotateY(in_Angle.y) * rotateX(in_Angle.x);//rotateY(in_Angle.y) * rotateZ(in_Angle.z) * rotateX(in_Angle.x);
    vec4 vertR = Rot * vec4(vec3(in_Vertex.x, in_Vertex.y, in_Vertex.z), 1.0);
    //vec4 vertR = vec4(in_Vertex, 1.0);

    //Then translate it with offset
    vec4 vertT = vertR + vec4(in_Offset, 0.0);

    gl_Position = modelviewProjection * vertT;
    texCoord = in_texCoord;
    texIndex = in_Vertex.w;
}