//? #version 150
const int LT_DIRECTIONAL	= 0;		// A light like a sun
const int LT_POINT			= 1;		// A point light, like an explosion
const int LT_TUBE			= 2;		// A tube light, like a fluorescent light
const int LT_CONE			= 3;		// A cone light, like a flood light
const int LT_AMBIENT		= 4;		// Directionless ambient light

const float SPEC_FACTOR_NO_SPEC_MAP		= 0.1;
const float GLOW_MAP_INTENSITY			= 1.5;
const float GLOW_MAP_SRGB_MULTIPLIER	= 3.0;
const float PI = 3.14159f;


vec3 FresnelSchlick(vec3 halfVec, vec3 view, vec3 specColor)
{
	return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(view, halfVec), 0.0, 1.0), 5.0);
}

vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, float specPower, float fresnel, float dotNL)
{
	return mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnel) * ((specPower + 2.0) / 8.0 ) * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower) * dotNL;
}

float GeometrySchlickGGX(float dotAB, float k)
{
    return dotAB / (dotAB * (1.0f - k) + k);
}
vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
{
	float alpha = roughness * roughness;
	float alphaSqr = alpha * alpha;
	float dotNH = clamp(dot(normal, halfVec), 0.0f, 1.0f);
	float dotNV = clamp(dot(normal, view), 0.0f, 1.0f);

	// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.

	// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)

	// Distribution Term - Trowbridge-Reitz GGX
	
	float denom = dotNH * dotNH * (alphaSqr - 1.0f) + 1.0001f; // Extra .0001 to prevent div 0
	float distribution = alphaSqr / (PI * denom * denom);

	// Fresnel Term - Fresnel-Schlick
	vec3 fresnel = mix(specColor, FresnelSchlick(halfVec, view, specColor), fresnelFactor);

	// Geometry Term - Schlick-GGX approximation
	float r = roughness + 1.0;
	float k = r * r / 8.0f;
	// Smith's method: 
	// Microsurfaces block light rays coming in from the light 
	// AND block light rays reflecting to the camera.
	// Hence, model both separately and multiply.
	float g1vNL = GeometrySchlickGGX(dotNL, k);
	float g1vNV = GeometrySchlickGGX(dotNV, k);
	float geometry = g1vNL * g1vNV;



	vec3 specular = distribution * fresnel * geometry / (4*dotNV*dotNL + 0.0001);
	
	// Diffuse term - Lambertian, kD represents energy lost to specular reflection.
	vec3 kD = vec3(1.0)-fresnel;
	kD *= (vec3(1.0) - specColor);
	vec3 diffuse = kD * diffColor/PI;

	return (specular + diffuse) * dotNL;
}

vec3 computeLighting(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL) 
{
	#ifdef FLAG_LIGHT_MODEL_BLINN_PHONG
	return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL);
	#else
	return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL);
	#endif
}

mat3 localCoordinates(vec3 normal, vec3 tangent_in)
{
// Create basis so we can transform `view` direction into local coord system
// We're not particularly attached to any basis as we have an isotropic roughness, and don't need to align axes with x,y terms.
vec3 tangent = normalize (tangent_in - dot (tangent_in, normal) * normal);
vec3 bitangent = cross(tangent, normal);
mat3 basis = mat3(tangent, bitangent, normal);
return basis;
}