//*********************************************************
// Post-Processor Bloom Shader.
// mittens and FX Composer.
//*********************************************************
float4 ClearColor <
string UIWidget = "Color";
string UIName = "Background";
> = { 0.0, 0.0, 0.0, 0.0 };

float4 ClearColor_White <
string UIWidget = "ColorWhite";
string UIName = "BackgroundWhite";
> = { 1.0, 1.0, 1.0, 1.0 };

float ClearDepth <string UIWidget = "none";> = 1.0;

#include <include\\color_spaces.fxh>
#include <include\\Quad.fxh>

int ActiveTechnique <
string UIWidget = "ActiveTechnique";
string UIName = "ActiveTechnique";
> = 0;

float Script : STANDARDSGLOBAL
<
string UIWidget = "none";
string ScriptClass = "scene";
string ScriptOrder = "postprocess";
string ScriptOutput = "color";

// We just call a script in the main technique.
string Script = "Technique=ActiveTechnique?MapGlow:MapGlowPrePause:MapPause;";
> = 0.8;

//*****************************************************************************
// Tweakables.
float BlurWidth <
string UIName = "Blur width";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 10.0f;
float UIStep = 0.5f;
> = 2.0f;

float NPixels <
string UIName = "Edge Pixels Steps";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 0.5f;
> = 4.0f;

float Threshhold <
string UIName = "Edge Threshhold";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.001f;
> = 0.99;

float4 GlowColor <
string UIName = "Edge Threshhold";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.001f;
> = float4( 1.0f, 1.0f, 1.0f, 1.0f );

float2 WindowSize : VIEWPORTPIXELSIZE < string UIWidget = "none"; >;
float downsampleScale < string UIWidget = "none"; > = 0.5;

//*****************************************************************************
// Texture and Sampler Data.
texture SceneMap : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 1.0, 1.0 };
int MIPLEVELS = 1;
string format = "X8R8G8B8";
>;
texture PauseMap : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 1.0, 1.0 };
int MIPLEVELS = 1;
string format = "X8R8G8B8";
>;
texture DepthMap : RENDERDEPTHSTENCILTARGET
<
float2 ViewportRatio = { 1.0, 1.0 };
string format = "D24S8";
>;

texture DepthMapNoMS : RENDERDEPTHSTENCILTARGET
<
float2 ViewportRatio = { 1.0, 1.0 };
string format = "D24S8";

int Multisampled = 0;
>;

