//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float3	g_LightPos;			        // Light's position in world space
float3	g_LightDir;
float4	g_LightDiffuse;				// Light's diffuse color
float3	g_LightAttenuation;

float3	g_Diffuse;

float3	g_CamPos;					// Camera position
float3	g_CamDir;					// Camera direction
float3	g_CamUp;						// Camera up direction
float3	g_CamRight;					// Camera right direction

float3	g_time;						// x = time, y = prevTime, z = dt

float4 g_DepthLayers;				// x = front depth, y = back depth, z = incr. depth

//const float4 g_DepthLayers = float4(2.0,3.0,0.25,0.0);

float3	g_vExplosionPosition;
float	g_fShockWaveSize;
float	g_fShockWaveStrength;
float	g_fGlowStrength;
float	g_fExplosionAlpha;

texture g_NoiseMap;					// Noise texture
texture g_ColourMap;				// Colour gradient texture
texture g_SplatTex1;				// Iso-surface field texture 
texture g_SplatTex2;				// Iso-surface field texture 
texture g_SplatTex3;				// Iso-surface field texture 
texture g_SplatTex4;				// Iso-surface field texture 
texture g_SurfaceDepth;				// Depth of surface (in layer-space)
texture g_SurfaceColour;			// Colour field for surface (x = num contributors, y = sum total contribution)
texture	g_depthTexture;				// Depth of scene
texture	g_sourceTexture;			// Source for refraction map

float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mWorldViewProjection;    // World * View * Projection matrix
float4x4 g_mWorldViewProjectionPrev;
float4x4 g_mViewProjectionInv;		

float4x4 g_mWorldToLightProj;		// Matrix to transform from world space to lights projection space


//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler NoiseMapSampler = 
sampler_state
{
    Texture = <g_NoiseMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
};

