#version 120
// It was expressed that some drivers required this next line to function properly
precision highp float;
#define MAX_LIGHTS 14
in vec3 alightVec[MAX_LIGHTS];
//in vec3 aeyeVec[MAX_LIGHTS];
in vec2 texCoord;

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

uniform float xcoo;
uniform float ycoo;
in vec3 vcam;
in vec4 vcam4;
uniform float lens;
uniform float size;

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

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

//in vec3 vNormal;

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;
//uniform float invRadius;
//out vec4 gl_FragColor;


const int maxnumalights=16;
uniform float widths[maxnumalights];
uniform float heights[maxnumalights];
uniform vec3 pnormals[maxnumalights];
uniform vec3 right[maxnumalights];
///uniform float up[maxnumalights]; //calculated instead of supplied

uniform int renderingmirror;
uniform vec4 clipeq;

vec3 CalcBumpedNormal()
{
    vec3 Normal = N;
    vec3 Tangent = T;
    Tangent = normalize(Tangent - dot(Tangent, Normal) * Normal);
    //vec3 Bitangent = cross(Tangent, 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(1.0 / (gl_LightSource.constantAttenuation +
                  gl_LightSource.linearAttenuation * dist +
                  gl_LightSource.quadraticAttenuation * dist * dist));
    */
    ///return 1.0/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_=CalcBumpedNormal();

    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];//normalize(vec3(gl_ModelViewMatrix*gl_LightSource.ambient));
    vec3 pnormal = pnormals[i];//normalize(gl_LightSource.spotDirection);
    vec3 right = normalize(cross(up,pnormal));

    //width and height of the area light:
    float width = widths[i]/2.0;///1.0;
    float height = heights[i]/2.0;///4.0;

    //project onto plane and calculate direction from center to the projection.
    vec3 lightpos;
    lightpos.x=lightsPosx[i];
    lightpos.y=lightsPosy[i];
    lightpos.z=lightsPosz[i];
    vec3 projection = projectOnPlane(V,lightpos,pnormal);// projection in plane
    vec3 dir = projection-lightpos;

    //calculate distance from area:
    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);//real distance to area rectangle

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

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

    ///float nDotL = dot(pnormal,-L);
    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;

    if (nDotL > 0.0 && sideOfPlane(V,lightpos,pnormal) == 1) //looking at the plane
    {
        //shoot a ray to calculate specular:
        //vec3 R = reflect(normalize(-V),N_);


        vec3 R = reflect(normalize(camPos-V),N_);
        vec3 E = linePlaneIntersect(V,R,lightpos,pnormal);
        
        ///lightpos.z+=sin(E.x);
        ///lightpos.z+=texture2D(lightMap,vec2(E.x/6.5+0.5,1.0)).r*10.0;
        ///lightpos.z+=texture2D(lightMap,vec2(texCoord.x,1.0-1.0/256.0)).r*10.0;
        ///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;

            /// calculating z distortion and recalculating other variables accordingly:

            const float shininess=6.0; ///1.5
    	    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;
        ///adiffuse  += colordiffuse * attenuation * nDotL;
        ///adiffuse  += (colordiffuse + vec4(attenuation,attenuation,attenuation,1.0)/128.0) * nDotL;
    }

    ///ambient  += colorambient * attenuation;
	aambient=colorambient;
}

*/







