//////////////////////////////////////////////////////////////////////////////
//
// Asura_PS3_AmbientOcclusion.cpp
//
// Created by Ben Weston 14/11/2008
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////


// INCLUDES

#include "Core/Asura.h"

// this file's header
#include "Rendering/Asura_PS3_AmbientOcclusion.h"

// independent
#include "Camera/Asura_Camera.h"
#include "Interface/Asura_CommandConsole.h"
#include "Rendering/Asura_AmbientOcclusion.h"
#include "Rendering/Asura_Viewport.h"

// PS3
#include "Rendering/Shaders/Asura_PS3_GCM_Shader.h"
#include "Rendering/Asura_PS3_DeferredRendering.h"
#include "Rendering/Asura_PS3_FrameBuffer.h"
#include "Rendering/Shaders/Asura_PS3_GCM_ShadersLibrary.h"
#include "Rendering/Asura_PS3_QuadOverlayRenderer.h"
#include "Rendering/Asura_PS3_RenderingStates.h"
#include "Rendering/Asura_PS3_RSXProfiling.h"
#include "Rendering/Asura_PS3_MaterialResponse_System.h"

// shader declarations
#include "Rendering/ShadersDefinition/FP/AmbientOcclusion_FP.h"
#include "Rendering/ShadersDefinition/FP/DepthDownsample_FP.h"
#include "Rendering/ShadersDefinition/FP/SSAO_DepthBlur_FP.h"


// GLOBALS

static Asura_PS3_FrameBuffer*			g_apxBlurredDepthBuffers[NUM_AMBIENT_OCCLUSION_LEVELS];

enum {
	SHADER_HASH_OCCLUSION,
	SHADER_HASH_DEPTHBLUR,
	SHADER_HASH_DEPTHDOWNSAMPLE
};

// DEBUG

enum SSAO_DEV_MODE {
	SSAO_OFF,
	SSAO_ON,
	SSAO_OPAQUE,	// replace screen colour with ambient occlusion result
	//SSAO_TEST_OFF,	// disable the second step of SSAO, but still do the first (for profiling)
	NUM_SSAO_MODES
};

char* g_aszSSAOModeName[] = {
	"OFF",
	"ON",
	"OPAQUE",
	"TEST-OFF",
};

static int g_iSSAOMode = SSAO_OFF;

static int g_iSampleDistance = 1;		// 0 = sample adjacent pixels, bigger values artificially expand the sample range
static int g_iReadBackScale = 2;		// factor of g_iSampleDistance to use when reading the blurred buffers
static int g_iSampleTightness = 0;
static float g_fDepthThreshold = 0.3f;	// depth-difference between pixels at which they are treated as seperate objects
static float g_fDistanceThreshold = 1.0f;	// a similar value to the depth difference, but applied in the final stage to fade the edge. The interaction between these two vals is unfortunate but with tweaking can yield good results
static float g_fBrightness = 0.0f;
static float g_fContrast = 1.0f;
static bool g_bShowBuffers = false;
static bool g_b16TapFilter = true; // more taps, fewer passes. This means we can eliminate intermediate buffers at the cost of some extra processing.

// DEV FUNCTIONS

#if defined(ASURA_PS3_ALLOW_SHADER_RELOAD)
static bool ReloadAmbientOcclusionShader( bool bHelp )
{
	if ( bHelp )
	{
		Asura_CommandConsole::Printf("recompile ambient occlusion shader");
		return true;
	}

	static const char* aszArgs[] = {	// disable fast precision
		"-mcgb",
		"-texformat d FLOAT_RGBA16",
		"-fuse-nrmh",
		"-nobcolor",
		"-fno-max-psize",
		"-po OutColorPrec=fp16",
		"-fastmath",
		"-nofastprecision",
		"-inline all",
		"-unroll all",
		"-nofloatbindings",
		"-ifcvt none",
		NULL
	};

	Asura_PS3_GCM_ShadersLibrary::LoadAndCompileShader( "~/Asura/PS3/Shaders/FragmentPrograms/AmbientOcclusion_FP.fpx",
														ASURA_SHADER_HASH_SSAO, SHADER_HASH_OCCLUSION, aszArgs, NULL, new Asura_PS3_AmbientOcclusion_FP::Handles );

	return true;
}

