
#version 330

#define MAX_LIGHTS 2
uniform struct Light {
    int flags;
    vec4 position;
    vec4 direction;
    mat4 viewMatrix;
    vec3 colour;
    float ambient;
    sampler2D s_projTexture;
    vec3 projColour;
} u_light[MAX_LIGHTS];

#define LIGHT_FLAG_ENABLED 1
#define LIGHT_FLAG_TEXTURED 2

uniform struct Material {
    int flags;
    vec3 diffuse;
    vec3 specular;
    float specularExp;
} u_material;

#define MATERIAL_FLAG_TEXTURED 2

uniform mat4 u_projectionMatrix;
uniform mat4 u_cameraMatrix;
uniform mat4 u_objectPositionMatrix;
uniform mat4 u_meshSpaceTransform;

in vec4 a_vertexPos;
in vec4 a_vertexNormal;
in vec4 a_colour;
in vec2 a_texCoord;
in vec4 a_meshSpaceTransformOffset;

out vec4 v_colour;
out vec2 v_texCoord;
out vec4 v_light_projTexCoord[MAX_LIGHTS];

const vec4 eyePos = vec4(0, 0, 0, 1);

// p and n are camera space
void applyLight(Light light, Material surface, vec4 p, vec4 n, vec4 pWorld, out vec4 light_projTexCoord) {
    vec4 l2p = normalize(p - (u_cameraMatrix * light.position));
    vec4 p2e = normalize(eyePos - p);
    vec3 halfplane = normalize(p2e - l2p).xyz;

    float ndotl = max(0.0, -dot(n, u_cameraMatrix * light.direction));
    float ndoth = dot(n.xyz, halfplane);

    v_colour.rgb += (light.colour * a_colour.rgb * light.ambient);
    v_colour.rgb += (ndotl * light.colour * a_colour.rgb * surface.diffuse);
    if (ndoth > 0.0) {
        //FIXME: we also get specular out the back of the light
        // This looks only at position and not at the direction of the light
        // Work around it by moving the lights off-screen for now
        v_colour.rgb += pow(ndoth, surface.specularExp) * surface.specular * light.colour;
    }

    if ((light.flags & LIGHT_FLAG_TEXTURED) != 0) {
        light_projTexCoord = light.viewMatrix * vec4(pWorld.xyz, 1.0);
    }
}


void main() {

    vec4 pMesh = a_vertexPos + a_meshSpaceTransformOffset;
    pMesh = u_meshSpaceTransform * pMesh;
    pMesh -= a_meshSpaceTransformOffset;

    vec4 pWorld = u_objectPositionMatrix * pMesh;
    vec4 p = u_cameraMatrix * pWorld;

    vec4 n = u_cameraMatrix * u_objectPositionMatrix * a_vertexNormal;

    v_colour = vec4(0.0, 0.0, 0.0, a_colour.a);
    if ((u_light[0].flags & LIGHT_FLAG_ENABLED) != 0) applyLight(u_light[0], u_material, p, n, pWorld, v_light_projTexCoord[0]);
    if ((u_light[1].flags & LIGHT_FLAG_ENABLED) != 0) applyLight(u_light[1], u_material, p, n, pWorld, v_light_projTexCoord[1]);

    v_texCoord = a_texCoord;

    gl_Position = u_projectionMatrix * p;
}
