
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 bool 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

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;
	normal = normalize(normal);
	return normal;
}
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 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 volumeres = fbosize;
	vec2 tc = vec2(gl_FragCoord)/vec2(volumeres, volumeres);
	float depthtex = texture2D(depthTexture, tc).x;
	//vec3 normal = texture2D(normalTexture, tc).xyz;
	//vec3 dir = (gl_ModelViewMatrix*vec4(normal, 1.0)).xyz;//vec3(0,0,1);//normal-vec3(0,0,-1);
	//vec3 dir = vec3(0,0,1);
	
//	float depthtex = smoothDepth(tc);
//	float depthtex = medianDepth(tc);

	//gl_FragDepth = gl_FragCoord.z;
	/*
	float offset = depthoffset/20.0;
	float slice_size = depththickness/20.0;
	vec3 fragcord = (gl_FragCoord).xyz;
	vec3 vposZ = vec3(gl_FragCoord.x, gl_FragCoord.y, depthtex+offset);
	vec3 vnegZ = vposZ - (slice_size * dir);
	
	if(fragcord.z<vposZ.z && fragcord.z>vnegZ.z)
	{
		//gl_FragDepth = 1.0;
		//finalColour.xyz = normal.xyz;
	}
	else
	{
		if(depthpeal==true)
		{
			finalColour.w = 0.0;
			discard;
			return;
		}
	}*/
	
	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))
	{
		//gl_FragDepth = 1.0;
	}
	else
	{
		if(depthpeal==true)
		{
			finalColour.w = 0.0;
			discard;
			return;
		}
	}

	if(depthpeal==false)
	{
		vec3 norm;
		norm = eval_normal();
		finalColour.xyz = norm;
		finalColour.w = 1.0;
	}
	
	//assing the colour to our final colour
	gl_FragColor = finalColour;	
}