
uniform int channel;
uniform sampler3D volumeTexture;
uniform sampler3D volumeTexture2;
uniform sampler2D RGBlookupTexture;
uniform sampler2D RAGABAlookupTexture;
uniform sampler2D depthTexture;
uniform sampler2D normalTexture;

uniform float kernel[9];
uniform float kernel_norm;
uniform float fbosize;
uniform float depthoffset;
uniform float depththickness;
uniform int depthpeal;

#define s2(a, b)				temp = a; a = min(a, b); b = max(temp, b);
#define mn3(a, b, c)			s2(a, b); s2(a, c);
#define mx3(a, b, c)			s2(b, c); s2(a, c);

#define mnmx3(a, b, c)			mx3(a, b, c); s2(a, b);                                   // 3 exchanges
#define mnmx4(a, b, c, d)		s2(a, b); s2(c, d); s2(a, c); s2(b, d);                   // 4 exchanges
#define mnmx5(a, b, c, d, e)	s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e);           // 6 exchanges
#define mnmx6(a, b, c, d, e, f) s2(a, d); s2(b, e); s2(c, f); mn3(a, b, c); mx3(d, e, f); // 7 exchanges

varying vec3 V;
varying vec3 V1;
varying vec3 L;

vec3 eval_normal(void)
{
	vec3 normal;
	//==============================================
	//EVALUATE OUR NORMAL BY CENTRAL DIFFERENCE
	//==============================================
	float stepsize	= 1.0/fbosize;
	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;
	return normal;
}
//BLING-PHONG LIGHTING MODEL
vec3 shading_func(vec3 N, vec3 VV, vec3 L)
{
	N = normalize(N);

	vec3 Ka = gl_LightSource[0].ambient.xyz; //vec3(0.1, 0.1, 0.1);
	vec3 Kd = gl_LightSource[0].diffuse.xyz; //vec3(0.6, 0.6, 0.6);
	vec3 Ks = gl_LightSource[0].specular.xyz; //vec3(0.2, 0.2, 0.2);
	float n = 8.0;

	vec3 H = normalize(L+VV);

	vec3 ambient = Ka ;

	float diffuseLight = max(dot(L,N),0.0);
	vec3 diffuse = Kd * diffuseLight;

	float specularLight = pow(max(dot(H,N),0.0), n);
	if(diffuseLight<=0.0) specularLight = 0.0;
	vec3 specular = Ks * specularLight;

	return ambient+diffuse+specular;
}
float LinearizeDepth(float zoverw)
{		
	float near = gl_ProjectionMatrix[2].z; // camera z near	
	float far = gl_ProjectionMatrix[3].z; // camera z far		

	return (-zoverw-near)/(far-near); // will map near..far to 0..1
//	return (2.0 * n) / (f + n - zoverw * (f - n));	
}
float convertZ(float depthBufferValue )
{
	float near = -1024.0; // camera z near	
	float far = 1024.0; // camera z far		

	float clipZ = ( depthBufferValue - 0.5 ) * 2.0;
	return -(2.0 * far * near) / ( clipZ * ( far - near ) - ( far + near ));
}
float readDepth(vec2 coord ) {
	float near = gl_ProjectionMatrix[2].z; // camera z near	
	float far = gl_ProjectionMatrix[3].z; // camera z far		
	return (2.0 *  near) / (far +  near - texture2D( depthTexture, coord ).x * (far - near));	
}
float mylength(vec3 v)
{
	float l = v.x*v.x+v.y*v.y+v.z*v.z;
	l = sqrt(l);
	return l;
}

