#pragma tdm_include "tdm_transform.glsl"

// Contains common formulas for computing interaction.
// Includes: illumination model, fetching surface and light properties
// Excludes: shadows


in vec3 var_Position;
in vec4 var_Color;
in vec2 var_TexDiffuse;
in vec2 var_TexNormal;
in vec2 var_TexSpecular;
in vec4 var_TexLight;

uniform sampler2D u_normalTexture;
uniform sampler2D u_diffuseTexture;
uniform sampler2D u_specularTexture;
uniform sampler2D u_lightFalloffTexture;
uniform sampler2D u_lightProjectionTexture;
uniform samplerCube	u_lightProjectionCubemap;

uniform float	u_advanced;
uniform float	u_cubic;
uniform float	u_RGTC;
uniform vec3	u_hasTextureDNS;
uniform vec3 	u_lightOrigin;
uniform vec4 	u_viewOrigin;
uniform vec4 	u_diffuseColor;
uniform vec4 	u_specularColor;
uniform int		u_testSpecularFix;	//stgatilov #5044: for testing only!
uniform int		u_testBumpmapLightTogglingFix;  //stgatilov #4825: for testing only


// output of fetchDNS
vec3 RawN, N;

// common variables
vec3 lightDir, viewDir;     //direction to light/eye in model coords
vec3 L, V, H;               //normalized light, view and half angle vectors 
float NdotH, NdotL, NdotV;

#pragma tdm_include "tdm_bitangents.glsl"

//fetch surface normal at fragment
void fetchDNS() {
/*	if (u_hasTextureDNS[1] != 0) {
		vec4 bumpTexel = texture (u_normalTexture, var_TexNormal.st) * 2. - 1.;
		RawN = u_RGTC == 1.0
			? vec3(bumpTexel.x, bumpTexel.y, sqrt(max(1. - bumpTexel.x*bumpTexel.x - bumpTexel.y*bumpTexel.y, 0)))
			: normalize(bumpTexel.wyz);
		N = var_TangentBitangentNormalMatrix * RawN;
	}
	else {
		RawN = vec3(0, 0, 1);
		N = var_TangentBitangentNormalMatrix[2];
	}
*/
	//initialize common variables (TODO: move somewhere else?)
	lightDir = u_lightOrigin.xyz - var_Position;
	viewDir = u_viewOrigin.xyz - var_Position;
	L = normalize(lightDir);
	V = normalize(viewDir);
	H = normalize(L + V);
	calcNormals();
	NdotH = clamp(dot(N, H), 0.0, 1.0);
	NdotL = clamp(dot(N, L), 0.0, 1.0);
	NdotV = clamp(dot(N, V), 0.0, 1.0);
}

//fetch color of the light source
vec3 lightColor() {
	// compute light projection and falloff 
	vec3 lightColor;
	if (u_cubic == 1.0) {
		vec3 cubeTC = var_TexLight.xyz * 2.0 - 1.0;
		lightColor = texture(u_lightProjectionCubemap, cubeTC).rgb;
		float att = clamp(1.0 - length(cubeTC), 0.0, 1.0);
		lightColor *= att * att;
	}
	else {
		vec3 lightProjection = textureProj(u_lightProjectionTexture, var_TexLight.xyw).rgb;
		vec3 lightFalloff = texture(u_lightFalloffTexture, vec2(var_TexLight.z, 0.5)).rgb;
		lightColor = lightProjection * lightFalloff;
	}
	return lightColor;
}

//illumination model with "simple interaction" setting
vec3 simpleInteraction() {
	// compute the diffuse term    
	vec3 diffuse = texture(u_diffuseTexture, var_TexDiffuse).rgb * u_diffuseColor.rgb;

	// compute the specular term
	float specularPower = 10.0;
	float specularContribution = pow(NdotH, specularPower);
	vec3 specular = texture(u_specularTexture, var_TexSpecular).rgb * specularContribution * u_specularColor.rgb;

	// compute lighting model
	vec3 finalColor = (diffuse + specular) * NdotL * lightColor() * var_Color.rgb;

	return finalColor;
}

//illumination model with "enhanced interaction" setting
vec3 advancedInteraction() {
	vec4 fresnelParms = vec4(1.0, .23, .5, 1.0);
	vec4 fresnelParms2 = vec4(.2, .023, 120.0, 4.0);
	vec4 lightParms = vec4(.7, 1.8, 10.0, 30.0);

	vec3 diffuse = texture(u_diffuseTexture, var_TexDiffuse).rgb;

	vec3 specular = vec3(0.026);	//default value if texture not set?...
	if (dot(u_specularColor, u_specularColor) > 0.0)
		specular = texture(u_specularTexture, var_TexSpecular).rgb;

	vec3 localL = normalize(var_LightDirLocal);
	vec3 localV = normalize(var_ViewDirLocal);
	//must be done in tangent space, otherwise smoothing will suffer (see #4958)
	float NdotL = clamp(dot(RawN, localL), 0.0, 1.0);
	float NdotV = clamp(dot(RawN, localV), 0.0, 1.0);
	float NdotH = clamp(dot(RawN, normalize(localV + localL)), 0.0, 1.0);

	// fresnel part, ported from test_direct.vfp
	float fresnelTerm = pow(1.0 - NdotV, fresnelParms2.w);
	float rimLight = fresnelTerm * clamp(NdotL - 0.3, 0.0, fresnelParms.z) * lightParms.y;
	float specularPower = mix(lightParms.z, lightParms.w, specular.z);
	float specularCoeff = pow(NdotH, specularPower) * fresnelParms2.z;
	float fresnelCoeff = fresnelTerm * fresnelParms.y + fresnelParms2.y;

	vec3 specularColor = specularCoeff * fresnelCoeff * specular * (diffuse * 0.25 + vec3(0.75));
	float R2f = clamp(localL.z * 4.0, 0.0, 1.0);

	float NdotL_adjusted = NdotL;
	if (u_testBumpmapLightTogglingFix != 0) {
		//stgatilov: hacky coefficient to make lighting smooth when L is almost in surface tangent plane
		vec3 meshNormal = normalize(var_TangentBitangentNormalMatrix[2]);
		float MNdotL = dot(meshNormal, L);
		if (MNdotL < min(0.25, NdotL))
			NdotL_adjusted = mix(MNdotL, NdotL, MNdotL / 0.25);
	}
	float light = rimLight * R2f + NdotL_adjusted;

	vec3 totalColor;
	if (u_testSpecularFix != 0)
		totalColor = (specularColor * u_specularColor.rgb * R2f + diffuse * u_diffuseColor.rgb) * light * lightColor() * var_Color.rgb;
	else
		totalColor = (specularColor * R2f + diffuse) * light * u_diffuseColor.rgb * lightColor() * var_Color.rgb;

	return totalColor;
}

vec3 computeInteraction() {
	vec3 res;
	if (u_advanced == 1.0)
		res = advancedInteraction();
	else
		res = simpleInteraction();
	return res;
}
