//pref
overlayEmit|set|true
overlayDepth|float|0.01|0.9|10.0
underlayOpacity|float|0.01|0.5|1.0
specular|float|0.0|0.12|1
shininess|float|0.01|10.0|30
edgeThresh|float|0.0|0.01|1
edgeExp|float|0.0|0.15|1
boundExp|float|0.0|0.0|3
BETA quality release. This shader allows you to adjust depth of visibility for overlays. Only shows first three overlays. Please select a different shader for 2D views.|note
//vert
void main() {
	gl_TexCoord[1] = gl_MultiTexCoord1;
	gl_Position = ftransform();
}
//frag
uniform int loops, overlays;
uniform float stepSize, sliceSize, viewWidth, viewHeight;
uniform sampler3D intensityVol; //3DTexture containing brightness
uniform sampler3D gradientVol; //3DTexture containing gradient direction and magnitude
uniform sampler2D backFace;
uniform sampler1D TransferTexture, OverlayR, OverlayB, OverlayG;
uniform bool useTransferTexture;
uniform vec3 clearColor,lightPosition, clipPlane;
uniform float clipPlaneDepth;
uniform float specular, shininess, edgeThresh, edgeExp, boundExp, overlayDepth, overlayalpha, underlayOpacity;

void main() {
	// get normalized pixel coordinate in view port (e.g. [0,1]x[0,1])
	vec2 pixelCoord = gl_FragCoord.st;
	pixelCoord.x /= viewWidth;
	pixelCoord.y /= viewHeight;	
	// starting position of the ray is stored in the texture coordinate
	vec3 start = gl_TexCoord[1].xyz;
	vec3 backPosition = texture2D(backFace,pixelCoord).xyz;
	vec3 dir = backPosition - start;
	float len = length(dir);
	dir = normalize(dir);
	//next see if clip plane intersects ray
	if (clipPlaneDepth > -0.5) {
		gl_FragColor.rgb = vec3(1.0,0.0,0.0);
		//next, see if clip plane faces viewer
		//bool frontface = facing(dir , clipPlane);
		bool frontface = (dot(dir , clipPlane) > 0.0);
		//next, distance from ray origin to clip plane
		float dis = dot(dir,clipPlane);
		if (dis != 0.0  )  dis = (-clipPlaneDepth - dot(clipPlane, start.xyz-0.5)) / dis;
		//if ((frontface) && (dis > len)) return;
		//if ((!frontface) && (dis < 0.0)) return;
		//if ((!frontface) && (dis < 0.0)) return; //2006 MacBookPro with OSX 10.4 will not return from program
		if ((frontface) && (dis > len)) len = 0.0;
		if ((!frontface) && (dis < 0.0)) len = 0.0;
		//if ((!frontface) && (dis < 0.0)) return; //2006 MacBookPro with OSX 10.4 will not return from program
		//if ((frontface) && (dis > len)) return; //hence, set len=0 to exit after one sample
		if ((dis > 0.0) && (dis < len)) {
			if (frontface) {
				start = start + dir * dis;
			} else {
				backPosition =  start + dir * (dis); 
			}
			dir = backPosition - start;
			len = length(dir);
			dir = normalize(dir);		
		}
	}	
	vec3 deltaDir = dir * stepSize;
	vec4 rgbaSample, colorSample,gradientSample,colAcc = vec4(0.0,0.0,0.0,0.0);
	float lengthAcc = 0.0;
	float alphar  = 0.0;
	float alphag  = 0.0;
	float alphab  = 0.0;
	float temp = 0.0;
	float opac  = 0.0;
	//We need to calculate the ray's starting position. We add a random
	//fraction of the stepsize to the original starting point to dither the output
	vec3 samplePos = start.xyz + deltaDir* (fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453));
	//float specularColor = 1.0; //pure white, for red... vec3 specularColor= vec3(1.0,0.0,0.0); 
	vec4 prevNorm = vec4(0.0,0.0,0.0,0.0);
	vec3 lightDirHeadOn =  normalize(gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,0.0)).xyz ;
	float stepSizex2 = stepSize * 2.0;
	for(int i = 0; i < loops; i++) {
		gradientSample= texture3D(gradientVol,samplePos); //interpolate gradient direction and magnitude
		gradientSample.rgb = normalize(gradientSample.rgb*2.0 - 1.0); //direction saved as 0..1, rescale to -1..1
		//re-use previous normal if it has larger magnitude
		if (gradientSample.a < prevNorm.a)
			gradientSample.rgb = prevNorm.rgb;
		prevNorm = gradientSample;

		if (useTransferTexture) {
			colorSample.a = texture3D(intensityVol,samplePos).a;
			colorSample= texture1D(TransferTexture, colorSample.a).rgba;
			colorSample.a = 1.0-pow((1.0 - colorSample.a), stepSize/sliceSize);//opacity correction
		} else {
			rgbaSample = texture3D(intensityVol,samplePos);
			colorSample= texture1D(TransferTexture, rgbaSample.a).rgba;
			colorSample.a = 1.0-pow((1.0 - colorSample.a), stepSize/sliceSize);//opacity correction	 

			//temp = 1.0-pow((1.0 - gradientSample.a), stepSize/sliceSize);//opacity correction
			//temp *= colorSample.a;	
			temp = colorSample.a;
			if (temp > 0.0) { 
				temp = underlayOpacity;
			}
			opac= (1.0 - opac) * pow(temp,overlayDepth)+ opac;
			if (overlays > 0) {
				rgbaSample.r *= (1.0- opac);
				alphar= max(rgbaSample.r, alphar);
				if (overlays > 1) {
					rgbaSample.g *= (1.0- opac);
					alphag= max(rgbaSample.g, alphag);
					if (overlays > 2) {
						rgbaSample.b *= (1.0- opac);
						alphab= max(rgbaSample.b, alphab);
					
					}
				}
			}
			
			

				

			
		}
		

		if ((gradientSample.a > 0.01) && (lengthAcc > stepSizex2)  ) {
			//Edge shading - darken edges parallel with viewing direction
			float lightNormDot = dot(gradientSample.rgb, lightDirHeadOn); //with respect to viewer
			float edgeVal = pow(1.0-abs(lightNormDot),edgeExp);
			edgeVal = edgeVal * pow(gradientSample.a,0.3);
	    		if (edgeVal >= edgeThresh) 
				colorSample.rgb = mix(colorSample.rgb, vec3(0.0,0.0,0.0), pow((edgeVal-edgeThresh)/(1.0-edgeThresh),4.0));
	  	
			//specular
			lightNormDot = dot(gradientSample.rgb, lightPosition); //with respect to light location
			if (lightNormDot > 0.0)
				colorSample.rgb +=   specular * pow(max(dot(reflect(lightPosition, gradientSample.rgb), dir), 0.0), shininess);
				//previous line assumes specular color is white, if not...
				//colorSample.rgb +=   specular*specularColor * pow(max(dot(reflect(lightPosition, gradientSample.rgb), dir), 0.0), shininess);
		}

		if (boundExp > 0.0)
			colorSample.a = colorSample.a * pow(gradientSample.a,boundExp);	
		colorSample.rgb *= colorSample.a; 
		//accumulate color
		colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
		samplePos += deltaDir;
		lengthAcc += stepSize;
		//terminate if opacity > 1 or the ray is outside the volume
		if ( lengthAcc >= len ) break;
	}
	//colAcc.a = colAcc.a/0.999;
	vec4 colOverAcc;
	if ( alphar  > 0.0 ) {

		colOverAcc = texture1D(OverlayR, alphar).rgba;
		colOverAcc.a = alphar;
		colOverAcc.rgb = mix(colAcc.rgb,colOverAcc.rgb, alphar);
		if (overlayalpha  < 0.0) 
		{
			colAcc.rgb = max(colOverAcc.rgb,colAcc.rgb);
		} else {
			colAcc.rgb = mix(colOverAcc.rgb,colAcc.rgb, overlayalpha);
		}
		colAcc.a = max(alphar ,colAcc.a);  
	}
	if ( alphag  > 0.0 ) {

		colOverAcc = texture1D(OverlayG, alphag).rgba;
		colOverAcc.a = alphag;
		colOverAcc.rgb = mix(colAcc.rgb,colOverAcc.rgb, alphag);
		if (overlayalpha  < 0.0) 
		{
			colAcc.rgb = max(colOverAcc.rgb,colAcc.rgb);
		} else {
			colAcc.rgb = mix(colOverAcc.rgb,colAcc.rgb, overlayalpha);
		}
		colAcc.a = max(alphag ,colAcc.a);  
	}
	if ( alphab  > 0.0 ) {

		colOverAcc = texture1D(OverlayB, alphab).rgba;
		colOverAcc.a = alphab;
		colOverAcc.rgb = mix(colAcc.rgb,colOverAcc.rgb, alphab);
		if (overlayalpha  < 0.0) 
		{
			colAcc.rgb = max(colOverAcc.rgb,colAcc.rgb);
		} else {
			colAcc.rgb = mix(colOverAcc.rgb,colAcc.rgb, overlayalpha);
		}
		colAcc.a = max(alphab ,colAcc.a);  
	}	

	if ( colAcc.a < 1.0 )
		colAcc.rgb = mix(clearColor,colAcc.rgb,colAcc.a);
	if (len == 0.0) colAcc.rgb = clearColor;
	gl_FragColor = colAcc;
}