sampler SceneSampler = sampler_state 
{
	texture = <SceneMap>;
	AddressU  = CLAMP;        
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

sampler PauseSampler = sampler_state 
{
	texture = < PauseMap >;
	AddressU  = CLAMP;        
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

texture MapRenderTexture : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 1.0, 1.0 };
int MIPLEVELS = 1;
string format = "A8R8G8B8";

int Multisampled = 0;
>;

sampler MapRenderSampler = sampler_state 
{
	texture = < MapRenderTexture >;
	AddressU  = CLAMP;        
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

texture MapOutlineTexture : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 1.0, 1.0 };
int MIPLEVELS = 1;
string format = "A8R8G8B8";

int Multisampled = 0;
>;

sampler MapOutlineSampler = sampler_state 
{
	texture = < MapOutlineTexture >;
	AddressU  = CLAMP;
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

texture HBlurMap : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 0.5, 0.5 };
int MIPLEVELS = 1;
string format = "A8R8G8B8";

int Multisampled = 0;
>;

sampler HBlurSampler = sampler_state 
{
	texture = <HBlurMap>;
	AddressU  = CLAMP;        
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

texture FinalBlurMap : RENDERCOLORTARGET
< 
float2 ViewportRatio = { 0.5, 0.5 };
int MIPLEVELS = 1;
string format = "A8R8G8B8";

int Multisampled = 0;
>;

sampler FinalBlurSampler = sampler_state 
{
	texture = <FinalBlurMap>;
	AddressU  = CLAMP;        
	AddressV  = CLAMP;
	AddressW  = CLAMP;
	MIPFILTER = NONE;
	MINFILTER = LINEAR;
	MAGFILTER = LINEAR;
};

//*****************************************************************************
// Structures.
struct VS_OUTPUT_BLUR
{
	float4 Position		: POSITION;
	float2 TexCoord[8]	: TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 Position		: POSITION;
	float2 TexCoord0	: TEXCOORD0;
	float2 TexCoord1	: TEXCOORD1;
};

struct EdgeVertexOutput
{
	QUAD_REAL4 Position	: POSITION;
	QUAD_REAL2 UV00		: TEXCOORD0;
	QUAD_REAL2 UV01		: TEXCOORD1;
	QUAD_REAL2 UV02		: TEXCOORD2;
	QUAD_REAL2 UV10		: TEXCOORD3;
	QUAD_REAL2 UV12		: TEXCOORD4;
	QUAD_REAL2 UV20		: TEXCOORD5;
	QUAD_REAL2 UV21		: TEXCOORD6;
	QUAD_REAL2 UV22		: TEXCOORD7;
};

//*****************************************************************************
// Edge Detection Programs.
EdgeVertexOutput edgeVS( QUAD_REAL3 Position : POSITION, 
						QUAD_REAL3 TexCoord : TEXCOORD0 )
{
	EdgeVertexOutput OUT;
	OUT.Position = QUAD_REAL4(Position.xyz, 1);
	QUAD_REAL2 ctr = TexCoord.xy + QuadTexelOffsets;
	QUAD_REAL2 ox = QUAD_REAL2(NPixels/QuadScreenSize.x,0.0);
	QUAD_REAL2 oy = QUAD_REAL2(0.0,NPixels/QuadScreenSize.y);
	OUT.UV00 = ctr - ox - oy;	//Southwest.
	OUT.UV01 = ctr - oy;		//South.
	OUT.UV02 = ctr + ox - oy;	//Southeast.
	OUT.UV10 = ctr - ox;		//West.
	OUT.UV12 = ctr + ox;		//East.
	OUT.UV20 = ctr - ox + oy;	//Northwest.
	OUT.UV21 = ctr + oy;		//North.
	OUT.UV22 = ctr + ox + oy;	//Northeast.
	return OUT;
}

QUAD_REAL getGray(QUAD_REAL4 c)
{
	return( dot( c.rgb, ( ( 0.33333 ).xxx ) ) );
}

QUAD_REAL4 edgeDetectPS( EdgeVertexOutput IN,
						uniform sampler2D ColorMap,
						uniform QUAD_REAL T2 ) : COLOR
{
	QUAD_REAL4 CC;
	CC = tex2D( ColorMap, IN.UV00 ); QUAD_REAL g00 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV01 ); QUAD_REAL g01 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV02 ); QUAD_REAL g02 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV10 ); QUAD_REAL g10 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV12 ); QUAD_REAL g12 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV20 ); QUAD_REAL g20 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV21 ); QUAD_REAL g21 = getGray( CC );
	CC = tex2D( ColorMap, IN.UV22 ); QUAD_REAL g22 = getGray( CC );
	QUAD_REAL sx = 0;
	sx -= g00;
	sx -= g01 * 2;
	sx -= g02;
	sx += g20;
	sx += g21 * 2;
	sx += g22;
	QUAD_REAL sy = 0;
	sy -= g00;
	sy += g02;
	sy -= g10 * 2;
	sy += g12 * 2;
	sy -= g20;
	sy += g22;
	QUAD_REAL dist = (sx*sx+sy*sy);
	QUAD_REAL result = 1;

	if( dist > T2 ) { result = 0; }
	return result.xxxx;
}

//**********************************************************
// Blur.
VS_OUTPUT_BLUR VS_Blur( float4 Position : POSITION, 
					   float2 TexCoord : TEXCOORD0,
					   uniform int nsamples,
					   uniform float2 direction )
{
	// generate texcoords for blur
	VS_OUTPUT_BLUR OUT = (VS_OUTPUT_BLUR)0;
	OUT.Position = Position;
	float2 texelSize = BlurWidth / WindowSize;
	float2 s = TexCoord - texelSize*(nsamples-1)*0.5*direction;
	for(int i=0; i<nsamples; i++)
	{
		OUT.TexCoord[i] = s + texelSize*i*direction;
	}
	return OUT;
}

// blur filter weights
const float weights7[7] = {
	0.05,
	0.1,
	0.2,
	0.3,
	0.2,
	0.1,
	0.05,
};

// fx doesn't support variable length arrays
// otherwise we could generalize this
float4 PS_Blur7(VS_OUTPUT_BLUR IN,
				uniform sampler2D tex,
				uniform float weight[7] ) : COLOR
{
	float4 c = 0;
	// this loop will be unrolled by compiler
	for(int i=0; i<7; i++)
	{
		c += tex2D(tex, IN.TexCoord[i]) * weight[i];
	}
	return c;
} 

//****************************************************
// Shader Composition.
VS_OUTPUT VS_Quad(float4 Position : POSITION, 
				  float2 TexCoord : TEXCOORD0)
{
	VS_OUTPUT OUT;
	float2 texelSize = 1.0 / WindowSize;
	OUT.Position = Position;
	// don't want bilinear filtering on original scene:
	OUT.TexCoord0 = TexCoord + texelSize*0.5;
	OUT.TexCoord1 = TexCoord + texelSize*0.5/downsampleScale;
	return OUT;	
}