static bool ReloadDepthDownsampleShader( bool bHelp )
{
	if ( bHelp )
	{
		Asura_CommandConsole::Printf("recompile depth blur shader");
		return true;
	}

	static const char* aszArgs[] = {	// disable fast precision
		"-mcgb",
		"-texformat d FLOAT_RGBA16",
		"-fuse-nrmh",
		"-nobcolor",
		"-fno-max-psize",
		"-po OutColorPrec=fp16",
		"-fastmath",
		"-nofastprecision",
		"-inline all",
		"-unroll all",
		"-nofloatbindings",
		"-ifcvt none",
		NULL
	};

	Asura_PS3_GCM_ShadersLibrary::LoadAndCompileShader( "~/Asura/PS3/Shaders/FragmentPrograms/DepthDownsample_FP.fpx",
														ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHDOWNSAMPLE, aszArgs, NULL, new Asura_PS3_DepthDownsample_FP::Handles );

	Asura_PS3_GCM_ShadersLibrary::LoadAndCompileShader( "~/Asura/PS3/Shaders/FragmentPrograms/SSAO_DepthBlur_FP.fpx",
														ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHBLUR, aszArgs, NULL, new Asura_PS3_SSAO_DepthBlur_FP::Handles );

	return true;
}
#endif


#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
static bool ChangeMode ( bool bInc, bool bInterrogate, bool bHelp )
{
	if ( bHelp || bInterrogate )
	{
		Asura_CommandConsole::Printf( "%s", g_aszSSAOModeName[g_iSSAOMode] );
		return true;
	}

	g_iSSAOMode += bInc?1:-1;
	if ( g_iSSAOMode < 0 ) g_iSSAOMode = NUM_SSAO_MODES-1;
	if ( g_iSSAOMode >= NUM_SSAO_MODES ) g_iSSAOMode = 0;

	return true;
}
#endif


static void ShowBuffer ( Asura_PS3_Texture* pxTexture, float x, float y, float w, float h )
{
	Asura_Overlay_Quad xQuad;
	int iScreenW = Asura_Viewport::GetWidth();
	int iScreenH = Asura_Viewport::GetHeight();
	xQuad.SetRectXY( x*(float)iScreenW, y*(float)iScreenH, w*(float)iScreenW, h*(float)iScreenH );
	xQuad.SetRectUV(0,0,1,1);//.5,.5,.25,.25);

	Asura_PS3_RenderingStates::RequestAlphaTest( false );
	Asura_PS3_RenderingStates::RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );
	xQuad.TranslucencyMode = ASURA_TRANSLUCENCY_OFF;  //cheat! we use some wierd blend modes here so do it without telling the quad system or render states system.
	Asura_PS3_RenderingStates::SetAlphaBlending( false );
	
	xQuad.Colour = 0xffffffff;
	Asura_PS3_QuadOverlayRenderer::RenderEx( xQuad, pxTexture );
	Asura_PS3_RenderingStates::RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
}


// FUNCTIONS

void Asura_AmbientOcclusion::Platform_Initialise() { Asura_PS3_AmbientOcclusion::Initialise(); }
void Asura_AmbientOcclusion::Platform_Shutdown() { Asura_PS3_AmbientOcclusion::Shutdown(); }
void Asura_AmbientOcclusion::Platform_Reset() { }
void Asura_AmbientOcclusion::Platform_PrepareDepthData() { }
void Asura_AmbientOcclusion::Platform_Render() { Asura_PS3_AmbientOcclusion::Render(); }

