uniform sampler3D tex;
uniform sampler3D gradient;
uniform sampler2D tex_front;
uniform sampler2D tex_back;
uniform sampler1D rgb_sampler;
uniform int apply_filter;
uniform int apply_transfer;
uniform int renderpass;
uniform const float stepsize;
uniform const float startoffset;

varying vec3 normal;
varying vec3 view;
varying vec3 lightdirection;

vec4 raycasting()
{
	vec3 V = vec3(0.0, 0.0, 0.0);
	vec3 R = vec3(0.0, 0.0, 0.0);
	vec4 Ambient = vec4(0.0, 0.0, 0.0, 0.0);
	vec4 Diffuse = vec4(0.0, 0.0, 0.0, 0.0);
	vec4 Specular = vec4(0.0, 0.0, 0.0, 0.0);
	vec4 ret = vec4(0.0, 0.0, 0.0, 0.0);
	
	const float dz = stepsize;
	const int maxrange = 2000;
	
	vec4 front_color;
	
	vec4 entry_point = texture2D(tex_front, vec2(gl_TexCoord[2].x, gl_TexCoord[2].y));
	vec4 point = entry_point;
	vec4 exit_point = texture2D(tex_back, vec2(gl_TexCoord[2].x, gl_TexCoord[2].y));
	
	float dist = distance(entry_point, exit_point)/dz;
	int maxiter = int(floor(dist));
	vec3 diff = vec3((exit_point.x - entry_point.x)/dist, (exit_point.y - entry_point.y)/dist, (exit_point.z - entry_point.z)/dist);
	//point = vec4(point.x + startoffset*diff.x, point.y + startoffset*diff.y, point.z + startoffset*diff.z, 0.0);
	
	int firsthit = 0;
	vec4 grad_first;
	V = normalize(-view);
	
	if(entry_point != exit_point)
	{
		for(int i = 0; i < maxrange; i++)
		{
			if (i > startoffset)
			{
				vec4 intensity = texture3D(tex, point.xyz);
				front_color = texture1D(rgb_sampler, intensity.x);	
				vec4 grad = texture3D(gradient, point.xyz);
							
				R = normalize(-reflect(lightdirection,(grad.xyz)));
				Ambient = gl_LightSource[0].ambient;
				Diffuse = gl_LightSource[0].diffuse * max(dot(grad.xyz, lightdirection), 0.0);
				//if (firsthit == 0 && intensity.x > 0.3)
				{
					Specular = gl_LightSource[0].specular * pow(max(dot(R, V), 0.0), 20);
					firsthit = 1;
				}
							
				
				
				//front_color = vec4(1.0, 0, 0, 0.1);
				front_color.w = front_color.w * intensity.s; //gewichtung grauwert mit opacity
				vec4 ambient_lookup = texture1D(rgb_sampler, Ambient.x);
				vec4 diffuse_lookup = texture1D(rgb_sampler, Diffuse.x);
				vec4 specular_lookup = texture1D(rgb_sampler, Specular.x);
				
				ret.xyz = ret.xyz + (1.0 - ret.w) * front_color.w * (front_color.xyz+ambient_lookup.xyz+Diffuse.xyz + Specular.xyz);
				ret.w = ret.w + (1.0 - ret.w) * front_color.w;
			}
			point = vec4(point.x + diff.x, point.y + diff.y, point.z + diff.z, 0.0);
			if ((ret.w >= 1.0) || (ret.x >= 1.0) || (ret.y >= 1.0) || (ret.z >= 1.0)|| (i >= maxiter)) break;	
		}
	}
	
	return ret ;
}

void main()
{
	vec4 color;
	vec4 
	intensity_;
	
	if (apply_filter == 1)
	{
		intensity_ = 0.2 * ( texture3D(tex, vec3(gl_TexCoord[0].x-0.003, gl_TexCoord[0].y+0.003, gl_TexCoord[0].z))  +
		 texture3D(tex, vec3(gl_TexCoord[0].x-0.003, gl_TexCoord[0].y-0.003, gl_TexCoord[0].z)) + 
		 texture3D(tex, vec3(gl_TexCoord[0].x+0.003, gl_TexCoord[0].y+0.003, gl_TexCoord[0].z)) + 
		 texture3D(tex, vec3(gl_TexCoord[0].x+0.003, gl_TexCoord[0].y-0.003, gl_TexCoord[0].z)) +
		( texture3D(tex, vec3(gl_TexCoord[0].x, gl_TexCoord[0].y, gl_TexCoord[0].z)) ) );
	}
	else
	{
		intensity_ = texture3D(tex, gl_TexCoord[0].xyz);
	}
	
	if (apply_transfer == 1)
	{
		color = texture1D(rgb_sampler, intensity_.s);
	}
	else if (apply_transfer == 2)
	{
		color = intensity_;
	}
	else
	{
		if (renderpass == 1)
		{
			//color = vec4(0.0, 1.0,1.0, 0.0);
			color = vec4(gl_TexCoord[2].x, gl_TexCoord[2].y, gl_TexCoord[2].z, 0.0);
		}
		else if(renderpass == 2)
		{
			color = vec4(gl_TexCoord[3].x, gl_TexCoord[3].y, gl_TexCoord[3].z, 0.0);
		}
		else 
		{	
			color = raycasting();
		}
	}
	//color = vec4(0.0, 1.0,1.0, 0.0);
	gl_FragColor = color;
}
