// Author: Nikolai V. Chr.
// License: GPL v2
#version 120

varying vec3    VNormal;
varying vec3    eyeVec;

uniform sampler2D BaseTex;
uniform sampler2D dust_texture;
uniform float dirt_factor;
uniform float innerAngle;//inside this angle the display is perfect
uniform float outerAngle;//from inner to outer the display gets more color distorted.
uniform float blackAngle;//from outer to this angle the display gets more black. From this angle to 90 the display stays black.
uniform float contrast;//0.0001 - 255.0, 1.0 is normal
uniform int use_als;
uniform int use_filters;

const vec4  kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const vec4  kRGBToI     = vec4 (0.596, -0.275, -0.321, 0.0);
const vec4  kRGBToQ     = vec4 (0.212, -0.523, 0.311, 0.0);

const vec4  kYIQToR   = vec4 (1.0, 0.956, 0.621, 0.0);
const vec4  kYIQToG   = vec4 (1.0, -0.272, -0.647, 0.0);
const vec4  kYIQToB   = vec4 (1.0, -1.107, 1.704, 0.0);

vec3 filter_combined (in vec3 color) ;

vec3 rotateHue (in vec4 color) {
    // Convert to YIQ
    float   YPrime  = dot (color, kRGBToYPrime);
    float   I      = dot (color, kRGBToI);
    float   Q      = dot (color, kRGBToQ);

    // Calculate the hue and chroma
    float   hue     = atan (Q, I);
    float   chroma  = sqrt (I * I + Q * Q);

    // Make the adjustment
    hue += radians(180.0);
    YPrime = 1.0 - YPrime;

    // Convert back to YIQ
    Q = chroma * sin (hue);
    I = chroma * cos (hue);

    // Convert back to RGB
    vec4    yIQ   = vec4 (YPrime, I, Q, 0.0);
    color.r = dot (yIQ, kYIQToR);
    color.g = dot (yIQ, kYIQToG);
    color.b = dot (yIQ, kYIQToB);

    // reduce contrast by alot
    color.rgb = ((color.rgb - 0.5) * 0.1) + 0.5;
    return color.rgb;
}

// todo: rembrandt and stuff

void main (void) {
    vec3 gamma      = vec3(1.0/2.2);// standard monitor gamma correction
    vec3 gammaInv   = vec3(2.2);
    vec4 texel      = texture2D(BaseTex, gl_TexCoord[0].st);    

    vec3 eye = normalize(-eyeVec);
    vec3 N  = normalize(VNormal);
    float angle = degrees(acos(dot(N,eye)));//angle between normal and viewer
    vec3 color = vec3(0.0,0.0,0.0);
    if (angle <= innerAngle) {
        color = texel.rgb;
    } else if (angle <= outerAngle) {
        vec3 hsl = rotateHue(texel);
        float amount = (angle - innerAngle)/(outerAngle-innerAngle);
        color = mix(texel.rgb, hsl, amount);
    } else if (angle <= blackAngle) {
        vec3 hsl = rotateHue(texel);
        float amount = (angle - outerAngle)/(blackAngle-outerAngle);
        color = mix(hsl, vec3(0,0,0), amount);
    }

    // apply contrast
    color.rgb = ((color.rgb - 0.5) * contrast) + 0.5;

    color = pow(color, gammaInv);
    color = color * gl_FrontMaterial.emission.rgb;

    float phong = 0.0;
    vec3 Lphong = normalize(gl_LightSource[0].position.xyz);
    if (dot(N, Lphong) > 0.0) {
        // lightsource is not behind
        vec3 Rphong = normalize(-reflect(Lphong,N));
        phong = pow(max(dot(Rphong,eye),0.0),gl_FrontMaterial.shininess);
        phong = clamp(phong, 0.0, 1.0);
    }
    vec4 specular = gl_FrontMaterial.specular * gl_LightSource[0].diffuse * phong;
    vec3 ambient = gl_FrontMaterial.ambient.rgb * gl_LightSource[0].ambient.rgb * gl_LightSource[0].ambient.rgb * 2.0;//hack but works, pitch black at night. :)

    vec3 L = normalize((gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz);
    N = normalize((gl_ModelViewMatrixTranspose * vec4(N,0.0)).xyz);
    float nDotVP = dot(N,L);
    nDotVP = max(0.0, nDotVP);
    vec3 diffuse = gl_FrontMaterial.diffuse.rgb * gl_LightSource[0].diffuse.rgb * nDotVP;

    color = clamp(color+specular.rgb+ambient, 0.0, 1.0); // +diffuse broken on non-NVIDIA

    vec4 dustTexel = texture2D(dust_texture, gl_TexCoord[0].st);
    dustTexel.rgb *= gl_LightSource[0].diffuse.rgb * nDotVP;
    dustTexel.a = clamp(dustTexel.a * dirt_factor * (1.0 - 0.4 * max(0.0,dot(normalize(VNormal), Lphong)))*(length(vec3(1.0))/1.76),0.0,1.0); 
    color.rgb =  mix(color.rgb, dustTexel.rgb,  dustTexel.a );
    //color.a = max(color.a, dustTexel.a);
    texel.a = max(texel.a, dustTexel.a);
    if (use_als > 0 && use_filters > 0) {
        gl_FragColor = vec4(filter_combined(pow(color,gamma)), texel.a);
    } else {
        gl_FragColor = vec4(pow(color,gamma), texel.a);
    }
}