////////////////////////////////////////////////////////////////////////////////////////////////////
// post.fx
////////////////////////////////////////////////////////////////////////////////////////////////////



// Transforms
////////////////////////////////////////////////////////////////////////////////////////////////////
float4x4 g_wvp_mtx;
float4 g_offset;
float4 g_weight;
float4 g_add_color;



// Lighting
////////////////////////////////////////////////////////////////////////////////////////////////////
float4 g_sun_pos;
float4 g_sun_dir;




// Textures & samplers
////////////////////////////////////////////////////////////////////////////////////////////////////
texture g_rt_tex;
texture g_fx_tex;
texture1D g_ramp_tex;
texture g_fx2_tex;

sampler g_rt_samp = sampler_state
{
    texture = <g_rt_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    AddressW  = CLAMP;
};

sampler g_rt_point_samp = sampler_state
{
    texture = <g_rt_tex>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    AddressW  = CLAMP;
};

sampler g_fx_samp = sampler_state
{
    texture = <g_fx_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    AddressW  = CLAMP;
};

sampler g_fx2_samp = sampler_state
{
    texture = <g_fx2_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = WRAP;
    AddressV  = WRAP;
    AddressW  = WRAP;
};

sampler1D g_ramp_samp = sampler_state
{
    texture = <g_ramp_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    AddressW  = CLAMP;
};



// Vertex shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
void vs_main(
    in float3 iPos : POSITION0,
    in float2 iTc0 : TEXCOORD0,

    out float4 oPos	: POSITION,
    out float2 oTc0	: TEXCOORD0 )
{
    // Transform vertex position 
    oPos = mul( float4( iPos.xyz, 1.0 ), g_wvp_mtx );

    // Copy texcoord
    oTc0 = iTc0;
}