float4 PS_Comp(VS_OUTPUT IN,
			   uniform sampler2D sceneSampler,
			   uniform sampler2D blurredSceneSampler,
			   uniform sampler2D mapRenderSampler ) : COLOR
{   
	float4 orig = tex2D(sceneSampler, IN.TexCoord0);
	float4 blur = tex2D(blurredSceneSampler, IN.TexCoord1 );
	float4 fullwhite = tex2D( mapRenderSampler, IN.TexCoord0 );

	return( ( 1.0f - blur )*GlowColor );
}

float4 PS_Pause(VS_OUTPUT IN,
			   uniform sampler2D pauseSampler ) : COLOR
{   
	float4 pause = tex2D( pauseSampler, IN.TexCoord1 );

	return( pause );
}

//*****************************************************************************
// Techniques.

//*****************************************************************************
technique MapGlow <
string Script = "SetRenderMode=render_background;"
				"RenderColorTarget=;"
				"RenderDepthStencilTarget=;"
				"ClearSetColor=ClearColor;"
				"ClearSetDepth=ClearDepth;"
				"Clear=Color;"
				"Clear=Depth;"
				"ScriptSignature=color;"
				"ScriptExternal=;"

				"SetRenderMode=render_mapglow;"
				"RenderColorTarget=MapRenderTexture;"
				"RenderDepthStencilTarget=DepthMap;"
				"ClearSetColor=ClearColor;"
				"ClearSetDepth=ClearDepth;"
				"Clear=Color;"
				"Clear=Depth;"
				"ScriptSignature=color;"
				"ScriptExternal=;"

				"Pass=MapOutline;"
				"Pass=GlowH;"
				"Pass=GlowV;"
				"Pass=FinalComp;"
				
				"SetRenderMode=render_scene;"
				"RenderColorTarget=;"
				"RenderDepthStencilTarget=;"
				"ScriptSignature=color;"
				"ScriptExternal=;"

				"SetRenderMode=render_model;"
				"RenderColorTarget=;"
				"RenderDepthStencilTarget=;"
				"Clear=Depth;"
				"ScriptExternal=;"

				"SetRenderMode=render_entire_scene;";
>
{
	pass MapOutline <
		string Script = "RenderColorTarget0=MapOutlineTexture;"
						"RenderDepthStencilTarget=DepthMapNoMS;"
						"ClearSetColor=ClearColor;"
						"ClearSetDepth=ClearDepth;"
						"Clear=Color;"
						"Clear=Depth;"
						"Draw=Buffer;";
	> {
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_1_1 edgeVS();
		PixelShader = compile ps_2_0 edgeDetectPS( MapRenderSampler, Threshhold );
	}

	pass GlowH
		<
		string Script = "RenderColorTarget0=HBlurMap;"
						"RenderDepthStencilTarget=DepthMapNoMS;"
						"ClearSetColor=ClearColor;"
						"Clear=Color;"
						"Draw=Buffer;";
		>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_2_0 VS_Blur( 7, float2( 1, 0 ) );
		PixelShader  = compile ps_2_0 PS_Blur7( MapOutlineSampler, weights7 );
	}

	pass GlowV
		<
		string Script = "RenderColorTarget0=FinalBlurMap;"
						"RenderDepthStencilTarget=DepthMapNoMS;"
						"ClearSetColor=ClearColor;"
						"Clear=Color;"
						"Draw=Buffer;";
		>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_2_0 VS_Blur( 7, float2( 0, 1 ) );
		PixelShader  = compile ps_2_0 PS_Blur7( HBlurSampler, weights7 );
	}
		
	pass FinalComp
		<
		string Script = "RenderColorTarget=;"
						"RenderDepthStencilTarget=;"
						"Draw=Buffer;";        	
		>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		
		VertexShader = compile vs_2_0 VS_Quad( );
		PixelShader  = compile ps_2_0 PS_Comp( SceneSampler, FinalBlurSampler, MapRenderSampler );
	}
}

//*****************************************************************************
technique MapGlowPrePause <
string Script = "SetRenderMode=render_background;"
"RenderColorTarget=PauseMap;"
"RenderDepthStencilTarget=DepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"ScriptSignature=color;"
"ScriptExternal=;"

"SetRenderMode=render_mapglow;"
"RenderColorTarget=MapRenderTexture;"
"RenderDepthStencilTarget=DepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"ScriptSignature=color;"
"ScriptExternal=;"

"Pass=MapOutline;"
"Pass=GlowH;"
"Pass=GlowV;"
"Pass=FinalComp;"