/*
    //vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
    vAmbient = vec4(1.0f,1.0f,1.0f,1.0f)
               * vec4(lightsAmbientr[0],lightsAmbientg[0],lightsAmbientb[0],1.0f);

    vec3 viewDir = normalize(camPos-v);

    for (int i=0; i<MAX_LIGHTS; i++)
    {
        if (lightsEnabled[i]>0.0)
        {
            vec3 L = normalize(vec3(lightsPosx[i],lightsPosy[i],lightsPosz[i]) - v);
            vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
            vec3 R = normalize(-reflect(L,N));
            vec3 lightDir = L;//normalize(lightPos - FragPos);

            lightVec=alightVec[i];
            //eyeVec=aeyeVec[i];
            //lightVec=L; eyeVec=E;

            distSqr = dot(lightVec, lightVec);
            att = clamp(1.0 - lightsinvRadius[i] * sqrt(distSqr), 0.0, 1.0);
            //att = 1.0 - lightsinvRadius[i] * sqrt(distSqr);
            lVec = lightVec * inversesqrt(distSqr);
            //vVec = normalize(eyeVec);

            //bump = normalize( texture2D(normalMap, texCoord).xyz * 2.0f - 1.0);
            //bump = normalize(N);
            bump=CalcBumpedNormal();

            //diffuse = max( dot(lVec, bump), 0.0 );
            diffuse = clamp( dot(lVec, bump), 0.0, 1.0 );
            //	vDiffuse = gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse * diffuse *
            vDiffuse = vec4(lightsDiffuser[i],lightsDiffuseg[i],lightsDiffuseb[i],1.0f) * diffuse *
                       texture2D(lightMap, vec2(diffuse/1.02f,lightMapSelect[i]));

            //diffuse = clamp( dot(lVec, bump), 0.0, 1.0 );
            //diffuse = max(dot(N,L), 0.0);
            diffuse = max(dot(bump,L), 0.0);
            vec4 Idiff = vec4 (lightsDiffuser[i],lightsDiffuseg[i],lightsDiffuseb[i],1.0f)* diffuse*
                        texture2D(lightMap, vec2(diffuse/1.02f,lightMapSelect[i]));
            Idiff = clamp(Idiff, 0.0, 1.0);

            accvDiffuse = accvDiffuse + Idiff *att;
            //accvDiffuse = accvDiffuse + vDiffuse * att;

            //vDiffuse = gl_LightSource[i].diffuse * diffuse *
            //         texture2D(lightMap, vec2(diffuse-0.01,lightMapSelect[i]));
            //accvDiffuse = accvDiffuse + vDiffuse;

            //specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0),
            //gl_FrontMaterial.shininess );


            vec3 reflectDir=reflect(-lightDir,bump);
            const float shininess=1.5f;
            //specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0f, 1.0f), 32.0f );// * texture2D(specularMap, texCoord).r; //here shiness is replaced with 1.0, should introduce material functionality in obj loader //16.0
            specular = pow(clamp(dot(viewDir,reflectDir)*shininess,0.0f,1.0f),1.2f); //32.0f
            //specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0f, 1.0f), 32.0f );// * texture2D(specularMap, texCoord).r; //here shiness is replaced with 1.0, should introduce material functionality in obj loader //16.0
            //specular= clamp( dot(lVec, bump), 0.0, 1.0 ) * texture2D(specularMap, texCoord).r;
            //* pow(max(dot(R,E),0.0),0.3*shininess);

            //vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular * specular;
//	vSpecular = gl_LightSource[i].specular * gl_FrontMaterial.specular * specular *
            vSpecular = vec4(lightsSpecularr[i],lightsSpecularg[i],lightsSpecularb[i],1.0f)* specular *
                        texture2D(lightMap, vec2(specular-0.01,lightMapSelect[i]));


            //const float shininess=1.0f;
            //specular=pow(max(dot(normalize(reflect(-L, bump)), E), 0.0f), 32.0f );// * texture2D(specularMap, texCoord).r; //here shiness is replaced with 1.0, should introduce material functionality in obj loader //16.0
            //specular=pow(max(dot(normalize(reflect(-L, bump)), E), 0.0f), 32.0f );// * texture2D(specularMap, texCoord).r; //here shiness is replaced with 1.0, should introduce material functionality in obj loader //16.0
            //specular=max(dot(normalize(L+normalize(E)),bump),0.0f);
            //specular=pow(max(dot(R,E),0.0),0.3*shininess);
            vec4 Ispec = vec4(lightsSpecularr[i],lightsSpecularg[i],lightsSpecularb[i],1.0f) * specular *
                        texture2D(lightMap, vec2(specular/1.02f,lightMapSelect[i]));
            //* pow(max(dot(R,E),0.0),0.3*shininess);
            //* pow(max(dot(N,L),0.0),0.3*shininess);
            //* pow(max(dot(R,E),0.0),0.3*shininess);
            Ispec = clamp(Ispec, 0.0, 1.0);

            //accvSpecular = accvSpecular + vSpecular * att;
            accvSpecular = accvSpecular + Ispec * att;

            //vSpecular = gl_LightSource[i].specular * specular * texture2D(lightMap, vec2(specular-0.01,lightMapSelect[i]));
            //accvSpecular = accvSpecular + vSpecular;
        }
    }
*/
    ///gl_FragColor = ( vAmbient*base + accvDiffuse*base + accvSpecular)*glColor;
    /*
    aambient.b*=1.2;
    gl_FragColor = ( aambient*base + adiffuse*base + aspecular)*glColor;
    gl_FragColor += flash;
    */
    /*
    aambient.r/=2.5;
    aambient.g/=2.5;
    aambient.b/=2.5;
    adiffuse.r/=1.2;
    adiffuse.g/=1.2;
    adiffuse.b/=1.2;
    vec4 bubble = ( aambient*base + adiffuse*base + aspecular);
    */
    //vec2 coo=vec2(pow(vcam.x-xcoo,1.0)/1.0+xcoo,pow(vcam.y-ycoo,1.0)/1.0+ycoo);
    //vec2 coo=vec2(pow(vcam4.x/vcam4.w/2.0-0.5,1.0)/1.0,pow(vcam4.y/vcam4.w/2.0-0.5,1.0)/1.0);
    
    //vec2 coo=vec2((pow(vcam4.x/vcam4.w/2.0-0.5,lens)-xcoo)/1.4+xcoo,(pow(vcam4.y/vcam4.w/2.0-0.5,lens)-ycoo)/1.4+ycoo);
    /*
    float rx=(vcam4.x/vcam4.w/2.0-0.5)-xcoo;
    rx=pow(abs(rx),lens)*sign(rx);
    float ry=(vcam4.y/vcam4.w/2.0-0.5)-ycoo;
    ry=pow(abs(ry),lens)*sign(ry);
    vec2 coo=vec2(rx/1.15+xcoo,ry/1.15+ycoo);
    */
    float div=vcam4.w;
    float rx=(vcam4.x/div/2.0-0.5)-xcoo;
    float ry=(vcam4.y/div/2.0-0.5)-ycoo;
    float u,v;
    u=0.5+rx/(size); v=0.5+ry/(size);
    //u=0.5+rx; v=0.5+ry;
    //vec2 uv=vec2(u,v)*2.0-vec2(1.0);
    vec2 uv=vec2(rx,ry)/size;

	///uv = fragCoord.xy*2. / iResolution.xy-vec2(1.);
    

    float d=length(uv);
    float z = sqrt(1.0 - d * d);
    ///float r = atan(d, z) / 3.14159;
    float r = atan(d, z) / 2.9;
    float phi = atan(uv.y, uv.x);
    
    uv = vec2(r*cos(phi)+.5,r*sin(phi)+.5);
    vec2 coo=vec2(xcoo,ycoo)+uv*size;
    ///if (coo.x>0.0) coo.x=0.0;
    ///if (coo.x<-0.999) coo.x=-0.999;
    ///if (coo.y>0.0) coo.y=0.0;
    ///if (coo.y<-0.999) coo.y=-0.999;
    coo.x=clamp(coo.x,-1.0+1.0/1920.0,0.0-1.0/1920.0);
    coo.y=clamp(coo.y,-1.0+1.0/1080.0,0.0-1.0/1080.0);
    gl_FragColor = (texture2D(lightMap, coo)*vec4(1.0,1.0,1.0,glColor.b*1.35));
    ///gl_FragColor = (texture2D(lightMap, coo));
}

