/*===============================================================================*\
|########################   [GLSL PSX FX SHADER V1.30]    ########################|
|########################	   [BY ASMODEAN@PCSX2]	     #########################|
||																				 ||
||			  		   ,---.  .---..-.   .-.  ,---..-.   .-.					 ||
||					   | .-.\( .-._)) \_/ /   | .-' ) \_/ / 					 ||
||					   | |-' )) \  (_)   /    | `-.(_)   /  					 ||
||					   | |--'_ \ \   / _ \    | .-'  / _ \  					 ||
||					   | | ( `-'  ) / / ) \   | |   / / ) \ 					 ||
||					   /(   `----' `-' (_)-'  )\|  `-' (_)-'					 ||
||					  (__)                   (__)           					 ||
||																				 ||
||		  This program is free software; you can redistribute it and/or			 ||
||		  modify it under the terms of the GNU General Public License			 ||
||		  as published by the Free Software Foundation; either version 2		 ||
||		  of the License, or (at your option) any later version.				 ||
||																				 ||
||		  This program is distributed in the hope that it will be useful,		 ||
||		  but WITHOUT ANY WARRANTY; without even the implied warranty of		 ||
||		  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the			 ||
||		  GNU General Public License for more details.							 ||
||																				 ||
|#################################################################################|
\*===============================================================================*/
#version 330 compatibility

/*------------------------------------------------------------------------------
								[EXTENSIONS]
------------------------------------------------------------------------------*/

#extension GL_NV_gpu_shader5 : enable
#extension GL_ARB_gpu_shader5 : enable  
#extension GL_ARB_shader_precision : enable
#extension GL_ARB_conservative_depth : enable
#extension GL_ARB_uniform_buffer_object : enable
#extension GL_ARB_vertex_attrib_64bit : enable
#extension GL_NV_explicit_multisample : enable
#extension GL_ARB_shader_texture_lod : enable
#extension GL_ARB_texture_multisample : enable
#extension GL_ARB_texture_rectangle : enable
#extension GL_ARB_sample_shading : enable

precision highp int;
precision highp float;

/*------------------------------------------------------------------------------
                     [DEFINITIONS & LOCAL VARIABLES]
------------------------------------------------------------------------------*/

#define TXFAA_ENABLED 		 0	 /*Make 1 to enable 2DAA. Make 0 to enable FXAA (Default)*/
#define SPRITE_INTERPOLATION 1 	 /*Make 1 to enable 2DAA. Make 0 to enable FXAA (Default)*/

#define FXAA_PIXEL_SIZE vec2(1.0/2560.0, 1.0/1440.0)
#define MAX_LIGHTS 16
#define NUM_LIGHTS 16

uniform sampler2D Vectors;
uniform vec4 OGL2Param;
uniform vec4 OGL2Size;
uniform vec4 OGL2InvSize;

precise uniform float FXAA_SUBPIX_SHIFT = (1.0/16.0);
precise uniform float rt_w = (2560.0);
precise uniform float rt_h = (1440.0);
precise uniform float Depth;

uniform vec4 diffuse_color;
uniform vec4 specular_color;
uniform vec4 ambient_color;
uniform float shininess;
uniform vec3 LightPosition;// = vec3(0.0, 10.0, 4.0);

uniform vec2 TextureSize = FXAA_PIXEL_SIZE;
precise float dx = (1.0 / TextureSize.x);
precise float dy = (1.0 / TextureSize.y);
precise float att;

precise in int gl_VertexID;
precise in vec4 position;
precise in vec4 vertex;
precise in vec3 Normal;
precise in vec2 texCoord0;
precise in vec2 texCoord1;
precise in vec3 tangent;
precise in vec3 binormal;
precise in vec4 inputColor;

precise vec4 specularColor;
precise vec3 lightVec[MAX_LIGHTS]; 
precise vec3 lightPosition;
precise vec4 shadowCoord;

smooth out vec3 vNormal;
smooth out vec3 vLightPos;
smooth out vec2 vTexCoords;
smooth out vec4 gl_Position;
smooth out vec4 posPos;
smooth out vec3 eyeVec;
smooth out vec4 vertOutFragColor;
smooth out float nDotL;
smooth out vec3  ReflectVec;
smooth out vec3  ViewVec;
smooth out vec3 v;
smooth out vec3 N;

