
uniform sampler3D volumeTexture;
uniform sampler2D RGBlookupTexture;
uniform sampler2D RAGABAlookupTexture;

uniform int channel;

uniform vec3 gooch_warmCol;
uniform vec3 gooch_coolCol;
uniform float silhCont;
uniform float silhExp;
uniform float degenthresh;
uniform float alphathresh;

varying vec3 V;
varying vec3 V1;

float g_window(float g)
{
	float result = g;

	float min = 0.2;
	float max = 0.8;

	if(g<min) result = 0.0;
	else if(g>max) result = 1.0;
	else
	{
		g = g/2.0;
		result = g; //;(g/2.0)*(min/max);
	}

	return result;
}

vec3 eval_normal(void)
{
	vec3 normal;
	//==============================================
	//EVALUATE OUR NORMAL BY CENTRAL DIFFERENCE
	//==============================================
	float stepsize	= 1.0/256.0;
	vec3 sample1,sample2,sample3,sample4;
	sample1.x = texture3D(volumeTexture, gl_TexCoord[0].stp-vec3(stepsize,0,0)).x;
	sample2.x = texture3D(volumeTexture, gl_TexCoord[0].stp+vec3(stepsize,0,0)).x;
	sample1.y = texture3D(volumeTexture, gl_TexCoord[0].stp-vec3(0,stepsize,0)).x;
	sample2.y = texture3D(volumeTexture, gl_TexCoord[0].stp+vec3(0,stepsize,0)).x;
	sample1.z = texture3D(volumeTexture, gl_TexCoord[0].stp-vec3(0,0,stepsize)).x;
	sample2.z = texture3D(volumeTexture, gl_TexCoord[0].stp+vec3(0,0,stepsize)).x;

	normal = sample2-sample1;
//	normal.rgb = normal.rgb*2.0 - 1.0;
//	normal = normalize(normal);

	return normal;
}
//GOOCH LIGHTING
vec3 shading_func(vec3 N, vec3 V, vec3 L)
{
	vec3 colour; 
	
	//=============================
	//APPLY GOOCH LIGHTING
	//=============================
	//Calculate the diffuse contribution of the light
	//float dotLight = 0.0; //dot(normalize(vec3(gl_LightSource[0].position)), N.rgb);

	//Calculate the correct color according to the Gooch shading model.
	//toneLight ranges from -1 to 1
	float dotLight = dot(vec3(N),L);
	
	vec3 warm = vec3(gooch_warmCol[0], gooch_warmCol[1], gooch_warmCol[2]);
	vec3 cool = vec3(gooch_coolCol[0], gooch_coolCol[1], gooch_coolCol[2]);

	colour.rgb = (((1.0+dotLight)*0.25)*warm + (1.0-((1.0+dotLight)*0.5))*cool);
	return colour;
}