sampler ColourMapSampler = 
sampler_state
{
    Texture = <g_ColourMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SplatTexSampler1 = 
sampler_state
{
    Texture = <g_SplatTex1>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SplatTexSampler2 = 
sampler_state
{
    Texture = <g_SplatTex2>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SplatTexSampler3 = 
sampler_state
{
    Texture = <g_SplatTex3>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SplatTexSampler4 = 
sampler_state
{
    Texture = <g_SplatTex4>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SurfaceDepthSampler = 
sampler_state
{
    Texture = <g_SurfaceDepth>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SurfaceColourSampler = 
sampler_state
{
    Texture = <g_SurfaceColour>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler SourceSampler = 
sampler_state
{
    Texture = <g_sourceTexture>;
    MinFilter = Linear;  
    MagFilter = Linear;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler DepthSampler = 
sampler_state
{
    Texture = <g_depthTexture>;
    MinFilter = Linear;  
    MagFilter = Linear;

    AddressU = Clamp;
    AddressV = Clamp;
};

//--------------------------------------------------------------------------------------
// Vertex shader output structure/s
//--------------------------------------------------------------------------------------s
struct VS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position 
    float3 ScreenPos	: TEXCOORD0;	// Un-normalised light vector in world space
    float4 PosLight		: TEXCOORD1;	// Fragment position in light's projection space
    float2 LocalPos		: TEXCOORD2;
    float2 TexUV		: TEXCOORD3;
    float2 Depth		: TEXCOORD4;
};

struct VS_OUTPUT_GLOW
{
    float4 Position		: POSITION;		// vertex position 
    float3 Normal		: TEXCOORD0;	// Normal vector outwards from sphere
    float3 WorldPos		: TEXCOORD1;	// World position
    float3 ScreenPos	: TEXCOORD2;	// Screen position
};

struct WriteVelocityVS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position 
    float2 Velocity		: TEXCOORD0;
};

const float fSize = 0.40;

//--------------------------------------------------------------------------------------
// 
//--------------------------------------------------------------------------------------

VS_OUTPUT_GLOW GlowVS(	float4 vPos : POSITION, 
						float3 vNormal : NORMAL, 
						float2 vTexCoord0 : TEXCOORD0 )
{
    VS_OUTPUT_GLOW Output;
   
   
	// Test if position is behind the viewing plane, if it is then move vertex back along sphere to sit on plane
   
	vPos.xyz *= g_fShockWaveSize;
	
   	vPos.xyz += g_vExplosionPosition;
    
    Output.WorldPos = vPos;
    
	Output.Position = mul(vPos, g_mWorldViewProjection);   // Projection space   
         
	Output.Normal = vNormal; // Normal in world space
	
	float fInvW = 1.0f / Output.Position.w;
	
	// Calculate screen space position of vertex
	Output.ScreenPos = Output.Position.xyz * fInvW * 0.5 + float3(0.5,0.5,0.0);
	
	// Negate y-axis to conform with windows coordinates
	Output.ScreenPos.y = 1.0 - Output.ScreenPos.y;
	
	// Adjust by Direct 3D's half a pixel offset convention
	Output.ScreenPos.xy += float2( +0.5/800.0, +0.5/600.0 );
	
    return Output;    
}


VS_OUTPUT RenderSceneVS( float4 vPos : POSITION, 
                         float2 vTexCoord0 : TEXCOORD0, 
                         float3 vTexCoord1 : TEXCOORD1 )
{
    VS_OUTPUT Output;

	float3 vUp = float3(0,1,0);
	float3 vSide = normalize( cross( vUp, g_CamDir ) );
	vUp = normalize( cross( g_CamDir, vSide ) );
	
	float3 vIn = cross( vUp, vSide );
	
	float4 vNewPos = vPos;
	
	float fParticleSize = fSize * vTexCoord1.y;
	
	vNewPos.xyz = vNewPos.xyz + (vSide*(vTexCoord0.x*fParticleSize)) + (vUp*(vTexCoord0.y*fParticleSize));
	
	Output.LocalPos = vTexCoord0;
	
    // Transform the position from object space to homogeneous projection space
	Output.Position = mul(vNewPos, g_mWorldViewProjection);      
   
    // Calculate world position
    float3 vWorldPos = mul(vPos, g_mWorld); // position (world space)   
        
	// Copy texture coordinate through
	//Output.TextureUV = vTexCoord1.x; 
				
	// Transform fragment position to lights projection space
	Output.PosLight.xyz = vWorldPos;//mul( vNewPos, g_mWorldToLightProj );
	Output.PosLight.w = 0;
		
	Output.TexUV = vTexCoord1.xy;

	vNewPos.xyz = vPos.xyz + vIn * (fParticleSize * 0.5);
	vNewPos.w = 1;
	
	float4 vFrontPosition = mul(vNewPos, g_mWorldViewProjection);      
   
   Output.Depth.x = length( (g_CamPos - vWorldPos) );
   Output.Depth.y = Output.Depth.x;
	//Output.Depth.x = Output.Position.z / Output.Position.w;
	//Output.Depth.y = Output.Depth.x - vFrontPosition.z / vFrontPosition.w;
	
	float fInvW = 1.0f / Output.Position.w;
	
	Output.ScreenPos = Output.Position.xyz * fInvW * 0.5 + float3(0.5,0.5,0.0);
	Output.ScreenPos.y = 1.0 - Output.ScreenPos.y;
	
	
    return Output;    
}

//--------------------------------------------------------------------------------------
// Pixel shader output structure/s
//--------------------------------------------------------------------------------------
struct PS_OUTPUT_DEPTH
{
    float4	RGBColor : COLOR0;  // Pixel color    
    float	Depth	 : DEPTH;
};

struct PS_OUTPUT
{
    float4	RGBColor : COLOR0;  // Pixel color    
};
struct PS_OUTPUT2
{
    float4	RGBColor[2] : COLOR0;  // Pixel color    
};
struct PS_OUTPUT3
{
    float4	RGBColor[3] : COLOR0;  // Pixel color    
};
struct PS_OUTPUT4
{
    float4	RGBColor[4] : COLOR0;  // Pixel color    
};


//--------------------------------------------------------------------------------------
// 
//--------------------------------------------------------------------------------------
float4 CopyPS( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
	return tex2D( SourceSampler, OriginalUV );    
}

PS_OUTPUT GlowPS( VS_OUTPUT_GLOW In ) 
{ 
    PS_OUTPUT Output;                     	

	float fSurfaceDepth = tex2D(DepthSampler, In.ScreenPos ).x;
	
	if (fSurfaceDepth < 0.01)
	{
		fSurfaceDepth = 100.0;
	}
		
	float3 vGlowColour = float3(1.0,0.8,0.4);                     				
	
	float3 vFragWorldPos = g_vExplosionPosition + In.Normal * g_fShockWaveSize;
	
	float3 fToFrag = vFragWorldPos - g_CamPos;
	
	float fDistance = length( fToFrag );
	
	
	float3 vFragDir = fToFrag / fDistance;
	
	float3 l = g_vExplosionPosition - g_CamPos;
	float d = dot(l,vFragDir);
	
	float fSphereDepth = 2.0*(d - fDistance);
		
	vGlowColour *= pow( fSphereDepth / (2.0*g_fShockWaveSize), 8.0 );
	
	float fBackDist = fDistance + fSphereDepth;
	
	fBackDist = min( fBackDist, fSurfaceDepth );	
	
	float fDepth = pow(fBackDist - fDistance, 1.0);
	
	//fDepth = saturate(fDepth);
	
	vGlowColour *= fDepth * g_fGlowStrength * 0.5;

	float fRefractionAmount = pow( 1.0 - abs( dot( vFragDir, In.Normal ) ), 6.0 );

	float2 vRefrTexCoords = In.ScreenPos + float2( In.Normal.x, -In.Normal.y ) * fRefractionAmount * g_fShockWaveStrength * 0.6;
	
	Output.RGBColor.rgb = tex2D(SourceSampler, vRefrTexCoords ).rgb + vGlowColour;
	Output.RGBColor.a = 1;
	
    return Output;
}

PS_OUTPUT QuadGlowPS( float2 OriginalUV : TEXCOORD0 ) 
{ 
    PS_OUTPUT Output;                     	
		
	float fFrontDist = 0.0f;
	float fBackDist = tex2D(DepthSampler, OriginalUV ).x;;
	
	if (fBackDist < 0.01)
	{
		// Account for infinte distance objects (e.g. skybox)
		fBackDist = 100.0;
	}
	
	// Calculate fragment direction using camera tangent basis vectors
	float2 vScreenSpace = OriginalUV; 
	vScreenSpace.y = 1.0f - vScreenSpace.y;
	vScreenSpace -= float3(0.5,0.5,0.0);
	float3 vFragDir = g_CamDir + g_CamRight*(vScreenSpace.x*4/3) + g_CamUp*vScreenSpace.y;
	vFragDir = normalize( vFragDir );
	
	// Calculate fragment direction using inverse view-projection matrix
	//float4 vTemp = mul( g_mViewProjectionInv,  float4( OriginalUV.x, OriginalUV.y, 0.0, 1.0 ) );
	//float3 vFragDir = float3(vTemp.x,vTemp.y,vTemp.z);
	//vFragDir = normalize(vFragDir - g_CamPos);
	
	// Ray sphere intersection for refraction and glow sphere
	float3 l = g_vExplosionPosition - g_CamPos;
		
	float d = dot(l,vFragDir);
		
	float l2 = dot(l,l);
		
	float r2 = g_fShockWaveSize*g_fShockWaveSize;
		
	if (d < 0.0f && l2 > r2)
	{
		fBackDist = 0.0f;
	}
	
	float m2 = l2 - (d*d);
	
	if (m2 > r2)
	{
		fBackDist = 0.0f;
	}
		
	float q = sqrt( r2-m2);
		
	fFrontDist = max( d-q, fFrontDist );
	fBackDist = min( d+q, fBackDist );
	
	float fDepth = fBackDist - fFrontDist;
		
	// Calculate glow colour
	float3 vGlowColour = float3(1.0,0.8,0.4) * pow( 2.0*q / (2.0*g_fShockWaveSize), 8.0 ) * saturate(fDepth) * g_fGlowStrength * 1.5;

	float2 vRefrTexCoords = OriginalUV;
	
	if (fDepth > 0.01f)
	{
		// Calculate screen-space refraction coordinates
		float3 vSphereNormal = normalize( (g_CamPos + vFragDir*(d-q)) - g_vExplosionPosition );

		float fRefractionAmount = pow( 1.0 - abs( dot( vFragDir, vSphereNormal ) ), 4.0 );

		vRefrTexCoords = OriginalUV + float2( vSphereNormal.x, -vSphereNormal.y ) * fRefractionAmount * g_fShockWaveStrength * 1.5;
	}

	// Calculate final output colour
	Output.RGBColor.rgb = tex2D(SourceSampler, vRefrTexCoords ).rgb + saturate(vGlowColour);
	Output.RGBColor.a = 1;

    return Output;
}

PS_OUTPUT_DEPTH RenderScenePS( VS_OUTPUT In ) 
{ 
    PS_OUTPUT_DEPTH Output;                     	
                     				
    // Lookup mesh texture and modulate it with diffuse

	//Output.RGBColor.rgb = tex2D(DiffuseMapSampler, In.TextureUV) * g_LightDiffuse * g_Diffuse;
	
	float fCenterDist = (0.2 - length( In.LocalPos )) * 5.0;
	
	// Clip edges
	clip( fCenterDist );
	

	float2 texLookup;
	
	// Get noise value	
	texLookup.y = tex3D(NoiseMapSampler, In.PosLight.xyz * 5).x;
	
	texLookup.x = In.TexUV.x;
	
	// Get colour from gradient texture
	Output.RGBColor.rgb = tex2D(ColourMapSampler, texLookup) * 1.8;
	

	//Output.RGBColor.rgb *= saturate( (0.2 - length( In.LocalPos ))*5.0 );
	
	Output.RGBColor.a = 1; 
	
	// Set depth (depth replace)
	Output.Depth = In.Depth.x - saturate( (0.2 - length( In.LocalPos ))*5.0 ) * In.Depth.y;
	
    return Output;
}

float CalculateGaussian( float2 vOffset )
{
	//float fGauss = exp( -30.0 * (vOffset.x*vOffset.x + vOffset.y*vOffset.y) ) - 0.4;
	
	//float fGauss = saturate( 5.0 * (0.2 - length( vOffset )) );
	
	float fDist = saturate( length( vOffset ) * 5.0 );

	float fGauss = 1.0 - saturate( -2.0*fDist*fDist*fDist + 3.0*fDist*fDist );

	return saturate( fGauss );
}

float GetFragmentLayerDepth( float fDepth, float fNumLayers )
{
	float fLayerSize = (g_DepthLayers.y - g_DepthLayers.x) * (1.0f / fNumLayers);
	
	return (fDepth - g_DepthLayers.x) / fLayerSize;
}

float4 CalculateLayerStrengths( float fLayerDepth, float4 fLayers )
{
	return saturate( 2.0 - 2.0*abs(fLayers - fLayerDepth) );
	
	// 1.0 - saturate( -2.0*fDist*fDist*fDist + 3.0*fDist*fDist );
}

PS_OUTPUT SplatParticleIso4( VS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;
                     				
    float4 fGaussStrength = CalculateGaussian( In.LocalPos );
                 				
	// Find fragments layer depth
		
	float1 fLayerDepth = GetFragmentLayerDepth( In.Depth.x, 4.0 );
	
	// Calculate strength for first 4 layers
	
	float4 fLayers = float4(0,1,2,3);
	
	Output.RGBColor = CalculateLayerStrengths( fLayerDepth, fLayers ) * fGaussStrength;
						
    return Output;
}

PS_OUTPUT2 SplatParticleIso8MRT( VS_OUTPUT In ) 
{ 
    PS_OUTPUT2 Output;
                 				
    float4 fGaussStrength = CalculateGaussian( In.LocalPos );
                 				
	// Find fragments layer depth
		
	float1 fLayerDepth = GetFragmentLayerDepth( In.Depth.x, 8.0 );
	
	// Calculate layer strengths
		
	Output.RGBColor[0] = CalculateLayerStrengths( fLayerDepth, float4(0,1,2,3) ) * fGaussStrength;
				
	Output.RGBColor[1] = CalculateLayerStrengths( fLayerDepth, float4(4,5,6,7) ) * fGaussStrength;
			
    return Output;
}

PS_OUTPUT3 SplatParticleIso12MRT( VS_OUTPUT In ) 
{ 
    PS_OUTPUT3 Output;
                 				
    float4 fGaussStrength = CalculateGaussian( In.LocalPos );
                 				
	// Find fragments layer depth
		
	float1 fLayerDepth = GetFragmentLayerDepth( In.Depth.x, 12 );
	
	// Calculate layer strengths
		
	Output.RGBColor[0] = CalculateLayerStrengths( fLayerDepth, float4(0,1,2,3) ) * fGaussStrength;
				
	Output.RGBColor[1] = CalculateLayerStrengths( fLayerDepth, float4(4,5,6,7) ) * fGaussStrength;
			
	Output.RGBColor[2] = CalculateLayerStrengths( fLayerDepth, float4(8,9,10,11) ) * fGaussStrength;
	
    return Output;
}
 
PS_OUTPUT4 SplatParticleIso16MRT( VS_OUTPUT In ) 
{ 
    PS_OUTPUT4 Output;
                 				
    float4 fGaussStrength = CalculateGaussian( In.LocalPos );
                 				
	// Find fragments layer depth
		
	float1 fLayerDepth = GetFragmentLayerDepth( In.Depth.x, 16 );
	
	// Calculate layer strengths
		
	Output.RGBColor[0] = CalculateLayerStrengths( fLayerDepth, float4(0,1,2,3) ) * fGaussStrength;
				
	Output.RGBColor[1] = CalculateLayerStrengths( fLayerDepth, float4(4,5,6,7) ) * fGaussStrength;
	
	Output.RGBColor[2] = CalculateLayerStrengths( fLayerDepth, float4(8,9,10,11) ) * fGaussStrength;
		
	Output.RGBColor[3] = CalculateLayerStrengths( fLayerDepth, float4(12,13,14,15) ) * fGaussStrength;
	
    return Output;
}

PS_OUTPUT SplatParticleColour( VS_OUTPUT In, uniform float iNumLayers ) 
{ 
    PS_OUTPUT Output;
                 				
    float4 fGaussStrength = CalculateGaussian( In.LocalPos );
                 				
	// Find fragments layer depth
		
	float1 fLayerDepth = GetFragmentLayerDepth( In.Depth.x, iNumLayers );
	
	// Get surface depth
	
	float fSurfaceDepth = tex2D(SurfaceDepthSampler, In.ScreenPos ).x;
	
	Output.RGBColor = fGaussStrength * CalculateLayerStrengths( fLayerDepth, float4(fSurfaceDepth,fSurfaceDepth,fSurfaceDepth,fSurfaceDepth) );
	
	Output.RGBColor.y = Output.RGBColor.x * In.TexUV.x;
				
    return Output;
}

float CalculateIntersectionPoint( float fFieldA, float fFieldB, float fFieldC, float fFieldD, float fFieldE, float fIsoValue, float4 fDepthLayers )
{
	float4 fGaussA = float4( fFieldD, fFieldC, fFieldB, fFieldA );
    float4 fGaussB = float4( fFieldE, fFieldD, fFieldC, fFieldB );
	
    float4 fIntersectPoints = (float4(fIsoValue,fIsoValue,fIsoValue,fIsoValue) - fGaussA) / (fGaussB - fGaussA + 0.001);
	
    fIntersectPoints += (fIntersectPoints.xyzw < 0) ? 100000.0 : 0.0;
	
    fIntersectPoints += (fIntersectPoints.xyzw > 1) ? 100000.0 : 0.0;
	
    fIntersectPoints += fDepthLayers;
	
    fIntersectPoints = min(fIntersectPoints.xyyy,fIntersectPoints.zwww);
    
    float fDepth = min(fIntersectPoints.xxxx,fIntersectPoints.yyyy).x;
	
	return fDepth;	
}

PS_OUTPUT DrawSurfaceDepth8( float2 OriginalUV : TEXCOORD0 ) 
{ 
    PS_OUTPUT Output;
   
    float4 fGauss1 = tex2D(SplatTexSampler1, OriginalUV );
    float4 fGauss2 = tex2D(SplatTexSampler2, OriginalUV );
    
    Output.RGBColor = float4(1,0.8,0,0);
                
    float fDepth = CalculateIntersectionPoint( fGauss1.a, fGauss2.x, fGauss2.y, fGauss2.z, fGauss2.a, 0.3, float4(7,6,5,4) );
    
    float fTempDepth = CalculateIntersectionPoint( 0, fGauss1.x, fGauss1.y, fGauss1.z, fGauss1.a, 0.3, float4(3,2,1,0) );
 
	fDepth = min( fDepth, fTempDepth );

	float fAlpha = fGauss1.x + fGauss1.y + fGauss1.z + fGauss1.a;
	fAlpha		+= fGauss2.x + fGauss2.y + fGauss2.z + fGauss2.a;
	
	Output.RGBColor = float4(fDepth,fAlpha,0,0);
		
    return Output;
}
  
PS_OUTPUT DrawSurfaceDepth12( float2 OriginalUV : TEXCOORD0 ) 
{ 
    PS_OUTPUT Output;
   
    float4 fGauss1 = tex2D(SplatTexSampler1, OriginalUV );
    float4 fGauss2 = tex2D(SplatTexSampler2, OriginalUV );
    float4 fGauss3 = tex2D(SplatTexSampler3, OriginalUV );
    
    Output.RGBColor = float4(1,0.8,0,0);
        
    float fDepth = CalculateIntersectionPoint( fGauss2.a, fGauss3.x, fGauss3.y, fGauss3.z, fGauss3.a, 0.3, float4(11,10,9,8) );
    
    float fTempDepth = CalculateIntersectionPoint( fGauss1.a, fGauss2.x, fGauss2.y, fGauss2.z, fGauss2.a, 0.3, float4(7,6,5,4) );
 
	fDepth = min( fDepth, fTempDepth );
	
	fTempDepth = CalculateIntersectionPoint( 0, fGauss1.x, fGauss1.y, fGauss1.z, fGauss1.a, 0.3, float4(3,2,1,0) );
 
	fDepth = min( fDepth, fTempDepth );


	float fAlpha = fGauss1.x + fGauss1.y + fGauss1.z + fGauss1.a;
	fAlpha		+= fGauss2.x + fGauss2.y + fGauss2.z + fGauss2.a;
	fAlpha		+= fGauss3.x + fGauss3.y + fGauss3.z + fGauss3.a;
	
	Output.RGBColor = float4(fDepth,fAlpha,0,0);
		
    return Output;
}

PS_OUTPUT DrawSurfaceDepth16( float2 OriginalUV : TEXCOORD0 ) 
{ 
    PS_OUTPUT Output;
   
    float4 fGauss1 = tex2D(SplatTexSampler1, OriginalUV );
    float4 fGauss2 = tex2D(SplatTexSampler2, OriginalUV );
    float4 fGauss3 = tex2D(SplatTexSampler3, OriginalUV );
    float4 fGauss4 = tex2D(SplatTexSampler4, OriginalUV );
     
    Output.RGBColor = float4(1,0.8,0,0);
            
	float fDepth = CalculateIntersectionPoint( fGauss3.a, fGauss4.x, fGauss4.y, fGauss4.z, fGauss4.a, 0.3, float4(15,14,13,12) );
    
	float fTempDepth = CalculateIntersectionPoint( fGauss2.a, fGauss3.x, fGauss3.y, fGauss3.z, fGauss3.a, 0.3, float4(11,10,9,8) );
 
	fDepth = min( fDepth, fTempDepth );
	
    fTempDepth = CalculateIntersectionPoint( fGauss1.a, fGauss2.x, fGauss2.y, fGauss2.z, fGauss2.a, 0.3, float4(7,6,5,4) );
 
	fDepth = min( fDepth, fTempDepth );
	
	fTempDepth = CalculateIntersectionPoint( 0, fGauss1.x, fGauss1.y, fGauss1.z, fGauss1.a, 0.3, float4(3,2,1,0) );
 
	fDepth = min( fDepth, fTempDepth );

	float fAlpha = fGauss1.x + fGauss1.y + fGauss1.z + fGauss1.a;
	fAlpha		+= fGauss2.x + fGauss2.y + fGauss2.z + fGauss2.a;
	fAlpha		+= fGauss3.x + fGauss3.y + fGauss3.z + fGauss3.a;
	fAlpha		+= fGauss4.x + fGauss4.y + fGauss4.z + fGauss4.a;
	
	Output.RGBColor = float4(fDepth,fAlpha,0,0);
		
    return Output;
}

PS_OUTPUT DrawFinalColourSurface( float2 OriginalUV : TEXCOORD0 ) 
{ 
    PS_OUTPUT Output;
   
	// Read depth
	
	float2 fSurfaceDepth = tex2D(SurfaceDepthSampler, OriginalUV ).xy;
		
	// Read colour field
	
	float2 fColourField = tex2D(SurfaceColourSampler, OriginalUV ).xy;
	
	// Calculate output colour
		
	if (fColourField.x > 0)
	{
		float3 vDir = normalize( g_CamDir + (g_CamRight * (OriginalUV.x - 0.5)) + (g_CamUp * (0.5 - OriginalUV.y) ) );
	
		float fLayerSize = (g_DepthLayers.y - g_DepthLayers.x) / 8.0;
	
		float3 vWorldPos = g_CamPos + vDir * (g_DepthLayers.x + fLayerSize*fSurfaceDepth.x);
     
		vWorldPos.z += g_time.x * 0.00001;
     		
		float fRedFactor = tex3D(NoiseMapSampler, vWorldPos * 6.0).x;
		    
      		float3 vFireColour = 2.0 * lerp( float3(2.5,2.0,0.7), float3(2.0,0.2,0.1), float3(fRedFactor,fRedFactor,fRedFactor) );				
		float fTemperature = saturate( pow(fColourField.y / fColourField.x, 1.2) );	
		
		float3 vSmokeColour = float3(0.4,0.1,0.1) * 0.1;//* 0.4 * tex3D(NoiseMapSampler, vWorldPos * 2.5).x;
	
		
		vFireColour *= 1.8 * (tex3D(NoiseMapSampler, vWorldPos * 5.0).x  +  tex3D(NoiseMapSampler, vWorldPos * 9.0).x);		

		Output.RGBColor.rgb = lerp( vSmokeColour, vFireColour, float3(fTemperature,fTemperature,fTemperature) );
			
		Output.RGBColor.a = saturate( (fSurfaceDepth.y-0.3) / 3.5 ) * g_fExplosionAlpha;
	}	
		
	return Output;
}
	
	

  
//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------

technique AmbientPass_High
{
    pass P0
    {        
        VertexShader = compile vs_2_0 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS();
    }
}

technique AmbientPass_Medium
{
    pass P0
    {        
        VertexShader = compile vs_2_0 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS();
    }
}

technique Copy
{
    pass P0
    {        
        PixelShader = compile ps_2_0 CopyPS();
    }
}

technique Glow
{
    pass P0
    {        
        VertexShader = compile vs_1_1 GlowVS();
        PixelShader  = compile ps_2_0 GlowPS();
    }
}

technique QuadGlow
{
    pass P0
    {        
        PixelShader  = compile ps_2_0 QuadGlowPS();
    }
}
/*
technique IsoSurface4
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleIso4();
    }
    pass P1
    {        
        PixelShader  = compile ps_2_0 DrawSurface4();
    }
}
*/
/*
technique IsoSurface8MRT
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleIso8MRT();
    }
    pass P1
    {        
        PixelShader  = compile ps_2_0 DrawSurface8();
    }
}

technique IsoSurface12MRT
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleIso12MRT();
    }
    pass P1
    {        
        PixelShader  = compile ps_2_0 DrawSurface12();
    }
}
*/

technique IsoSurface8ColourMRT
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleIso8MRT();
    }
    pass P1
    {        
        PixelShader  = compile ps_2_0 DrawSurfaceDepth8();
    }
    pass P2
    {
		VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleColour( 8 );
    }
    pass P3
    {        
        PixelShader  = compile ps_3_0 DrawFinalColourSurface();
    }
}

technique IsoSurface12ColourMRT
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_3_0 SplatParticleIso12MRT();
    }
    pass P1
    {        
        PixelShader  = compile ps_3_0 DrawSurfaceDepth12();
    }
    pass P2
    {
		VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleColour( 12 );
    }
    pass P3
    {        
        PixelShader  = compile ps_3_0 DrawFinalColourSurface();
    }
}

technique IsoSurface16ColourMRT
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_3_0 SplatParticleIso16MRT();
    }
    pass P1
    {        
        PixelShader  = compile ps_3_0 DrawSurfaceDepth16();
    }
    pass P2
    {
		VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 SplatParticleColour( 16 );
    }
    pass P3
    {        
        PixelShader  = compile ps_3_0 DrawFinalColourSurface();
    }
}