precise mat3 normalMatrix;
precise uniform mat4 MVP;
precise uniform mat4 ModelView;

out VertexData
{
   precise vec3 normal;
} vertexData;

float calculateAttenuation(in int i, in float dist)
{
    return(1.0 / (gl_LightSource[i].constantAttenuation +
                  gl_LightSource[i].linearAttenuation * dist +
                  gl_LightSource[i].quadraticAttenuation * dist * dist));
}

void pointLight(in int i, in vec3 normal, in vec4 pos, inout vec4 diffuse, inout vec4 specular)
{
	vec4 color = diffuse_color;
	vec4 matspec = specular_color;
	float shininess = shininess;
	vec4 lightspec = gl_LightSource[i].specular;
	vec4 lpos = gl_LightSource[i].position;
	vec4 s = pos-lpos; 
	vec4 sn = -normalize(s);

	vec3 light = sn.xyz;
	vec3 n = normalize(normal);
	vec3 r = -reflect(light, n);
	r = normalize(r);
	vec3 v = -pos.xyz;
	v = normalize(v);

	nDotL = dot(n, sn.xyz);
	if(nDotL > 0.0)
	{
		float dist = length(s);    
		float attenuation = calculateAttenuation(i, dist);

		diffuse  += color * max(0.0, nDotL) * gl_LightSource[i].diffuse * attenuation;

	  if (shininess != 0.0)
	  {
    	specular += lightspec * matspec * pow(max(0.0,dot(r, v)), shininess) * attenuation;
	  }
	}
}

void spotLight(in int i, in vec3 normal, in vec4 pos, inout vec4 diffuse, inout vec4 specular)
{
	vec4 color = diffuse_color;
	vec4 matspec = specular_color;
	float shininess = shininess;
	vec4 lightspec = gl_LightSource[i].specular;
	vec4 lpos = gl_LightSource[i].position;
	vec4 s = pos-lpos; 
	vec4 sn = -normalize(s);

	vec3 light = sn.xyz;
	vec3 n = normalize(normal);
	vec3 r = -reflect(light, n);
	r = normalize(r);
	vec3 v = -pos.xyz;
	v = normalize(v);

	float cos_outer_cone_angle = gl_LightSource[i].spotExponent;
	float cos_cur_angle = dot(-normalize(gl_LightSource[i].spotDirection), sn.xyz);
	float cos_inner_cone_angle = gl_LightSource[i].spotCosCutoff;

	float cos_inner_minus_outer_angle = cos_inner_cone_angle - cos_outer_cone_angle;
	float spot = 0.0;
	spot = clamp((cos_cur_angle - cos_outer_cone_angle) / cos_inner_minus_outer_angle, 0.0, 1.0);

	float nDotL = dot(n, sn.xyz);
	if(nDotL > 0.0)
	{
		float dist = length(s);    
		float attenuation = calculateAttenuation(i, dist);
		diffuse  += color * max(0.0, nDotL) * gl_LightSource[i].diffuse * attenuation * spot;

	  if (shininess != 0.0)
	  {
    	specular += lightspec * matspec * pow(max(0.0,dot(r, v)), shininess) * attenuation * spot;
	  }
	}
}

void doLights(in int numLights, in vec3 normal, in vec4 pos, inout vec4 diffuse, inout vec4 specular)
{
	for (int i = 0; i < numLights; i++)
	{
		if (gl_LightSource[i].spotCutoff == 180.0)
		{
			pointLight(i, normal, pos, diffuse, specular);
		} else
		{
			spotLight(i, normal, pos, diffuse, specular);
		}
    }
}

/*------------------------------------------------------------------------------
                        [MAIN() & VERTEX CODE SECTION]
------------------------------------------------------------------------------*/

