



#version 120

precision highp float;
#define MAX_LIGHTS 14
in vec3 alightVec[MAX_LIGHTS];

in vec2 texCoord;

in vec3 v;
in vec3 N;
in vec3 T;
in vec3 B;

uniform vec4 flash;
uniform vec4 glColor;
uniform vec3 camPos;

uniform float lightsPosx[MAX_LIGHTS];
uniform float lightsPosy[MAX_LIGHTS];
uniform float lightsPosz[MAX_LIGHTS];



uniform float lightsEnabled[MAX_LIGHTS];
uniform float lightsinvRadius[MAX_LIGHTS];
uniform float lightMapSelect[MAX_LIGHTS];


uniform float lightsAmbientr[MAX_LIGHTS];
uniform float lightsAmbientg[MAX_LIGHTS];
uniform float lightsAmbientb[MAX_LIGHTS];

uniform float lightsDiffuser[MAX_LIGHTS];
uniform float lightsDiffuseg[MAX_LIGHTS];
uniform float lightsDiffuseb[MAX_LIGHTS];

uniform float lightsSpecularr[MAX_LIGHTS];
uniform float lightsSpecularg[MAX_LIGHTS];
uniform float lightsSpecularb[MAX_LIGHTS];



uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform sampler2D lightMap;
uniform sampler2D specularMap;




const int maxnumalights=16;
uniform float widths[maxnumalights];
uniform float heights[maxnumalights];
uniform vec3 pnormals[maxnumalights];
uniform vec3 right[maxnumalights];


uniform int renderingmirror;
uniform vec4 clipeq;

vec3 CalcBumpedNormal()
{
    vec3 Normal = N;
    vec3 Tangent = T;
    Tangent = normalize(Tangent - dot(Tangent, Normal) * Normal);
    
    vec3 Bitangent = B;
    vec3 BumpMapNormal = texture2D(normalMap, texCoord).xyz;
    BumpMapNormal = 2.0 * BumpMapNormal - vec3(1.0, 1.0, 1.0);
    vec3 NewNormal;
    mat3 TBN = mat3(Tangent, Bitangent, Normal);
    NewNormal = TBN * BumpMapNormal;
    NewNormal = normalize(NewNormal);
    return NewNormal;
}




vec3 projectOnPlane(in vec3 p, in vec3 pc, in vec3 pn)
{
    float distance = dot(pn, p-pc);
    return p - distance*pn;
}
int sideOfPlane(in vec3 p, in vec3 pc, in vec3 pn){
   if (dot(p-pc,pn)>=0.0) return 1; else return 0;
}
vec3 linePlaneIntersect(in vec3 lp, in vec3 lv, in vec3 pc, in vec3 pn){
   return lp+lv*(dot(pn,pc-lp)/dot(pn,lv));
}

float calculateAttenuation(in int i, in float dist)
{
    
    
    return clamp(1.0 - lightsinvRadius[i] * sqrt(dist), 0.0, 1.0);
}










void main (void)
{

    vec3 lightVec;
    vec3 eyeVec;
    vec4 accvDiffuse = vec4(0.0);
    vec4 accvSpecular = vec4(0.0);
    float distSqr;
    vec3 lVec;
    vec3 vVec;
    float att;
    vec4 base;
    vec4 vAmbient;
    vec3 bump;
    float diffuse;
    vec4 vDiffuse;
    vec4 vSpecular;
    float specular;
    vec3 nrmltexture;
    vec3 V=v;
    
    vec3 N_=-N; 

    base = texture2D(colorMap, texCoord);




    if (renderingmirror>0 && dot(clipeq, vec4(v,1.0)) < 0)
    {
        discard;
    }




vec4 aambient=vec4(0,0,0,0);
vec4 adiffuse=vec4(0,0,0,0);
vec4 aspecular=vec4(0,0,0,0);

for (int i=0;i<maxnumalights-2;i++)
    if (lightsEnabled[i]>0.0)
{



    vec3 up = right[i];
    vec3 pnormal = pnormals[i];
    vec3 right = normalize(cross(up,-pnormal));

    
    float width = widths[i]/2.0;
    float height = heights[i]/2.0;

    
    vec3 lightpos;
    lightpos.x=lightsPosx[i];
    lightpos.y=lightsPosy[i];
    lightpos.z=lightsPosz[i];
    vec3 projection = projectOnPlane(V,lightpos,pnormal);
    vec3 dir = projection-lightpos;

    
    vec2 diagonal = vec2(dot(dir,right),dot(dir,up));
    vec2 nearest2D = vec2(clamp(diagonal.x,-width,width),clamp(diagonal.y,-height,height));
    vec3 nearestPointInside = lightpos+(right*nearest2D.x+up*nearest2D.y);

    float dist = distance(V,nearestPointInside);

    vec3 L = normalize(nearestPointInside - V);
    float attenuation = calculateAttenuation(i, dist);

    
    
    attenuation*=clamp(0.3+pow(dot(normalize(nearestPointInside-V),N_),0.3),0.0,1.0);
    
    

    
    float nDotL = dot(N_,L);

vec4 colorambient, colordiffuse, colorspecular;
    colorambient.r=lightsAmbientr[i];
    colorambient.g=lightsAmbientg[i];
    colorambient.b=lightsAmbientb[i];
    colorambient.a=1.0;
    colordiffuse.r=lightsDiffuser[i];
    colordiffuse.g=lightsDiffuseg[i];
    colordiffuse.b=lightsDiffuseb[i];
    colordiffuse.a=1.0;
    colorspecular.r=lightsSpecularr[i];
    colorspecular.g=lightsSpecularg[i];
    colorspecular.b=lightsSpecularb[i];
    colorspecular.a=1.0;

    
    {
        
        


        vec3 R = reflect(normalize(camPos-V),N_);
        vec3 E = linePlaneIntersect(V,R,lightpos,pnormal);
        
        
        
        
        


        float specAngle = dot(R,pnormal);
        if (specAngle > 0.0){
	    vec3 dirSpec = E-lightpos;
	    const float scale=1.0;
    	    vec2 dirSpec2D = vec2(dot(dirSpec,right),dot(dirSpec,up));
            vec2 nearestSpec2D = vec2(clamp( dirSpec2D.x,-width,width  ),clamp(  dirSpec2D.y,-height,height))/scale;

            
            



            const float shininess=6.0; 
    	    float specFactor = 1.0-clamp(length(nearestSpec2D-dirSpec2D)*shininess,0.0,1.0);
            float specattenuation=texture2D(specularMap,
                                   vec2(
                                        i/16.0f+1.0/16.0-((nearestSpec2D.x+width)/2.0/width)*scale/16.0f,
                                        -(nearestSpec2D.y+height)/2.0/height*scale
                                        )
                                   ).b;
          aspecular += colorspecular * specattenuation * specFactor * specAngle;
        }
        adiffuse  += colordiffuse * attenuation * nDotL;
        
        
    }

    
	aambient=colorambient;
}















































    

    aambient.b*=1.2;
    gl_FragColor = ( aambient*base + adiffuse*base + aspecular)*glColor;
    gl_FragColor += flash;

    

    
    
    
}











