///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Platform_RenderStates.cpp
// Author : Kevin Floyer-Lea
// Date   : 1-Jul-2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

/******************************************************************************/
/* Included Files                                                             */
/******************************************************************************/

#include "Core/Asura.h"

#include "Rendering/Asura_RenderStates.h"

// Asura Platform-independent
#include "Core/Asura_TextureManagement.h"
#include "Rendering/Asura_Render.h"

// Asura Xbox 360
#include "Rendering/Asura_Xbox360_Graphics.h"
#include "Rendering/Asura_Xbox360_TextureManagement.h"

// undef if you want pix events on any asura device setting
//#define ENABLE_OPTIONAL_PIX_EVENTS

#ifdef ENABLE_OPTIONAL_PIX_EVENTS
#define OPTIONAL_PIX_MARKER(args) PIXSetMarker(args)
#else
#define OPTIONAL_PIX_MARKER(args)
#endif

/******************************************************************************/
/* Asura_Render_States Class Functions                                        */
/******************************************************************************/

void Asura_Render_States::SetTextureIndex( int t, int i )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTextureIndex(t,i)", t, i ));
	Asura_Xbox360_Graphics::GetDevice()->SetTexture( t, Asura_Xbox360_TextureManagement::GetTexture(i)->GetD3DTexture() );
}

void Asura_Render_States::SetWireFrameMode( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetWireFrameMode(%s)", b ? "true" : "false" ));
	WireFrameMode = b;
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_FILLMODE, b ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
}

void Asura_Render_States::SetDitheringMode( bool b )
{
	// (AAM - 21.03.2006) There is no dithering render state on 360
	DitheringMode = b;
}

void Asura_Render_States::SetZBufferEnabled( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetZBufferEnabled(%s)", b ? "true" : "false" ));
	ZBufferEnabled = b;
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZENABLE, b ? D3DZB_TRUE: D3DZB_FALSE );
}

void Asura_Render_States::SetZBufferCompareMode( ASURA_ZBUFFERCMP_ID mode )
{
	ZBufferCompareMode = mode;

	switch( mode )
	{
		case ASURA_ZBUFFERCMP_LESSEQUAL:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL)"));
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
			break;
		}

		case ASURA_ZBUFFERCMP_ALWAYS:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetZBufferCompareMode(ASURA_ZBUFFERCMP_ALWAYS)"));
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS );
			break;
		}

		case ASURA_ZBUFFERCMP_EQUALS:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetZBufferCompareMode(ASURA_ZBUFFERCMP_EQUALS)"));
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
			break;
		}

		case ASURA_ZBUFFERCMP_GREATER:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetZBufferCompareMode(ASURA_ZBUFFERCMP_GREATER)"));
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZFUNC, D3DCMP_GREATER );
			break;
		}

		default:
		{
			Asura_Assert( false, "Unknown Z buffer compare mode." );
			break;
		}
	}
}

void Asura_Render_States::SetZBufferWriteEnabled( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "ZBufferWriteEnabled(%s)", b ? "true" : "false" ));
	ZBufferWriteEnabled = b;
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ZWRITEENABLE, b );
}

void Asura_Render_States::SetAlphaBlending( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetAlphaBlending(%s)", b ? "true" : "false" ));
	AlphaBlendingEnabled = b;
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ALPHABLENDENABLE, b );
}

void Asura_Render_States::SetTranslucencyMode(  ASURA_TRANSLUCENCY_MODE eMode )
{
	// Don't use D3DRS_ALPHABLENDENABLE on Xbox 360, because that sets the same blend mode
	// for all render targets. We can't use blending on a floating point RT

	D3DBLENDSTATE xBlendState;
	xBlendState.BlendOp = xBlendState.BlendOpAlpha = D3DBLENDOP_ADD;

	TranslucencyMode = eMode;

	switch( TranslucencyMode )
	{
	 	case ASURA_TRANSLUCENCY_OFF:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_OFF)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_ONE;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ZERO;
			break;
		}

	 	case ASURA_TRANSLUCENCY_NORMAL:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_SRCALPHA;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_INVSRCALPHA;
			break;
		}

	 	case ASURA_TRANSLUCENCY_COLOUR:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_COLOUR)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_DESTCOLOR;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ZERO;
			break;
		}

		case ASURA_TRANSLUCENCY_DOUBLECOLOUR:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_DOUBLECOLOUR)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_DESTCOLOR;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_SRCCOLOR;
			break;
		}

		case ASURA_TRANSLUCENCY_INVCOLOUR:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_INVCOLOUR)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_ZERO;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_INVSRCCOLOR;
			break;
		}

		case ASURA_TRANSLUCENCY_GLOWING:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_GLOWING)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_SRCALPHA;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ONE;
			break;
		}

		case ASURA_TRANSLUCENCY_DARKENINGCOLOUR:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_DARKENINGCOLOUR)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_INVDESTCOLOR;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ZERO;
			break;
		}

		case ASURA_TRANSLUCENCY_JUSTSETZ:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_JUSTSETZ)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_ZERO;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ONE;
			break;
		}

		case ASURA_TRANSLUCENCY_ALPHACOMPARE:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_ALPHACOMPARE)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_DESTALPHA;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ZERO;
			break;
		}

		case ASURA_TRANSLUCENCY_UGH:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetTranslucencyMode(ASURA_TRANSLUCENCY_UGH)"));
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_DESTCOLOR;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ONE;
			break;
		}

		default:
		{
			Asura_Assert( false, "Unknown translucency mode." );
			xBlendState.SrcBlend = xBlendState.SrcBlendAlpha = D3DBLEND_ONE;
			xBlendState.DestBlend = xBlendState.DestBlendAlpha = D3DBLEND_ZERO;
			break;
		}
	}

	Asura_Xbox360_Graphics::GetDevice()->SetBlendState( 0, xBlendState );
}

void Asura_Render_States::SetTextureOpMode( ASURA_TEXTUREOP_ID mode )
{
}

void Asura_Render_States::SetAlphaTest( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetAlphaTest(%s)", b ? "true" : "false" ));
	AlphaTest = b;

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ALPHATESTENABLE, b );

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ALPHAREF, m_iAlphaTestRef);
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
	
}

void Asura_Render_States::SetDynamicLights( bool b )
{
	DynamicLights = b;
}

void Asura_Render_States::SetCullMode( ASURA_CULLMODE_ID eMode )
{
	m_eCullMode = eMode;

	switch( eMode )
	{
		default:
		case ASURA_CULLMODE_NONE:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetCullMode(ASURA_CULLMODE_NONE)"));
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
			break;
		}

		case ASURA_CULLMODE_CW:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetCullMode(ASURA_CULLMODE_CW)"));
			if( Asura_Render::ShouldRenderMirrored())
			{
				Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
			}
			else
			{
				Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
			}

			break;
		}

		case ASURA_CULLMODE_CCW:
		{
			OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetCullMode(ASURA_CULLMODE_CCW)"));
			if( Asura_Render::ShouldRenderMirrored() )
			{
				Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
			}
			else
			{
				Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
			}

			break;
		}
	}
}

void Asura_Render_States::SetStencilEnabled( bool b )
{
	OPTIONAL_PIX_MARKER(( D3DCOLOR_XRGB( 0, 0, 0 ), "SetStencilEnabled(%s)", b ? "true" : "false"));
	StencilEnabled = b;
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_STENCILENABLE, b ? TRUE : FALSE );
}
