float4x4 mat_WorldViewProj: WorldViewProjection;
float4x4 mat_World: World;
float4x4 mat_WorldI: WorldInverse;
float4x4 mat_WorldIT: WorldInverseTranspose;
float4x4 ViewInv : ViewInverse;

float4x4 GazeLocator
<
	string UIName = "Gaze locator";
>;

// Parameters
float3 EyePivot: Position
<
	string UIName = "Eye pivot";
	string Space = "World";
> = {0, 0, 0};

float3 LightPos : Position 
<
	string UIName =  "Lamp Position";
	string Object = "PointLight";
	string Space = "World";
> = {-54.0f, 50.0f, 100.0f};

float3 LightColor : Diffuse
<
	string UIName =  "Lamp";
	string UIWidget = "Color";
	string Object = "PointLight";
> = {1.0f, 1.0f, 1.0f};

texture EyeTexture : Diffuse
<
	string ResourceName = "default_color.dds";
	string ResourceType = "2D";
	string UIName =  "Eye Texture (if used)";
>;

sampler2D EyeDiffuse = sampler_state 
{
	Texture = <EyeTexture>;
	MinFilter = LinearMipMapLinear;
	MagFilter = Linear;
	AddressU = Wrap;
	AddressV = Repeat;
};

float IrisScaleX
<
  string UIName = "Iris scale X";
  string UIWidget = "Slider";
  float UIMin = 0.0;
  float UIStep = 0.05;
>
 = 1;

float IrisScaleY
<
  string UIName = "Iris scale Y";
  string UIWidget = "Slider";
  float UIMin = 0.0;
  float UIStep = 0.05;
> = 1;

float PupilScaleX 
<
  string UIName = "Pupil scale X";
  string UIWidget = "Slider";
  float UIMin = 0.0;
  float UIStep = 0.05;
> = 0.5;

float PupilScaleY 
<
  string UIName = "Pupil scale Y";
  string UIWidget = "Slider";
  float UIMin = 0.0;
  float UIStep = 0.05;
> = 0.5;

float3 PupilColor 
<
  string UIName = "Pupil color";
  string UIWidget = "Color";
> = {0.019607843, 0.019607843, 0.031372549};

// Vertex data
struct inputdata
{
	float4 pos: POSITION;
	float3 normal: NORMAL;
	float3 rest_pos: COLOR0;
};

struct vertex_outputdata
{
	float4 pos: POSITION;
	float3 worldpos: TEXCOORD0;
	float3 normal: TEXCOORD1;
	float3 eyelocal: TEXCOORD2;
	float3 eyegaze: TEXCOORD3;
	float2 eyexy: TEXCOORD4;
	float3 view_eye_pos: TEXCOORD5;
};

vertex_outputdata mainVS(inputdata in_data)
{
	vertex_outputdata out_data;

	out_data.pos = mul(mat_WorldViewProj, in_data.pos);
	out_data.normal = normalize(mul(mat_WorldIT, float4(in_data.normal, 1.f)).xyz);

	float4 eye_pivot = mul(mat_WorldI, float4(EyePivot, 1));

	out_data.worldpos = mul(mat_World, in_data.pos).xyz;
	out_data.eyelocal = in_data.rest_pos.xyz - eye_pivot.xyz;
	out_data.eyegaze = mul(mat_WorldI, mul(GazeLocator, float4(0, 0, 0, 1))).xyz - eye_pivot.xyz;

	float3 zaxis = normalize(out_data.eyegaze);
	float3 xaxis = cross(normalize(mul(mat_WorldI, mul(GazeLocator, float4(0, 1, 0, 0))).xyz), zaxis);
	float3 yaxis = cross(zaxis, xaxis);

	out_data.eyexy.x = dot(xaxis, float4(out_data.eyelocal, 1));
	out_data.eyexy.y = dot(yaxis, float4(out_data.eyelocal, 1));


	out_data.view_eye_pos = mul(ViewInv, float4(0, 0, 0, 1)).xyz;

	return out_data;
}

#define EYEPROJECTION_EPSILON 1e-30
#define PI 3.1415926535897932384626433832795

#define PUPIL_REGION_END 0.1
#define IRIS_REGION_END 0.3

float ellipseAngle(float2 Pt, float a, float b) 
{
        float X = Pt.x;
        float Y = Pt.y;
        float angle = 0;
        if (X == 0 && Y == 0)
        {
            angle = 0;
        }
        else if (X == 0 && Y != 0)
        {
            angle = acos(sqrt(1 - b * b));
        }
        else 
        {
                float m = Y / X;
                float x = (a * b) / sqrt(b * b + a * a * m * m);
                float y = m * x;
                float z = sqrt(1 - (x * x + y * y));
                angle = acos(z);
        }
        return angle;
}

float4 mainPS(vertex_outputdata in_data) : COLOR
{
	float3 color;

	float3 P = normalize(in_data.eyelocal);
	float3 temp = normalize(in_data.eyegaze);
	float len = length(in_data.eyegaze);

	float angleP = acos(saturate(dot(temp, P)));
	float angleV = atan2(in_data.eyexy.x, in_data.eyexy.y);

	float pupilAngle = ellipseAngle(in_data.eyexy, PupilScaleX, PupilScaleY);
	float irisAngle = ellipseAngle(in_data.eyexy, IrisScaleX, IrisScaleY);

	angleV = (angleV + PI) / (2 * PI); // normalize angle

	float u, v;

	v = saturate(angleV);

	if (v > 0.5)
		v = 1 - v;

	float angleU = 0;

	if (angleP > irisAngle)
	{
		if (abs(PI - irisAngle) > EYEPROJECTION_EPSILON)
		{
			angleU = (angleP - irisAngle) / (PI - irisAngle);
        }
		u = lerp(IRIS_REGION_END, 1.0, angleU);
	}
	else if (angleP > pupilAngle)
	{
		if (abs(irisAngle - pupilAngle) > EYEPROJECTION_EPSILON)
		{
			angleU = (angleP - pupilAngle) / (irisAngle - pupilAngle);
        }
		u = lerp(PUPIL_REGION_END, IRIS_REGION_END, angleU);
	}
	else
	{
		if (abs(pupilAngle) > EYEPROJECTION_EPSILON)
		{
			angleU = (angleP / pupilAngle) ;
		}
		u = angleU * PUPIL_REGION_END;
	}

	//if (angleP < pupilAngle * 0.5)
	if (u < PUPIL_REGION_END * 0.5)
	{
		color = PupilColor;
	}
	else
	{
		color = tex2D(EyeDiffuse, float2(u, v));
	}

	//color = max(dot(in_data.normal, normalize(LightPos - in_data.worldpos)), 0) * LightColor * color;
	color = max(dot(in_data.normal, normalize(in_data.view_eye_pos - in_data.worldpos)), 0) * LightColor * color;
	return float4(color, 1.f);
}

technique Default < string Script = "Pass=p0;"; > 
{
	pass p0 < string Script = "Draw=geometry;"; > 
	{
		VertexProgram = compile vp40 mainVS();
		DepthTestEnable = true;
		DepthMask = true;
		CullFaceEnable = false;
		DepthFunc = LEqual;
		FragmentProgram = compile fp40 mainPS();
	}
}
