//<vertex>
	void main()
	{
		gl_Position = ftransform();
		gl_TexCoord[0] = gl_MultiTexCoord0;
	}
//</vertex>

//<fragment>
	uniform sampler2DRect	samMeshDepthFront;
	uniform sampler2DRect	samMeshDepthBack;
	uniform sampler2DRect	samVolumeDepthFront;
	uniform sampler2DRect	samVolumeDepthBack;

	uniform sampler2D samFront;
	uniform sampler2D samBack;
	uniform sampler3D samVolume;
	uniform sampler2D samTransferFunction;
//	uniform sampler2D samNoise;
	uniform sampler2D samResult;
	uniform sampler2D samNormalFront;
	uniform sampler2D samNormalBack;

	uniform float fSampleDistance;
	uniform float fUnitStep;
	uniform float vdRatio;
	uniform vec4 samVecMeshEdge;
	uniform vec4 samVecMeshMaterial;
	uniform vec3 vecSteps;
	uniform vec3 vecLightVolume;
	uniform vec3 vecHalfVolume;
	uniform vec3 vecLightMesh;
	uniform vec3 vecHalfMesh;
	uniform mat4 matVolume;

	uniform int isIn;
	uniform float depthDivisor;

	vec4 vecRayColor;
	float meshDepthFront;
	float meshDepthBack;
	float volumeDepthFront;
	float volumeDepthBack;

	vec4 addShading(vec4 vecColor, vec3 vecNormal, vec3 vecLight, vec3 vecHalf) {
		float fLength = length(vecNormal);
		if (fLength > 0.0) {
			vecNormal /= fLength;
			float fDiffuse = abs(dot(vecLight,vecNormal));
			vecColor.rgb *= fDiffuse;

			float fSpecular = pow(abs(dot(vecHalf,vecNormal)),32.0);
			vecColor.rgb += fSpecular;
		}
		return vecColor;
	}
	
	
	//<option name="components" value="1">
		vec4 GetColor(vec3 vecPosition)
		{
			vec4 vecSample;

			vec3 vecSampleOne;
			vecSampleOne.x = texture3D(samVolume,vecPosition-vec3(vecSteps.x,0.0,0.0)).a;
			vecSampleOne.y = texture3D(samVolume,vecPosition-vec3(0.0,vecSteps.y,0.0)).a;
			vecSampleOne.z = texture3D(samVolume,vecPosition-vec3(0.0,0.0,vecSteps.z)).a;
			vecSampleOne *= 0.5;

			vec3 vecSampleTwo;
			vecSampleTwo.x = texture3D(samVolume,vecPosition+vec3(vecSteps.x,0.0,0.0)).a;
			vecSampleTwo.y = texture3D(samVolume,vecPosition+vec3(0.0,vecSteps.y,0.0)).a;
			vecSampleTwo.z = texture3D(samVolume,vecPosition+vec3(0.0,0.0,vecSteps.z)).a;
			vecSampleTwo *= 0.5;

			vecSample.xyz = vecSampleOne - vecSampleTwo;
			vecSample.a = 0.25 * (texture3D(samVolume,vecPosition).a + vecSampleOne.x + vecSampleOne.y + vecSampleOne.z + vecSampleTwo.x + vecSampleTwo.y + vecSampleTwo.z);

			vec4 vecColor;
			vecColor = texture2D(samTransferFunction,vec2(vecSample.a,0.0));

			if (vecColor.a > 0.0)
			{   
				vec3 vecNormal = (matVolume * vec4(vecSample.x,vecSample.y,vecSample.z,0.0)).xyz;
				vecColor = addShading(vecColor, vecNormal, vecLightVolume, vecHalfVolume);
			}
			return vecColor;
		}
	//</option>

	//<option name="components" value="3">
		vec4 GetColor(vec3 vecPosition)
		{
			vec4 vecSample;
			vecSample.rgb = texture3D(samVolume,vecPosition).rgb;

			vec3 vecX = 0.5 * (texture3D(samVolume,vecPosition-vec3(vecSteps.x,0.0,0.0)).rgb - texture3D(samVolume,vecPosition+vec3(vecSteps.x,0.0,0.0)).rgb);
			vec3 vecY = 0.5 * (texture3D(samVolume,vecPosition-vec3(0.0,vecSteps.y,0.0)).rgb - texture3D(samVolume,vecPosition+vec3(0.0,vecSteps.y,0.0)).rgb);
			vec3 vecZ = 0.5 * (texture3D(samVolume,vecPosition-vec3(0.0,0.0,vecSteps.z)).rgb - texture3D(samVolume,vecPosition+vec3(0.0,0.0,vecSteps.z)).rgb);

			vec3 vecGradient;
			vecGradient.x = 0.33 * (vecX.r + vecX.g + vecX.b);
			vecGradient.y = 0.33 * (vecY.r + vecY.g + vecY.b);
			vecGradient.z = 0.33 * (vecZ.r + vecZ.g + vecZ.b);

			vec3 vecNormal = (matVolume * vec4(vecSample.x,vecSample.y,vecSample.z,0.0)).xyz;

			vecSample.a = length(vecNormal);
			return vecSample;
		}
	//</option>

	//<option name="components">
		vec4 GetColor(vec3 vecPosition)
		{
			return vec4(1.0,0.0,0.0,1.0);
		}
	//</option>

	void renderMeshEdge(vec3 vecNormalMesh) {
		vec4 vecMeshEdge = samVecMeshEdge;
		vecMeshEdge = addShading(vecMeshEdge, vecNormalMesh, vecLightMesh, vecHalfMesh);
		vecMeshEdge.a = 1.0 - pow(1.0-vecMeshEdge.a, fSampleDistance);
		vecMeshEdge.a *= (1.0 - vecRayColor.a);
		vecMeshEdge.rgb *= vecMeshEdge.a;
		vecRayColor += vecMeshEdge;
	}

	void renderMesh(float meshDistance) {
		vec4 vecMeshMaterial = samVecMeshMaterial;
		vecMeshMaterial.a = 1.0 - pow(1.0-vecMeshMaterial.a, meshDistance);
		vecMeshMaterial.a *= (1.0 - vecRayColor.a);
		vecMeshMaterial.rgb *= vecMeshMaterial.a;
		vecRayColor += vecMeshMaterial;
	}

	void renderVolume() {
		//Volume-unit stuff
		const vec4 vecFront = texture2D(samFront,gl_TexCoord[0].xy);
		const vec4 vecBack = texture2D(samBack,gl_TexCoord[0].xy);
		
		vec4 vecRayPosition = vec4(vecFront.xyz,0.0);
		float fDistance = distance(vecFront.xyz,vecBack.xyz);
		const float skipDistance = fDistance - (volumeDepthBack-meshDepthFront);
		const vec4 vecRayIncrement = vec4((vecBack.xyz - vecFront.xyz) / fDistance, 1.0) * (fSampleDistance*fUnitStep);
		if (volumeDepthBack > meshDepthBack) fDistance -= (volumeDepthBack-meshDepthBack);

		//	float fNoise = 2.0 * texture2D(samNoise,gl_FragCoord.xy / 64.0).a - 1.0;
		//	vecRayPosition += fNoise*vecRayIncrement;

		if (meshDepthFront <= volumeDepthFront) {
			<option name="renderMesh" value="1">
				//Some of the mesh is in front of the volume.		
				//renderMesh( int((volumeDepthFront-meshDepthFront)/vecRayIncrement.w) * fSampleDistance );
				renderMesh( (volumeDepthFront-meshDepthFront)/fUnitStep );
			</option>
		} else {
			//Calculate how much of the volume should be skipped
			vecRayPosition += (skipDistance/vecRayIncrement.w) * vecRayIncrement;
		}

		bool bContinue = false;

		do {
			do {
				<option name="renderMesh" value="1">
					renderMesh(fSampleDistance);
				</option>

				vec4 vecSampleColor = GetColor(vecRayPosition);
				if (vecSampleColor.a > 0.0)	{
					vecSampleColor.a = 1.0 - pow(1.0-vecSampleColor.a,fSampleDistance);
					vecSampleColor.a *= (1.0 - vecRayColor.a);
					vecSampleColor.rgb *= vecSampleColor.a;
					vecRayColor += vecSampleColor;
				}

				vecRayPosition += vecRayIncrement;
				bContinue = vecRayPosition.w < fDistance && vecRayColor.a < 1.0;
			} while (bContinue);
		} while (bContinue);

		//Render mesh behind volume
		<option name="renderMesh" value="1">
			if (volumeDepthBack < meshDepthBack) {
				//Some of the mesh is left behind the volume
				//renderMesh( int((meshDepthBack-volumeDepthBack)/vecRayIncrement.w) * fSampleDistance);
				renderMesh( (meshDepthBack-volumeDepthBack)/fUnitStep);
			}
		</option>
	}

	void main() {
	
		vecRayColor = texture2D(samResult, gl_TexCoord[0].xy);

		if (vecRayColor.a < 1.0) {
			meshDepthBack = texture2DRect(samMeshDepthBack, gl_FragCoord.st);
			meshDepthFront = texture2DRect(samMeshDepthFront, gl_FragCoord.st);

			if (meshDepthBack > meshDepthFront) {

				meshDepthBack *= depthDivisor;
				meshDepthFront *= depthDivisor;
				volumeDepthBack = texture2DRect(samVolumeDepthBack, gl_FragCoord.st) * depthDivisor;
				volumeDepthFront = texture2DRect(samVolumeDepthFront, gl_FragCoord.st) * depthDivisor;

				<option name="renderMesh" value="1">
					vec3 vecNormalMesh;
					if (samVecMeshEdge.a > 0.0) {
						vecNormalMesh = texture2D(samNormalFront, gl_TexCoord[0].xy).xyz;
						renderMeshEdge(vecNormalMesh);
					}
				</option>

				<option name="passType" value="0">		//Render volume only
					if (volumeDepthBack > volumeDepthFront) renderVolume();
				</option>
				<option name="passType" value="1">		//Render mesh only
					//renderMesh( (meshDepthBack-meshDepthFront)/(fSampleDistance*fUnitStep) * fSampleDistance);
					renderMesh( (meshDepthBack-meshDepthFront)/fUnitStep );
				</option>
				<option name="passType" value="2">		//Render volume only
					if (volumeDepthBack > volumeDepthFront) renderVolume();
				</option>
				<option name="passType" value="3">		//Render volume and mesh
					if (meshDepthBack <= volumeDepthFront || 
						volumeDepthBack <= volumeDepthFront ||
						volumeDepthBack <= meshDepthFront) {
						//Render all of the mesh, nothing is mixed with volume
			//			renderMesh( (meshDepthBack-meshDepthFront)/(fSampleDistance*fUnitStep) * fSampleDistance);
						renderMesh( (meshDepthBack-meshDepthFront)/fUnitStep );
					}
					else if (volumeDepthBack > volumeDepthFront) {
						renderVolume();
					}
				</option>

				<option name="renderMesh" value="1">
					vecNormalMesh = texture2D(samNormalBack, gl_TexCoord[0].xy).xyz;
					if (samVecMeshEdge.a > 0.0) renderMeshEdge(vecNormalMesh);
				</option>
			}
		}

		gl_FragColor = vecRayColor;
	}
</fragment>