float medianDepth(vec2 texcood)
{
	float stepsize = 1.0/fbosize;
	vec2 Tinvsize = vec2(stepsize, stepsize);
	vec3 v[6];

	vec2 texcord = vec2(texcood.x, texcood.y);
	vec4 colorOrg = texture2D( depthTexture, texcord);

	v[0] = texture2D(depthTexture, texcord.xy + vec2(-1.0, -1.0) * Tinvsize).xyz;
	v[1] = texture2D(depthTexture, texcord.xy + vec2( 0.0, -1.0) * Tinvsize).xyz;
	v[2] = texture2D(depthTexture, texcord.xy + vec2(+1.0, -1.0) * Tinvsize).xyz;
	v[3] = texture2D(depthTexture, texcord.xy + vec2(-1.0,  0.0) * Tinvsize).xyz;
	v[4] = texture2D(depthTexture, texcord.xy + vec2( 0.0,  0.0) * Tinvsize).xyz;
	v[5] = texture2D(depthTexture, texcord.xy + vec2(+1.0,  0.0) * Tinvsize).xyz;

	// Starting with a subset of size 6, remove the min and max each time
	vec3 temp;
	mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
	v[5] = texture2D(depthTexture, texcood.xy + vec2(-1.0, +1.0) * Tinvsize).xyz;
	mnmx5(v[1], v[2], v[3], v[4], v[5]);
	v[5] = texture2D(depthTexture, texcood.xy + vec2( 0.0, +1.0) * Tinvsize).xyz;
	mnmx4(v[2], v[3], v[4], v[5]);
	v[5] = texture2D(depthTexture, texcood.xy + vec2(+1.0, +1.0) * Tinvsize).xyz;
	mnmx3(v[3], v[4], v[5]);

	vec4 filtered = vec4(v[4].x, v[4].y, v[4].z, 1.0);
	return filtered.x;
}
float smoothDepth(vec2 texcoord)
{
	float stepsize = 1.0/fbosize;
	vec4 filtered;
	filtered	= texture2D(depthTexture,  texcoord	+vec2(-stepsize,stepsize))  * kernel[0];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(0, stepsize))  		* kernel[1];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(stepsize, stepsize))  * kernel[2];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(-stepsize,0))  		* kernel[3];
	filtered	+= texture2D(depthTexture, texcoord)							* kernel[4];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(stepsize,0))   		* kernel[5];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(-stepsize,-stepsize)) * kernel[6];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(0,-stepsize))  		* kernel[7];
	filtered	+= texture2D(depthTexture, texcoord	+vec2(stepsize,-stepsize))  * kernel[8];
	filtered /= kernel_norm;
	return filtered.x;
}
void main()
{		
	//get the texture rgb data
	float texValue = texture3D(volumeTexture, gl_TexCoord[0].stp).x;
	//if(texValue==0.0) discard;
	//float lookup_offset = (1.0/1024.0/2.0);
	//texValue += 0.5;

	//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.5)).x;
		RAGABAlookupValue.x = texture2D(RAGABAlookupTexture, vec2(texValue, 0.5)).x;

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

		finalColour = vec4(0.0, 0.0, RGBlookupValue.z, RAGABAlookupValue.z);
	}
	if(channel==3)
	{		
		RGBlookupValue.x = texture2D(RGBlookupTexture, vec2(texValue, 0.5)).x;
		RAGABAlookupValue.x = texture2D(RAGABAlookupTexture, vec2(texValue, 0.5)).x;

		finalColour = vec4(RGBlookupValue.x,RGBlookupValue.x,RGBlookupValue.x, RAGABAlookupValue.x);
	}
	if(channel==4)
	{
		float texValue2 = texture3D(volumeTexture2, gl_TexCoord[0].stp).x;
		
		RGBlookupValue.x = texture2D(RGBlookupTexture, vec2(texValue, 0.5)).x;
		RAGABAlookupValue.x = texture2D(RAGABAlookupTexture, vec2(texValue2, 0.5)).x;
 
		finalColour = vec4(RGBlookupValue.x,RGBlookupValue.x,RGBlookupValue.x, RAGABAlookupValue.x);	
	}
	
	if(finalColour.w==0.0)
	{
		discard;
		return;
	}

	float offset = depthoffset/20.0;
	float slice_size = depththickness/20.0;
	float volumeres = fbosize;
	
	vec2 tc = vec2(gl_FragCoord)/vec2(volumeres, volumeres);
	//float depthtex = medianDepth(tc);
	float depthtex = texture2D(depthTexture, tc).x;
	
	/*vec3 dir = texture2D(normalTexture, tc).xyz;
	dir = dir * slice_size;
	
	vec3 vd0 = vec3(gl_FragCoord.x, gl_FragCoord.y, depthtex);
	vec3 vd1 = vd0+dir;
	vec3 vd2 = vec3(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z);
	
	vec3 dvec0 = vd0-vd1;
	vec3 dvec1 = vd0-vd2;
	
	float l0 = mylength(dvec0);
	float l1 = mylength(dvec1);

	if(l1<l0+offset)
	{
		vec3 N = eval_normal();
		vec3 shading = shading_func(N,V1,L);
		finalColour += vec4(shading,0.0);
	}
	else
	{
		if(depthpeal==true)
		{
			finalColour.x *= 0.5;
			//discard;
			//return;
		}
	}*/
	
				
	if(depthpeal==0)
	{	
		vec3 norm;
		norm = eval_normal();
		finalColour.xyz = norm;
		finalColour.w = 1.0;
	}
	else
	{
		float fragdepth = (gl_FragCoord.z);
		float posZ = fragdepth; //+slice_size
		float negZ = fragdepth-slice_size;
		if(negZ<=(depthtex+offset) && posZ>=(depthtex+offset))
		{
			finalColour.y = 1.0;
		}
		else
		{
			//if(depthpeal==1)
			{
				finalColour.x *= 0.5;
				//finalColour.w = 0.0;
				//discard;
				//return;
			}
		}
	}
	/*
	float fragdepth = (gl_FragCoord.z);
	float posZ = fragdepth; //+slice_size
	float negZ = fragdepth-slice_size;
	if(negZ<=(depthtex+offset) && posZ>=(depthtex+offset))
	{
		//finalColour.xyz = dir;
		//gl_FragDepth = 1.0;
		vec3 N = eval_normal();
		vec3 shading = shading_func(N,V1,L);
		finalColour += vec4(shading,0.0);
			//finalColour.xyzw *= 0.5;
	}
	else
	{
		if(depthpeal==true)
		{
			//finalColour.x *= 0.5;
//			finalColour.w *= 0.25;
//			discard;
//			return;
		}
	}	
*/

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

	float fragdepth = (gl_FragCoord.z);
	float offset = depthoffset/20.0;
	float slice_size = depththickness/20.0;
	float posZ = fragdepth; //+slice_size
	float negZ = fragdepth-slice_size;
	if(negZ<=(depthtex+offset) && posZ>=(depthtex+offset))
	{


	}
	else
	{
		if(depthpeal==true)
		{
			//finalColour.x *= 0.5;
			finalColour.w = 0.0;
//			finalColour =vec4(0.0, 0.0, 0.0, 0.0);
			discard;
			return;
		}
	}

	if(depthpeal==false)
	{
		vec3 norm;
		norm = eval_normal();
		finalColour.xyz = norm;
		finalColour.w = 1.0;
	}
	*/