#version 330

uniform mat4 WorldView;
uniform vec4 BaseColor;
uniform float Diffuse;
uniform vec4 Ambient;
uniform vec4 Specular;
uniform float SpecularPower;
uniform float Reflect;
uniform vec4 Emissive;
uniform bool Blinn;
uniform vec3 GlobalAmbient;
uniform vec4 BackFaceColor;
uniform int LightNum;
uniform vec4 LightPos[4];
uniform vec3 LightCol[4];
uniform vec3 LightSpc[4];
uniform vec3 ViewDir;
uniform vec3 CameraPos;
uniform int ClipPlaneNum;
uniform vec4 ClipPlane[4];

in vec3 VSWorldPos;
in vec4 VSColor;
in vec3 VSNormal;
in vec2 VSTexCoord;

out vec4 OutColor;

float PI = 3.141592653589793;
vec3 mul(vec3 v, mat3 m) { return m * v; }
float saturate(float v) { return clamp(v, 0, 1); }
vec2 saturate(vec2 v) { return clamp(v, 0, 1); }
vec3 saturate(vec3 v) { return clamp(v, 0, 1); }
vec4 saturate(vec4 v) { return clamp(v, 0, 1); }
vec3 lerp(vec3 x, vec3 y, float a) { return mix(x, y, a); }
float atan2(float y, float x) { return x == 0.0 ? sign(y)*PI/2 : atan(y, x); }


vec2 dirToUV(vec3 dir)
{
	return vec2(
		atan2(dir.z, dir.x) / (PI*2),
		acos(dir.y) / PI);
}

vec4 LINEARtoSRGB(vec4 srgbIn, bool is_srgb)
{
	if(is_srgb){
		vec3 linOut = pow(abs(srgbIn.xyz),vec3(1.0/2.2,1.0/2.2,1.0/2.2));
		return vec4(linOut,srgbIn.w);
	}else{
		return srgbIn;
	}
}

float GetSpecular(vec3 V, vec3 nv, vec3 light_dir)
{
	if(Blinn){
		vec3 Reflect = normalize(V + light_dir);
		return pow(saturate(dot(Reflect, nv)), SpecularPower);
	}else{
		vec3 Reflect = normalize(2 * dot(nv, light_dir) * nv - light_dir);
		return pow(saturate(dot(Reflect, V)), SpecularPower);
	}
}

// phong without texture
void main(void)
{
	for(int i=0; i<ClipPlaneNum; i++){
		if(dot(ClipPlane[i].xyz, VSWorldPos) + ClipPlane[i].w < 0)
			discard;
	}
	vec3 V = normalize(CameraPos - VSWorldPos);
	vec4 col = VSColor;
	if(col.w < 0.01)
		discard;

	vec3 nv = normalize(VSNormal);
	if(gl_FrontFacing){
		col.xyz *= BackFaceColor.xyz;
		nv = -nv;
	}
	vec3 dif = vec3(0,0,0);
	vec3 spc = vec3(0,0,0);
	for(int i=0; i<4 && i<LightNum; i++){
		vec3 light_dir;
		if(LightPos[i].w == 0){
			light_dir = normalize(LightPos[i].xyz - VSWorldPos); // point light
		}else{
			light_dir = LightPos[i].xyz; // directional light
		}
		dif += LightCol[i] * saturate(dot(nv, light_dir));
		spc += LightSpc[i] * GetSpecular(V, nv, light_dir);
	}
	col.xyz = GlobalAmbient * Ambient.xyz + col.xyz * (Emissive.xyz + Diffuse * dif) + Specular.xyz * spc;

	OutColor = saturate(col);
}

