#version 330

uniform sampler2D rayEntranceTexture; 
uniform sampler2D rayExitTexture;

uniform sampler3D volumeTex3D;
uniform float	  volMinVal;
uniform float     volMaxVal;

uniform sampler1D transferFunctionTex;

in vec2 		  fragmentTexCoords;

vec4 backgroundColor = vec4( 0.0, 0.0, 0.0, 0.0 );

uniform bool useDoF;
uniform int  raycastMode;


vec3 rayEntrancePosition;
vec3 rayExitPosition;
vec3 rayDirection;




layout(location = 0 ) out vec4 fragColor;


//volume:
uniform float stepDistance; //also used as slice 0.0-1.0


//helper function:
/*vec4 weightedTextureResolve2DEntrance(){
	ivec2 unnormalizedTexCoords = ivec2( floor( textureSize( rayEntranceTexture ) * fragmentTexCoords ) );
	vec4 ret = vec4( 0.0, 0.0, 0.0, 0.0 );
	for( int i = 0; i < aaSamples; ++i ){
		ret += texelFetch( rayEntranceTexture, unnormalizedTexCoords, i ) * 1/aaSamples;
	}
	return ret;
}

vec4 weightedTextureResolve2DExit(){
	ivec2 unnormalizedTexCoords = ivec2( floor( textureSize( rayExitTexture ) * fragmentTexCoords ) );
	vec4 ret = vec4( 0.0, 0.0, 0.0, 0.0 );
	for( int i = 0; i < aaSamples; ++i ){
		ret += texelFetch( rayExitTexture, unnormalizedTexCoords, i ) * 1/aaSamples;
	}
	return ret;
}*/


//DVR things:
vec4  frontToBack(){
	float compareDistance = length( rayDirection  );
	if( compareDistance == 0 ) return backgroundColor;
	rayDirection = normalize( rayDirection );

	float newDist = 0.0;
	vec3 newPos = rayEntrancePosition;

	vec4 color = vec4( 0.0, 0.0, 0.0, 0.0 );

	int i = 0;
	while(  color.a < 1.0 && newDist < compareDistance  ) {
			float val = texture( volumeTex3D,  newPos ).r; //get volume value
			val /= (volMaxVal - volMinVal); //normaliziation

			vec4 colorNew = texture( transferFunctionTex, val );
			color = (colorNew * colorNew.a) + color * (1.0-colorNew.a);


			newPos += (rayDirection * stepDistance);
			newDist = length( newPos - rayEntrancePosition  );	
	}

	return clamp( color, 0.0, 1.0 );
}





vec4 backToFront(){
	float compareDistance = length( rayDirection  );
	if( compareDistance == 0 ) return backgroundColor;
	rayDirection = normalize( rayDirection );

	float newDist = 0.0;
	vec3 newPos = rayExitPosition;

	vec4 color = vec4( 0.0, 0.0, 0.0, 0.0 );

	while(  color.a < 1.0 && newDist < compareDistance  ) {
			float val = texture( volumeTex3D,  newPos ).r; //get volume value
			val /= (volMaxVal - volMinVal); //normaliziation
			
			//workaround because the 1D Texture Preview (of the transferfunction) in gDebugger is buggy and crashes... 
			//color += ( 0.1 * val, 0.1 * val, 0.1 * val, 0.1 * val );
			vec4 colorNew = texture( transferFunctionTex, val );
			color = (colorNew * colorNew.a) + color * (1.0-colorNew.a);
			//color.rgb = (1.0 - color.a)*colorNew.rgb + color.rgb;
			//color.a = (1.0 - color.a)*colorNew.a + color.a;

			newPos += ((-rayDirection) * stepDistance);
			newDist = length( newPos - rayExitPosition  );	
	}

	return clamp( color, 0.0, 1.0 );
}




vec4 maxDensity(){
	float compareDistance = length( rayDirection  );
	if( compareDistance == 0 ) return backgroundColor;
	rayDirection = normalize( rayDirection );

	float newDist = 0.0;
	vec3 newPos = rayExitPosition;

	float maxVal = 0.0;
	vec4 color = vec4( 0.0, 0.0, 0.0, 0.0 );
	while(  color.a < 1.0 && newDist < compareDistance  ) {
			float val = texture( volumeTex3D,  newPos ).r; //get volume value
			if( val > maxVal ) maxVal = val;
			newPos += ((-rayDirection) * stepDistance);
			newDist = length( newPos - rayExitPosition  );	
	}
	maxVal /= (volMaxVal - volMinVal); //normaliziation
	vec4 maxDensColor = texture( transferFunctionTex, maxVal );
	//return vec4( maxDensColor.rgb, 1.0 );
	return maxDensColor;
}


vec4 averaging(){
	float compareDistance = length( rayDirection  );
	if( compareDistance == 0 ) return backgroundColor;
	rayDirection = normalize( rayDirection );

	float newDist = 0.0;
	vec3 newPos = rayEntrancePosition;

	float sumval = 0.0f;
	int steps = 0;

	int i = 0;
	while(  newDist < compareDistance  ) {
			sumval += texture( volumeTex3D,  newPos ).r; //get volume value
			newPos += (rayDirection * stepDistance);
			newDist = length( newPos - rayEntrancePosition  );	
			++steps;
	}
	sumval /= (volMaxVal - volMinVal); //normaliziation
	sumval /= steps;
	vec4 avgCol =  texture( transferFunctionTex, clamp(sumval, 0.0, 1.0) );
	//return vec4( avgCol.rgb, 1.0 );
	return avgCol;
}



vec4 first(){
	float compareDistance = length( rayDirection  );
	if( compareDistance == 0 ) return backgroundColor;
	rayDirection = normalize( rayDirection );

	float newDist = 0.0;
	vec3 newPos = rayEntrancePosition;
	while(  newDist < compareDistance  ) {
			float val = texture( volumeTex3D,  newPos ).r; //get volume value
			vec4 color = texture( transferFunctionTex, val );
			if( color.a != 0.0 )  return vec4( color );
			newPos += (rayDirection * stepDistance);
			newDist = length( newPos - rayEntrancePosition  );	
	}
	return vec4( 0.0, 0.0, 0.0, 0.0 );
}







void main(void)
{	
	rayEntrancePosition = texture( rayEntranceTexture, fragmentTexCoords).rgb;
	rayExitPosition = texture( rayExitTexture, fragmentTexCoords).rgb;
	rayDirection =   rayExitPosition - rayEntrancePosition;

	if( rayDirection == vec3( 0.0, 0.0, 0.0 ) ){
		fragColor = backgroundColor;
	} else {

		if( raycastMode == 0 ) fragColor = frontToBack();
		else if( raycastMode == 1 ) fragColor = backToFront();
		else if( raycastMode == 2 ) fragColor = maxDensity();
		else if( raycastMode == 3 ) fragColor = averaging();
		else if( raycastMode == 4 ) fragColor = first();

		else fragColor = vec4( 1.0,  0.0, 0.0, 1.0 );
	}

	//fragColor = vec4( rayEntrancePosition, 0.2);
	//if( rayDirection.z < 0.0 ) fragColor = vec4( 0.0, 1.0, 1.0, 1.0 );

}

