#version 440
/*	
	**Multi Domain Topology Render Shader**
	
	File Name	: RMultiDomain.frag
	Author		: Bora Yalciner
	Description	:

		Fragment Shader. Colorizes depending on the gradient
		provided.
*/

// Definitions
#define IN_POS layout(location = 0)
#define IN_NORMAL layout(location = 1)
#define IN_ELEV_REF_DOMAIN layout(location = 2)
#define IN_BARYCENTRIC layout(location = 3)

#define U_LIGHT layout(std140, binding = 1)

#define U_GRAD_EXTREMUM layout(location = 0)
#define U_GRAD_FACTOR layout(location = 1)
#define U_RENDER_MODE layout(location = 2)
#define U_ORTHO_MODE layout(location = 3)
#define U_IS_ETA layout(location = 4)

#define T_GRADIENT layout(binding = 0)
#define T_DOMAIN layout(binding = 1)
#define T_HEIGHT_REF layout(binding = 2)

#define GI_ONE_OVER_PI 0.318309f

#define RENDER_GRADIENT 0
#define RENDER_NORMALS 1
#define RENDER_DOMAINS 2

// Input
in IN_POS vec3 fPosition;
in IN_NORMAL vec3 fNormal;
in IN_ELEV_REF_DOMAIN vec3 fElevRefDomain;
in IN_BARYCENTRIC vec3 fBaryCoords;

// Output
out vec4 outColor;

// Images
// Textures
T_GRADIENT uniform sampler1D gradTex;

// Uniform Constants
U_GRAD_EXTREMUM uniform vec2 gradExtremum;
U_GRAD_FACTOR uniform vec2 texelFactorAndOffset;
U_RENDER_MODE uniform uint renderMode;
U_ORTHO_MODE uniform bool orthoMode;
U_IS_ETA uniform bool isEta;

// Uniform Buffers
U_LIGHT uniform LightBuffer
{
	vec4 direction;		// direction.w is intensity
	vec4 lightColor;	// color.a is specular power
	vec4 camPos;		// camera.w is unused
	vec4 ambientColor;	// ambientColor.a is unused
};

float edgeFactor()
{
	vec3 d = fwidth(fBaryCoords);
	vec3 a3 = smoothstep(vec3(0.0), d*0.95, fBaryCoords);
	return min(min(a3.x, a3.y), a3.z);
}

void main(void)
{
	// Cull underground water
	if(isEta && fElevRefDomain.y - fElevRefDomain.x > -0.1f) discard;

	// Directional Light
	vec3 worldEye = normalize(camPos.xyz - fPosition);
	vec3 worldLight = normalize(-direction.xyz);
	vec3 worldHalf = normalize(worldLight + worldEye);
	vec3 worldNormal = normalize(fNormal);

	// Light Factor
	float lightFactor = 0.0f;

	// Lambert Diffuse Model
	lightFactor += GI_ONE_OVER_PI * max(dot(worldNormal, worldLight), 0.0f);

	// Blinn-Phong Specular
	float specPower = 32.0f + lightColor.a * 1024.0f;
	lightFactor += pow(max(dot(worldHalf, worldNormal), 0.0f), specPower);
	
	// Calculate Gradient from Elevation
	float elev = fElevRefDomain.x;
	elev = clamp(elev, gradExtremum.x, gradExtremum.y);
	elev = (elev - gradExtremum.x) / (gradExtremum.y - gradExtremum.x);
	elev *= texelFactorAndOffset.x;
	elev += texelFactorAndOffset.y;
	vec3 gradColor = texture(gradTex, elev).rgb;

	if(texelFactorAndOffset.x == 0.0f) gradColor = vec3(1.0f);
	
	// Write Lighting
	outColor = vec4(vec3(0.0f), 1.0f);
	outColor.xyz = ambientColor.rgb;
	outColor.xyz += lightColor.xyz * direction.w * lightFactor;

	// No Lighting on ortho mode
	if(orthoMode) outColor.xyz = vec3(1.0f); // No Lighting in ortho mode

	// Bary Related

	// Choose Color
	if(renderMode == RENDER_GRADIENT) outColor.xyz *= gradColor;
	else if(renderMode == RENDER_DOMAINS) outColor.xyz *= vec3(fElevRefDomain.z);
	else if(renderMode == RENDER_NORMALS) outColor.xyz = (worldNormal + 1.0f) * 0.5f;

	// Wireframe Mode
	vec3 d = fwidth(fBaryCoords);
    vec3 a3 = smoothstep(vec3(0.0f), d*0.95f, fBaryCoords);
	float weight = min(min(a3.x, a3.y), a3.z);
	outColor.xyz = mix(vec3(0.02f), outColor.xyz, weight);
}