void main()
{
	vTexCoords = texCoord0.st;
	gl_Position = position;
	gl_Position.z = Depth;
	vNormal = Normal;
	vertexData.normal = Normal;
	
	float VertexAccuracy = texture(Vectors, vTexCoords).a;
    vec4 displaced = vec4(position.x, position.y, VertexAccuracy, 1.0);
    gl_Position = displaced;
	
	vertexData.normal = (gl_NormalMatrix * gl_Normal);
	
	normalMatrix[0] = normalize (ModelView[0].xyz);
    normalMatrix[1] = normalize (ModelView[1].xyz);
    normalMatrix[2] = normalize (ModelView[2].xyz);
	
	v = vec3(gl_ModelViewMatrix * gl_Vertex);
	N = normalize(gl_NormalMatrix * gl_Normal);

    vNormal = gl_NormalMatrix * gl_Normal;

	precise vec4 vertexPos = ModelView * vertex;
    precise vec3 vertexEyePos = vertexPos.xyz / vertexPos.w;
	
	vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
	vec3 lightDir = vec3(gl_LightSource[0].position.xyz - vVertex);
	eyeVec = -vVertex;
	
	shadowCoord = gl_TextureMatrix[7] * gl_Vertex;
	
	
    gl_Position = gl_ModelViewProjectionMatrix * position;
	gl_Position = ftransform();
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	
	gl_FogFragCoord = gl_Position.z;
	
	vec4 pos = gl_ModelViewMatrix * gl_Vertex;
	vec4 rawpos = gl_Vertex;
	
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

	if (SPRITE_INTERPOLATION == 1)
	{
		gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
		gl_TexCoord[0] = gl_MultiTexCoord0;



	}
	else if (TXFAA_ENABLED == 1)
	{
		float x = (OGL2Size.x/2560.0)*OGL2Param.x;
		float y = (OGL2Size.y/1440.0)*OGL2Param.y;
		vec2 dg1 = vec2( x,y);
		vec2 dg2 = vec2(-x,y);
		vec2 dx  = vec2(x,0.0);
		vec2 dy  = vec2(0.0,y);
		
		gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
		gl_TexCoord[0] = gl_MultiTexCoord0;
		gl_TexCoord[1].xy = gl_TexCoord[0].xy - dy;
		gl_TexCoord[2].xy = gl_TexCoord[0].xy + dy;
		gl_TexCoord[3].xy = gl_TexCoord[0].xy - dx;
		gl_TexCoord[4].xy = gl_TexCoord[0].xy + dx;
		gl_TexCoord[5].xy = gl_TexCoord[0].xy - dg1;
		gl_TexCoord[6].xy = gl_TexCoord[0].xy + dg1;
		gl_TexCoord[1].zw = gl_TexCoord[0].xy - dg2;
		gl_TexCoord[2].zw = gl_TexCoord[0].xy + dg2;
	}
	else
	{
		gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;
		gl_TexCoord[2] = gl_TextureMatrix[2] * gl_MultiTexCoord2;
		gl_TexCoord[3] = gl_TextureMatrix[3] * gl_MultiTexCoord3;
		gl_TexCoord[4] = gl_TextureMatrix[4] * gl_MultiTexCoord4;
		gl_TexCoord[5] = gl_TextureMatrix[5] * gl_MultiTexCoord5;
		gl_TexCoord[6] = gl_TextureMatrix[6] * gl_MultiTexCoord6;
		gl_TexCoord[7] = gl_TextureMatrix[7] * gl_MultiTexCoord7;
	} 	

	precise vec2 rcpFrame = vec2(1.0/rt_w, 1.0/rt_h);
	posPos.xy = gl_MultiTexCoord0.xy;
	posPos.zw = gl_MultiTexCoord0.xy - (rcpFrame * (FXAA_SUBPIX_SHIFT));
	
	mat3 TBN_Matrix;// = mat3(tangent, binormal, gl_Normal);  
	TBN_Matrix[0] =  gl_NormalMatrix * tangent; 
	TBN_Matrix[1] =  gl_NormalMatrix * binormal; 
	TBN_Matrix[2] =  gl_NormalMatrix * gl_Normal;
	
	vec3 ecPos      = vec3 (gl_ModelViewMatrix * gl_Vertex);
    vec3 tnorm      = normalize(gl_NormalMatrix * gl_Normal);
    vec3 lightVec   = normalize(LightPosition - ecPos);
    ReflectVec      = normalize(reflect(-lightVec, tnorm));
    ViewVec         = normalize(-ecPos);
    nDotL           = (dot(lightVec, tnorm) + 1.0) * 0.5;
	
	vec4 Vertex_ModelView = gl_ModelViewMatrix * gl_Vertex; 
	eyeVec = vec3(-Vertex_ModelView) * TBN_Matrix ; 

}