// Pixel shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_pass( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
    return tex2D( g_rt_samp, iTc0 );
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_downsample( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float4 acc = 0.0;

		// Read samples
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.w ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.w ) );

		// Done
		return acc * 0.25;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_downsample_and_cutoff( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float4 acc = 0.0;

		// Read samples
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.w ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.w ) );

		// Cutoff and done
		return max( (acc * 0.25) - 0.75, 0.0 );
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_downsample_and_cutoff_fire( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float4 acc = 0.0;

		// Read samples
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.y ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, g_offset.w ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, g_offset.w ) );

		// Cutoff and done
		return max( (acc * 0.35) - 0.5, 0.0 );
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_blur_h( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float4 acc = 0.0;

		// Read samples
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.x, 0 ) ) * g_weight.x;
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.y, 0 ) ) * g_weight.y;
		acc += tex2D( g_rt_samp, iTc0 );
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.z, 0 ) ) * g_weight.y;
		acc += tex2D( g_rt_samp, iTc0 + float2( g_offset.w, 0 ) ) * g_weight.z;

		// Done
		return acc * 0.3;
}                                                                                   



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_blur_v( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float4 acc = 0.0;

		// Read samples
		acc += tex2D( g_rt_samp, iTc0 + float2( 0, g_offset.x ) ) * g_weight.x;
		acc += tex2D( g_rt_samp, iTc0 + float2( 0, g_offset.y ) ) * g_weight.y;
		acc += tex2D( g_rt_samp, iTc0 );
		acc += tex2D( g_rt_samp, iTc0 + float2( 0, g_offset.z ) ) * g_weight.y;
		acc += tex2D( g_rt_samp, iTc0 + float2( 0, g_offset.w ) ) * g_weight.z;

		// Done
		return acc * 0.3;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		
		// Calc vignette
		iTc0 -= 0.5;
		float vignette = pow( 1.0 - dot( iTc0, iTc0 ), 2.0 );

		// Composite
		float4 final = vignette * (rt + fx);

		// Tone map, gamma correct, and return
		float4 x = max( 0.0, final - 0.004 ); // Filmic Curve
		return ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_extreme_vignette( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		
		// Calc vignette
		iTc0 -= 0.5;
		float vignette = pow( 1.0 - dot( iTc0, iTc0 ), 4.0 ) * 1.25;

		// Composite
		float4 final = (rt + fx);

		// Tone map, gamma correct, and return
		float4 x = max( 0.0, final - 0.004 ); // Filmic Curve
		float4 filmic = ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
		return vignette * filmic;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_no_vignette( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		
		// Composite
		float4 final = rt + fx;

		// Tone map, gamma correct, and return
		float4 x = max( 0.0, final - 0.004 ); // Filmic Curve
		float4 tonemapped = ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
		return tonemapped + g_add_color;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_pixel( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_point_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		float4 fx2 = tex2D( g_fx2_samp, iTc0.xy*g_offset.xy + g_offset.zw );
		
		// Composite
		float4 final = rt*fx2 + fx;

		// Tone map, gamma correct, and return
		float4 x = max( 0.0, final - 0.004 ); // Filmic Curve
		float4 tonemapped = ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
		return tonemapped + g_add_color;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_separate( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float x = 0.5 / 800.0;
		float y = 0.5 / 600.0;

		// Read samples
		float2 tc_adj = iTc0 - 0.5;
		float scale = 20.0 * dot( tc_adj, tc_adj );
		x += x * scale;
		y += y * scale;
		
		float r = tex2D( g_rt_samp, iTc0 + float2( -x, -y ) ).r;
		float g = tex2D( g_rt_samp, iTc0 ).g;
		float b = tex2D( g_rt_samp, iTc0 + float2(  x,  y ) ).b;
		float3 separated = float3( r, g, b );
		
		// Desaturate a bit
		return float4( separated, 1.0 );
}


////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_fire( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float x = 0.5 / 800.0;
		float y = 0.5 / 600.0;
		float s = 0.005;
		float2 offset0 = (tex2D( g_fx_samp, iTc0 * 0.25 + g_offset.xy ) * 2.0 - 1.0) * s;
		float2 offset1 = (tex2D( g_fx_samp, iTc0 * 0.50 - g_offset.xy ) * 2.0 - 1.0) * s;
		float2 offset2 = (tex2D( g_fx_samp, iTc0 * 1.00 + g_offset.xy*2.0 ) * 2.0 - 1.0) * s;
		iTc0 += offset0 + offset1*0.5 + offset2*0.25;

		float cool_samp = tex2D( g_fx_samp, iTc0*0.40 + float2( 0.0f, g_offset.y*4.0 ) );
		float cool = 1.0 - saturate( cool_samp - 0.5 ) * 1.35;

		float4 acc = 0;
		acc += tex2D( g_rt_samp, iTc0 );
		acc += tex2D( g_rt_samp, iTc0 + float2( -x,  y*2.5 ) );
		acc += tex2D( g_rt_samp, iTc0 + float2(  x,  y*2.5 ) );
		acc += tex2D( g_rt_samp, iTc0 + float2( 0.0, y*5.0 ) );		
		acc += tex2D( g_rt_samp, iTc0 + float2( 0.0, y*10.0 ) );		
    return saturate( acc / 5.0 ) * cool;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_colorgrade( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		float color = tex2D( g_rt_samp, iTc0 ).r;
		return tex1D( g_ramp_samp, color );
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_plain( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		
		return (rt+fx - rt*fx) + g_add_color;
}




////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_plain_background( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		float4 fx2 = saturate( tex2D( g_fx2_samp, iTc0 ) );
		float4 combined = (rt+fx - rt*fx);
		float4 composited = lerp( fx2, combined, saturate( dot( saturate(combined), float3(0.333, 0.334, 0.333) ) * 4.0 ) );		
		return composited + g_add_color;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_composite_disco( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
		// Read samples
		float4 rt = tex2D( g_rt_samp, iTc0 );
		float4 fx = tex2D( g_fx_samp, iTc0 );
		
		float4 final = rt + fx;
		float4 x = max( 0.0, final - 0.004 ); // Filmic Curve
		float4 tonemapped = ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
		
		return tonemapped + g_add_color;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_godrays( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
	float2 delta = iTc0 - g_sun_pos.xy;

	float dist = sqrt(delta.x * delta.x + delta.y * delta.y);
	float decay = 2.1f * saturate(0.51f - dist);
	float power = 0.09f * decay;

	float4 col = tex2D(g_rt_samp, iTc0);

	for (int i = 0; i < 12; i++)
	{
		iTc0 -= delta / 20;
		float4 sample = tex2D(g_rt_samp, iTc0);
		sample.rgb *= sample.a;
		sample.rgb *= float3( 1.0f, 0.7f, 0.4f );
		col += sample * power * saturate(-g_sun_dir.z);
		power *= decay;
	}

	return col + g_add_color;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
float4 ps_godrays2( in float2 iTc0 : TEXCOORD0 ) : COLOR
{
	float2 delta = iTc0 - g_sun_pos.xy;

	float dist = sqrt(delta.x * delta.x + delta.y * delta.y);
	float decay = 2.1f * saturate(0.51f - dist);
	float power = 0.09f * decay;

	float4 col = tex2D(g_rt_samp, iTc0);

	for (int i = 0; i < 12; i++)
	{
		iTc0 -= delta / 15;
		float4 sample = tex2D(g_rt_samp, iTc0);
		sample.rgb *= sample.a;
		sample.rgb *= float3( 1.0f, 0.7f, 0.4f );
		col += sample * power * saturate(-g_sun_dir.z);
		power *= decay;
	}

	return col + g_add_color;
}


// Techniques
////////////////////////////////////////////////////////////////////////////////////////////////////
technique passthrough
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_pass();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique downsample
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_downsample();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique downsample_and_cutoff
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_downsample_and_cutoff();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique downsample_and_cutoff_fire
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_downsample_and_cutoff_fire();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique blur_h
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_blur_h();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique blur_v
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_blur_v();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_extreme_vignette
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_extreme_vignette();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_no_vignette
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_no_vignette();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique rgb_separate
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_separate();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique fire
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_fire();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique colorgrade
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_colorgrade();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_plain
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_plain();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_plain_background
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_plain_background();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique godrays
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_3_0 vs_main();
        PixelShader = compile ps_3_0 ps_godrays();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique godrays2
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_3_0 vs_main();
        PixelShader = compile ps_3_0 ps_godrays2();
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_pixel
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_pixel();
    }
}




////////////////////////////////////////////////////////////////////////////////////////////////////
technique composite_disco
{
    pass p0
    {
        ZEnable = false;
        AlphaBlendEnable = false;
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_composite_disco();
    }
}