void Asura_PS3_AmbientOcclusion::Initialise()
{
	Asura_PS3_DepthDownsample_FP::AddToShaderLibrary( ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHDOWNSAMPLE );
	Asura_PS3_SSAO_DepthBlur_FP::AddToShaderLibrary( ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHBLUR );
	Asura_PS3_AmbientOcclusion_FP::AddToShaderLibrary( ASURA_SHADER_HASH_SSAO, SHADER_HASH_OCCLUSION );
	
	// alloc depth down-sample buffers
	// we could probably share these with something else [e.g. frame buffers or shadows or something]
	int w = Asura_PS3_Graphics::GetScreenWidth()>>1;
	int h = Asura_PS3_Graphics::GetScreenHeight()>>1;
	
	for ( int i=0; i < NUM_AMBIENT_OCCLUSION_LEVELS; i++ )
	{
		g_apxBlurredDepthBuffers[i] = new Asura_PS3_FrameBuffer( false, w, h, 1, ASURA_PS3_FRAMEBUFFER_RGBA, false, false, "Ambient Occlusion Buffer", -1 );
	}


#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
	Asura_CommandConsole::AddCmd( L"Render.SSAO.Mode", ChangeMode, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
#if defined(ASURA_PS3_ALLOW_SHADER_RELOAD)
	Asura_CommandConsole::AddCmd( L"Render.SSAO.ReloadAmbOccShader", ReloadAmbientOcclusionShader, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddCmd( L"Render.SSAO.ReloadDepthShader", ReloadDepthDownsampleShader, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
#endif
	Asura_CommandConsole::AddVar( L"Render.SSAO.SampleDistance", &g_iSampleDistance, 0, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.SampleReadScale", &g_iReadBackScale, 0, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.TightnessTweak", &g_iSampleTightness, 0, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.DepthThreshold", &g_fDepthThreshold, 0, FLT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.DistanceThreshold", &g_fDistanceThreshold, 0, FLT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.Contrast", &g_fContrast, -FLT_MAX, FLT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.Brightness", &g_fBrightness, -FLT_MAX, FLT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.ShowBuffers",  &g_bShowBuffers,  Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.SSAO.16TapFilter",  &g_b16TapFilter,  Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	
#endif
}


void Asura_PS3_AmbientOcclusion::Shutdown()
{
}


static void ComputeSamplePositions( float* pfSamplePositions )
{
	// compute the relative placement of the samples from the blurred buffers.
	// output an array of x,y,x,y,x,y with 1 sample position for each buffer.


	// the shader samples each buffer 4 times, rotating this sample point by 90 degrees for each sample
	// we pick coordinates to give this kind of arrangement:
	//
	//   +---+
	//   |	  +---+
	// +-+-+-+	  |
	// |   +-+-+-+
	// +---+   |
	//     +---+
	//
	// with the offsets each successively blurred buffer arranging it's boxes to cover the area beyond the previous one.
	// the buffers are blurred to to represent averages of 2x2, 8x8, 32x32, etc. pixels
	
	// A couple of modifications to that:
	//	- we downsample the first buffer by 1/2, so it's boxes can't be neatly arranged around our pixel. Instead the first level just uses 4 blocks arranged in a square,
	//	  which represents the smart-blurred average of 4x4 pixels, including the pixel we're shading! Fortunately there aren't any artefacts.
	//	- g_iSampleTightness slides those boxes against each other to tighten the iris in the middle, partially/totally overlapping the boxes of later levels with the earlier
	//	  levels. This is a touchy-feely tweak to help improve the visual quality (neither average perfectly represents all of it's constituent pixels, so overlaps might help)
	//	- g_iSampleDistance gives a result sparsely sampled, so rather than the first level representing 2x2 adjacent pixels it represents 4 pixels that were further apart
	//	  obviously this can cause artefacts, but within this function what we need to do is treat it as if it's been sampled from a larger area. Again this is a tweak to
	//	  trade the visual quality of larger blurs vs the artefacts, without incurring any performance hit (from doing more blur stages).

//notes on coordinates:
//
//  full-size (not downsampled) buffers:
// 	.5, 1.5, 5.5
// 	1.5, 6.5, 26.5
// 
// 	i = 0,1,2
// 	.5+[1<<(i-1)*2+[1<<(i-2)*2]]		 //[] - if it shifts right too we're good. (i.e. 1<<-1 = 0, 2<<-1*2 = 0)
// 	.5+1<<i*2+[2<<(i-1)*2+[2<<(i-2)*2]]
// 
// 	downsampled 1/2 (positions in full-screen pixels, for comparison):
// 	basepos rounded to nearest 2x2 corner, (-1,1)
// 	basepos rounded to nearest 2x2 corner, (-2,6)
// 	basepos rounded to nearest 2x2 corner, (-6,26)
// 
// 	1+[1<<(i-1)*2+[1<<(i-2)*2]]
// 	1<<i*2+[2<<(i-1)*2+[2<<(i-2)*2]]
// 
// 	iris:
// 	offset (-1,-1)*i*g_fIris. this screws it in, overlapping the inner layer
// 
// 	sample spacings:
// 	pretty sure this is just a scale applied to the offsets
// 	in the case of non-aligned ones we would add .5 afterwards


	// sample positions are in screen pixels, the shader re-scales to the pixels of the buffer.
	float fX = -1;
	float fY = 1;

	for ( int i=0; i < NUM_AMBIENT_OCCLUSION_SHADER_SAMPLERS; i++ )
	{
		pfSamplePositions[2*i+0] = fX*(1+g_iReadBackScale*g_iSampleDistance) - g_iSampleTightness*2*i; // *2 to force symmetry in 1/2 downsampled buffers (otherwise amb-occ gets some directionality)
		pfSamplePositions[2*i+1] = fY*(1+g_iReadBackScale*g_iSampleDistance) - g_iSampleTightness*2*i;
		
		fX -= 1<<(i*2);
		fY += (1<<((i+1)*2)) + (1<<(i*2));
	}
}


void Asura_PS3_AmbientOcclusion::Render()
{
	if ( g_iSSAOMode == SSAO_OFF ) return;
	
	// Smart-blur the depth buffer as a Z24S8 texture
	// The "smart" algorithm tries to represent the pixels that will cause occlusion, ignoring ones too far back to be part of the same object
	// the stencil value stores a confidence value, represent what percentage of the pixels that were sampled by the blur were actually used in creating this pixel's averaged (blurred) value.
	// when we read this back we use confidence to reduce occlusion, simulating occlusion from a smaller object (e.g. you get less occlusion from 1 far away pixel than a 32x32 box)

	ASURA_PS3_RSX_PROFILE__BEGIN( ASURA_PS3_RSX_PROFILE__CREATESHADOWS, "Ambient Occlusion Downsample" );
	
	Asura_PS3_RenderingStates::RequestAlphaTest( false );
	Asura_PS3_RenderingStates::SetAlphaBlending( false );
	Asura_PS3_RenderingStates::RequestZBufferWriteEnabled( false );
	
	int uNumPasses = g_b16TapFilter?NUM_AMBIENT_OCCLUSION_SHADER_SAMPLERS:NUM_AMBIENT_OCCLUSION_LEVELS;
	for ( int i=0; i < uNumPasses; i++ )
	{
		g_apxBlurredDepthBuffers[i]->Bind(false);

		Asura_PS3_FragmentShaderCopy* pxDepthSmartBlurFP;

		if ( i == 0 )
		{
			pxDepthSmartBlurFP = Asura_PS3_GCM_ShadersLibrary::GetPermanentFP( ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHDOWNSAMPLE );

			//special case, read the actual depth buffer
			pxDepthSmartBlurFP->SetTexture( Asura_PS3_DepthDownsample_FP::FP_DepthBufferSampler, Asura_PS3_DeferredRendering::GetDeferredFrameBuffer()->GetZBufferAsTexture(), false );
		}
		else
		{
			if ( g_b16TapFilter )
			{
				pxDepthSmartBlurFP = Asura_PS3_GCM_ShadersLibrary::GetPermanentFP( ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHBLUR );
			}
			else
			{
				pxDepthSmartBlurFP = Asura_PS3_GCM_ShadersLibrary::GetPermanentFP( ASURA_SHADER_HASH_SSAO, SHADER_HASH_DEPTHDOWNSAMPLE );
			}

			//read the texture from the previous step
			pxDepthSmartBlurFP->SetTexture( Asura_PS3_SSAO_DepthBlur_FP::FP_DepthBufferSampler, g_apxBlurredDepthBuffers[i-1]->GetRTAsTexture(0), false );
		}

		// set the threshold - perhaps this should change with each level? Not sure if it should get smaller (because 2D range is bigger), or bigger (because legitimate depth-difference caused by gentle slope is bigger)
		float fNear = Asura_Camera::GetNearClip();
		float fFar = Asura_Camera::GetFarClip();
		float fDepthProject1 = (fNear*fFar) / (fFar-fNear);	// imitate the calculation done when creating the projection matrix
		float fDepthProject2 = (fFar) / (fFar-fNear);
		
		float fFactor = 1;//i+1;//1<<i; // the acceptible error must increase with each level or the blurriest level will fail on steep planar surfaces, however this causes echoes
		float fThresholdFactor = fFactor * g_fDepthThreshold / fDepthProject1;
		
		int iSampleExp = i;
		if ( g_b16TapFilter && i > 0 ) iSampleExp = i*2-1; //0,1,3,5,... because 16-tap counts for 2 passes (first pass is only 4-tap)
		if ( i > 0 ) iSampleExp -= 1; //the first pass downsamples so halve all later passes
		float fSampleDistance = 0.5f * (float)(1<<iSampleExp);	// 0.5, 1/2, 4/2, 16/2,...
		fSampleDistance += (float)(g_iSampleDistance<<iSampleExp);
		

		float afParams[4] = { fSampleDistance, fThresholdFactor, i, 0 };
		pxDepthSmartBlurFP->SetFloats( Asura_PS3_DepthDownsample_FP::FP_Parameters, 4, afParams );

		float afDepthProjection[4] = { fDepthProject1, fDepthProject2, fNear, 0 };
		pxDepthSmartBlurFP->SetFloats( Asura_PS3_DepthDownsample_FP::FP_DepthProjection, 4, afDepthProjection );

		pxDepthSmartBlurFP->Bind();

		Asura_Overlay_Quad xQuad;
		xQuad.SetRectXY( 0, 0, g_apxBlurredDepthBuffers[i]->GetSurface()->width, g_apxBlurredDepthBuffers[i]->GetSurface()->height );
		Asura_PS3_QuadOverlayRenderer::RenderEx( &xQuad ); //render it without changing any more render states.
	}

	ASURA_PS3_RSX_PROFILE__END( ASURA_PS3_RSX_PROFILE__CREATESHADOWS );


	ASURA_PS3_RSX_PROFILE__BEGIN( ASURA_PS3_RSX_PROFILE__APPLYSHADOWS, "Ambient Occlusion Apply" );
	
	//if ( g_iSSAOMode == SSAO_TEST_OFF ) return;

	// setup 
	Asura_PS3_DeferredRendering::Bind();
	
	Asura_PS3_RenderingStates::RequestAlphaTest( false );
	Asura_PS3_RenderingStates::RequestTranslucencyMode( ASURA_TRANSLUCENCY_COLOUR );
	Asura_PS3_RenderingStates::SetAlphaBlending( true );

	Asura_PS3_FragmentShaderCopy* pxAmbientOcclusionFP = Asura_PS3_GCM_ShadersLibrary::GetPermanentFP( ASURA_SHADER_HASH_SSAO, SHADER_HASH_OCCLUSION );

	pxAmbientOcclusionFP->SetArray( Asura_PS3_AmbientOcclusion_FP::FP_ViewMatrix, 4, 4, Asura_PS3_Graphics::GetViewMatrix().GetElements() );

	float afParams[4];
	float fCameraTanHalfVertFOV	= Asura_Maths::Tangent( Asura_Camera::GetVerticalFieldOfView() * 0.5f );
	float fCameraTanHalfHorizFOV= fCameraTanHalfVertFOV * Asura_PS3_Graphics::GetScreenAspectRatio();// Asura_Camera::GetXOverYAspectRatio();
	afParams[0] = fCameraTanHalfHorizFOV;
	afParams[1] = fCameraTanHalfVertFOV;
	pxAmbientOcclusionFP->SetFloats( Asura_PS3_AmbientOcclusion_FP::FP_CameraTanHalfFOV, 2, &afParams[0] );
	
	Asura_PS3_MaterialResponse_System::SetDepthParameters( pxAmbientOcclusionFP, Asura_PS3_AmbientOcclusion_FP::FP_DepthAdjustment );

	afParams[0] = 2.0f / Asura_Viewport::GetWidth();
	afParams[1] = 2.0f / Asura_Viewport::GetHeight();	
	pxAmbientOcclusionFP->SetFloats( Asura_PS3_AmbientOcclusion_FP::FP_TwoOverScreen, 2, &afParams[0] );
	
	afParams[0] = g_fContrast;
	afParams[1] = g_fBrightness;
	pxAmbientOcclusionFP->SetFloats( Asura_PS3_AmbientOcclusion_FP::FP_BrightnessContrast, 2, &afParams[0] );
	
	afParams[0] = g_fDistanceThreshold;
	pxAmbientOcclusionFP->SetFloats( Asura_PS3_AmbientOcclusion_FP::FP_DistanceFade, 1, &afParams[0] );

	float afSamplePositions[8];
	ComputeSamplePositions(afSamplePositions);
	pxAmbientOcclusionFP->SetArray( Asura_PS3_AmbientOcclusion_FP::FP_SamplePositions, 2, 4, &afSamplePositions[0] );


	pxAmbientOcclusionFP->SetTexture( Asura_PS3_AmbientOcclusion_FP::FP_NormalMaterialBufferSampler, Asura_PS3_DeferredRendering::GetDeferredFrameBuffer()->GetRTAsTexture( ASURA_DEFERRED_RENDER_TARGET_NORMAL_MATERIAL ), false );
 	pxAmbientOcclusionFP->SetTexture( Asura_PS3_AmbientOcclusion_FP::FP_DepthBufferSampler, Asura_PS3_DeferredRendering::GetDeferredFrameBuffer()->GetZBufferAsTexture(), false );

	for ( int i=0; i < NUM_AMBIENT_OCCLUSION_SHADER_SAMPLERS; i++ )
	{
		int iTex = i;
		if ( !g_b16TapFilter ) iTex *= 2;
	
		pxAmbientOcclusionFP->SetTexture( Asura_PS3_AmbientOcclusion_FP::FP_DepthBlurSamplers+i, g_apxBlurredDepthBuffers[iTex]->GetRTAsTexture(0), false );
	}
	
	pxAmbientOcclusionFP->Bind();


	// debug overrides
	if ( g_iSSAOMode == SSAO_OPAQUE ) Asura_PS3_RenderingStates::SetAlphaBlending(false);

	// blit as a full screen quad.
	Asura_Overlay_Quad xQuad;
	xQuad.SetRectXY(0,0,Asura_PS3_Graphics::GetScreenWidth(),Asura_PS3_Graphics::GetScreenHeight());
	Asura_PS3_QuadOverlayRenderer::RenderEx( &xQuad ); //render it without changing any more render states.

	ASURA_PS3_RSX_PROFILE__END( ASURA_PS3_RSX_PROFILE__APPLYSHADOWS );


	// debug output	
	if ( g_bShowBuffers )
	{
		for ( int i=0; i < NUM_AMBIENT_OCCLUSION_SHADER_SAMPLERS; i++ )
		{
			int iTex = i;
			if ( !g_b16TapFilter ) iTex *= 2;
			ShowBuffer(g_apxBlurredDepthBuffers[iTex]->GetRTAsTexture(0), 0,.25f*(float)i, .25f,.25f);
		}
	}
}

