#version 330

uniform mat4 WorldView;
uniform vec4 BaseColor;
uniform float Diffuse;
uniform vec4 Ambient;
uniform vec4 Specular;
uniform float SpecularPower;
//uniform vec4 Emissive;
//uniform bool Blinn;
uniform int LightNum;
uniform vec4 LightPos[4];
uniform vec3 LightCol[4];
uniform vec3 LightSpc[4];
uniform vec4 BackFaceColor;
uniform vec3 ViewDir;
uniform int ClipPlaneNum;
uniform vec4 ClipPlane[4];
uniform int HasTextureMap;
uniform int Toon;
uniform bool Edge;

uniform sampler2D ColorMapSampler;
uniform sampler2D AlphaMapSampler;

in vec4 GSWorldPos;
in vec4 GSColor;
in vec3 GSNormal;
in vec2 GSTexCoord;

out vec4 OutColor;

#define float3 vec3
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); }

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;
	}
}

float3 GetDiffuse(float3 nv, float3 light_dir)
{
	float dif = dot(nv, light_dir);
	float t;
	switch(Toon){
	case 1:
		if(dif > 0.065)
			return float3(1.0,1.0,1.0);
		else if(dif < -0.065)
			return float3(0.8,0.8,0.8);
		t = (dif+0.065)/(0.065+0.065);
		return float3(
			1.0*t + 0.8*(1-t),
			1.0*t + 0.8*(1-t),
			1.0*t + 0.8*(1-t));
	case 2:
		if(dif > 0.065)
			return float3(1.0,1.0,1.0);
		else if(dif < -0.065)
			return float3(0.96,0.88,0.88);
		t = (dif+0.065)/(0.065+0.065);
		return float3(
			1.0*t + 0.96*(1-t),
			1.0*t + 0.88*(1-t),
			1.0*t + 0.88*(1-t));
	case 3:
		if(dif > 0.065)
			return float3(1.0,1.0,1.0);
		else if(dif < -0.065)
			return float3(0.60,0.60,0.60);
		t = (dif+0.065)/(0.065+0.065);
		return float3(
			1.0*t + 0.60*(1-t),
			1.0*t + 0.60*(1-t),
			1.0*t + 0.60*(1-t));
	case 4:
		if(dif > 0.065)
			return float3(1.0,1.0,1.0);
		else if(dif < -0.065)
			return float3(0.97,0.94,0.92);
		t = (dif+0.065)/(0.065+0.065);
		return float3(
			1.0*t + 0.97*(1-t),
			1.0*t + 0.94*(1-t),
			1.0*t + 0.92*(1-t));
	case 5:
		if(dif > -0.10) return float3(1.0,1.0,1.0);
		if(dif < -0.38) return float3(1,0.90,0.87);
		t = (dif+0.38)/(-0.10+0.38);
		return float3(
			1.0,
			1.0*t + 0.90*(1-t),
			1.0*t + 0.87*(1-t));
	case 6:
		if(0.52 < dif && dif < 0.64){
			t = abs((dif-0.58)/0.06);
			return float3(
				1.0,
				1.0*(1-t) + 0.93*t,
				1.0*(1-t) + 0.38*t);
		}
		if(dif > -0.33) return float3(1.00,0.93,0.38);
		if(dif < -0.60) return float3(0.77,0.68,0.02);
		t = (dif+0.60)/(-0.33+0.60);
		return float3(
			1.00*t + 0.77*(1-t),
			0.93*t + 0.68*(1-t),
			0.38*t + 0.02*(1-t));
	default:
		if(dif > 0.065)
			return float3(1,1,1);
		else if(dif < -0.065)
			return float3(0,0,0);
		t = (dif+0.065)/(0.065+0.065);
		return float3(t,t,t);
	}
}

float GetSpecular(vec3 nv, vec3 light_dir)
{
	vec3 Reflect = normalize(2 * dot(nv, light_dir) * nv - light_dir);
	return pow(saturate(dot(Reflect, ViewDir)), SpecularPower);
}

void main(void)
{
	for(int i=0; i<ClipPlaneNum; i++){
		if(dot(ClipPlane[i].xyz, GSWorldPos.xyz) + ClipPlane[i].w < 0)
			discard;
	}

	if(GSWorldPos.w == 0 && gl_FrontFacing)
		discard;

	vec4 base_color = GSColor;
	vec4 tex_col = LINEARtoSRGB(texture(ColorMapSampler, GSTexCoord), (HasTextureMap&3) == 2);
	vec4 alpha_col = texture(AlphaMapSampler, GSTexCoord);

	vec3 nv = normalize(GSNormal);
	if(gl_FrontFacing && GSWorldPos.w != 0){
		if(BackFaceColor.w == 0)
			discard;
		base_color.xyz *= BackFaceColor.xyz;
		nv = -nv;
	}
	vec3 light_dir = LightPos[0].xyz; // directional light
	vec3 litdif = GetDiffuse(nv, light_dir);
	vec3 spc = LightSpc[0] * GetSpecular(nv, light_dir);
	vec3 litcol = LightCol[0];

	vec4 col;
	col.xyz = saturate(Ambient.xyz + base_color.xyz * litcol * Diffuse) * litdif;
	col.w = base_color.w;
	col *= tex_col;
	col.w *= alpha_col.w;
	if(col.w < 0.01)
		discard;
	col.xyz += Specular.xyz * spc;

	if(GSWorldPos.w == 0 && Edge)
		col.xyz = vec3(0,0,0);

	OutColor = saturate(col);
}