"SetRenderMode=render_scene;"
"RenderColorTarget=PauseMap;"
"RenderDepthStencilTarget=DepthMap;"
"ScriptSignature=color;"
"ScriptExternal=;"

"SetRenderMode=render_model;"
"RenderColorTarget=PauseMap;"
"RenderDepthStencilTarget=DepthMap;"
"Clear=Depth;"
"ScriptExternal=;"

"SetRenderMode=render_entire_scene;";
>
{
	pass MapOutline <
		string Script = "RenderColorTarget0=MapOutlineTexture;"
		"RenderDepthStencilTarget=DepthMapNoMS;"
		"ClearSetColor=ClearColor;"
		"ClearSetDepth=ClearDepth;"
		"Clear=Color;"
		"Clear=Depth;"
		"Draw=Buffer;";
	> {
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_1_1 edgeVS();
		PixelShader = compile ps_2_0 edgeDetectPS( MapRenderSampler, Threshhold );
	}

	pass GlowH
		<
		string Script = "RenderColorTarget0=HBlurMap;"
		"RenderDepthStencilTarget=DepthMapNoMS;"
		"ClearSetColor=ClearColor;"
		"Clear=Color;"
		"Draw=Buffer;";
		>
		{
			cullmode = none;
			ZEnable = false;
			ZWriteEnable = false;
			VertexShader = compile vs_2_0 VS_Blur( 7, float2( 1, 0 ) );
			PixelShader  = compile ps_2_0 PS_Blur7( MapOutlineSampler, weights7 );
		}

		pass GlowV
			<
			string Script = "RenderColorTarget0=FinalBlurMap;"
			"RenderDepthStencilTarget=DepthMapNoMS;"
			"ClearSetColor=ClearColor;"
			"Clear=Color;"
			"Draw=Buffer;";
			>
			{
				cullmode = none;
				ZEnable = false;
				ZWriteEnable = false;
				VertexShader = compile vs_2_0 VS_Blur( 7, float2( 0, 1 ) );
				PixelShader  = compile ps_2_0 PS_Blur7( HBlurSampler, weights7 );
			}

			pass FinalComp
				<
				string Script = "RenderColorTarget=PauseMap;"
				"RenderDepthStencilTarget=DepthMap;"
				"Draw=Buffer;";        	
				>
				{
					cullmode = none;
					ZEnable = false;
					ZWriteEnable = false;

					VertexShader = compile vs_2_0 VS_Quad( );
					PixelShader  = compile ps_2_0 PS_Comp( SceneSampler, FinalBlurSampler, MapRenderSampler );
				}
}

//*****************************************************************************
technique MapPause <
string Script =	"SetRenderMode=render_pause;"
				"ClearSetColor=ClearColor;"
				"ClearSetDepth=ClearDepth;"
				"Clear=Color;"
				"Clear=Depth;"
				"ScriptSignature=color;"
				"ScriptExternal=;"
				
				"Pass=GlowH;"
				"Pass=GlowV;"
				"Pass=RenderPauseQuad;"

				"SetRenderMode=render_entire_scene;";
>
{
	pass GlowH
		<
		string Script = "RenderColorTarget0=HBlurMap;"
						"RenderDepthStencilTarget=DepthMapNoMS;"
						"ClearSetColor=ClearColor;"
						"Clear=Color;"
						"Draw=Buffer;";
		>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_2_0 VS_Blur( 7, float2( 1, 0 ) );
		PixelShader  = compile ps_2_0 PS_Blur7( PauseSampler, weights7 );
	}

	pass GlowV
		<
		string Script = "RenderColorTarget0=FinalBlurMap;"
						"RenderDepthStencilTarget=DepthMapNoMS;"
						"ClearSetColor=ClearColor;"
						"Clear=Color;"
						"Draw=Buffer;";
		>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;
		VertexShader = compile vs_2_0 VS_Blur( 7, float2( 0, 1 ) );
		PixelShader  = compile ps_2_0 PS_Blur7( HBlurSampler, weights7 );
	}

	pass RenderPauseQuad
	<
	string Script = "RenderColorTarget=;"	
					"RenderDepthStencilTarget=;"
					"ClearSetColor=ClearColor;"
					"ClearSetDepth=ClearDepth;"
					"Clear=Color;"
					"Clear=Depth;"
					"Draw=Buffer;";        	
	>
	{
		cullmode = none;
		ZEnable = false;
		ZWriteEnable = false;

		VertexShader = compile vs_2_0 VS_Quad( );
		PixelShader  = compile ps_2_0 PS_Pause( FinalBlurSampler );
	}
}