void main()
{	
	//get the texture rgb data
	float texValue = texture3D(volumeTexture, gl_TexCoord[0].stp).x;

	//==============================
	//APLY OUR TRANSFER FUNCTION
	//==============================
	//make sure we sample from centre of lookup table
	//float lookup_offset = (1.0/256.0/2.0);
	//texValue += lookup_offset;

	//get lookup table values
	//r,g,b,ra,ga,ba
	vec3 RGBlookupValue, RAGABAlookupValue;
	RGBlookupValue = RAGABAlookupValue = vec3(0.0);
	vec4 finalColour = vec4(0.0);

	if(channel==0)
	{
		RGBlookupValue.x = texture2D(RGBlookupTexture, vec2(texValue, 0.0)).x;
		RAGABAlookupValue.x = texture2D(RAGABAlookupTexture, vec2(texValue, 0.0)).x;
		finalColour = vec4(RGBlookupValue.x,0.0,0.0, RAGABAlookupValue.x);
	}
	else if(channel==1)
	{
		RGBlookupValue.y = texture2D(RGBlookupTexture, vec2(texValue, 0.0)).y;
		RAGABAlookupValue.y = texture2D(RAGABAlookupTexture, vec2(texValue, 0.0)).y;
		finalColour = vec4(0.0,RGBlookupValue.y,0.0, RAGABAlookupValue.y);
	}
	else if(channel==2)
	{
		RGBlookupValue.z = texture2D(RGBlookupTexture, vec2(texValue, 0.0)).z;
		RAGABAlookupValue.z = texture2D(RAGABAlookupTexture, vec2(texValue, 0.0)).z;
		finalColour = vec4(0.0,0.0,RGBlookupValue.z, RAGABAlookupValue.z);
	}
	else if(channel==3)
	{
		RGBlookupValue.x = texture2D(RGBlookupTexture, vec2(texValue, 0.0)).x;
		RAGABAlookupValue.x = texture2D(RAGABAlookupTexture, vec2(texValue, 0.0)).x;
		finalColour = vec4(RGBlookupValue.x,RGBlookupValue.x,RGBlookupValue.x, RAGABAlookupValue.x);
	}


	vec3 N = eval_normal();
	vec3 L;
	vec3 shading;

	bool degenerate = false;
	float length = sqrt(N.x*N.x+N.y*N.y+N.z*N.z);//length(N);
	if(length<degenthresh) degenerate = true;

	//We have to scale the gradient between -1 and 1
	N = normalize(N);
	//N = 0.5-N;
	//N = normalize(N);

	L = normalize(V1 - (gl_TextureMatrix[0]*gl_LightSource[0].position).xyz);	//gl_LightSource[0].position.xyz - V
	shading = shading_func(N,V1,L);
	finalColour += vec4(shading,0.0);

	//vec4 startColour = vec4(0.0);
	//startColour = finalColour;

/*	//========
	//boundaries
	//========
	float boundCont = 1.0;
	float invMaxGrad = 0.5;
	float boundExp = 2.0;
	float grad = length;
 	if(channel==0) finalColour.a += boundCont*pow(invMaxGrad*grad,boundExp);
	else  finalColour.a += boundCont*pow(invMaxGrad*grad,boundExp);

//	finalColour.a = RAGABAlookupValue.x;
*/
	
/*	//========
	//toon
	//========
	//...create a set of 4 colors that go from bright
	//to the specified toon color
	vec3 toonCol = vec3(0.0);
	if(channel==0) toonCol = vec3(1.0,0.0,0.0);
	if(channel==1) toonCol = vec3(0.0,1.0,0.0);
	if(channel==2) toonCol = vec3(0.0,0.0,1.0);

	vec3 col = toonCol - vec3(1.0, 1.0, 1.0);
	vec4 color1 = vec4(toonCol - 0.75*col, finalColour.a);
	vec4 color2 = vec4(toonCol - 0.5*col, finalColour.a);
	vec4 color3 = vec4(toonCol - 0.25*col, finalColour.a);
	vec4 color4 = vec4(toonCol, finalColour.a);
//	vec4 color1 = vec4(0.8, 0.0, 0.0, finalColour.a);
//	vec4 color2 = vec4(0.4, 0.0, 0.0, finalColour.a);
//	vec4 color3 = vec4(0.2, 0.0, 0.0, finalColour.a);
//	vec4 color4 = vec4(0.0, 0.0, 0.0, finalColour.a);

	float dotLight = dot(normalize(vec3(L)), vec3(texValue));
	dotLight = clamp(dotLight, 0.0, 1.0);

	//and then assign different ranges of the diffuse
	//coefficient to one of the 4 colors
	if (dotLight > 0.5)
		finalColour += color1;
	else if (dotLight > 0.25)
		finalColour += color2;
	else if (dotLight > 0.05)
		finalColour += color3;
	else
		finalColour += color4;	
*/

/*
	//========
	//edges
	//========
	//We make very perpendicular voxels black, and lesser perpendicular voxels
	//decreasingly dark until the value is below the threshold, when no
	//enhancement is performed.
	float edgeExp = 8.0;
	float edgeThresh = 0.01;
	float dotView2 = dot(N, (gl_TextureMatrix[0]*vec4(0,0,1,0)).xyz);
	float edgeVal = pow(1.0-abs(dotView2),edgeExp);
	
	if(edgeVal >= edgeThresh) finalColour.rgb -= mix(finalColour.rgb, vec3(0.0,0.0,0.0), pow((edgeVal-edgeThresh)/(1.0-edgeThresh),4.0));
*/

	//========
	//silhouettes
	//========
	//If we want to enhance silhoutte edges, we can make sure the gradient
	//is not degenerate and change the opacity based on the voxel's
	//perpendicularity relative to the viewer.		
	float dotView = dot(N, (gl_TextureMatrix[0]*vec4(0,0,1,0)).xyz);
	
	vec4 silhouette = vec4(0.0);

	if(!degenerate)
	{
		//silhouette =  vec4(g_window(length)*pow(1.0-abs(dotView),silhExp));
		//silhouette.rgb = -finalColour.rgb;

		silhouette =  vec4(silhCont*pow(1.0-abs(dotView),silhExp));
		finalColour.xyz -= silhouette.xyz;
		if(silhouette.w>alphathresh) finalColour.w = 1.0;
	}

	//assing the colour to our final colour
	gl_FragColor = finalColour;
}
