///////////////////////////////////////////////////////////////////////////////
//
// File		: Asura_PS3_RenderingStates.h
// Author	: Catalin Arsenescu (11-June-2007)
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_PS3_RENDERING_STATES_H__
#define __ASURA_PS3_RENDERING_STATES_H__

// I N C L U D E S ///////////////////////////////////////////////////////////

// Stdlib platform-specific.
#include <cell/gcm/gcm_enum.h>

// Engine independent.
#include "Rendering/Asura_RenderStates.h"

// C L A S S E S /////////////////////////////////////////////////////////////

struct CellGcmSurface;
struct CellGcmTexture;

class Asura_PS3_GCM_VertexShader;
class Asura_PS3_GCM_Shader;
class Asura_PS3_Texture;

#define ASURA_PS3_MAXIMUM_TEXTURES					16
#define ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS		16
//#define
#define ASURA_PS3_DEFAULT_ANISO						CELL_GCM_TEXTURE_MAX_ANISO_1
#define ASURA_PS3_DEFAULT_TEXTURE_OPTIMIZATION		ASURA_PS3_TEXTURE_OPTIMIZATION_HIGH_QUALITY
#define ASURA_PS3_DEFAULT_CONVOLUTION_FILTER		CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX

const float fASURA_PS3_DEFAULT_VIEWPORT_MIN_Z = 0.0f;
const float fASURA_PS3_DEFAULT_VIEWPORT_MAX_Z = 1.0f;


//BW (4/9/08) - changed enums to more meaningful bitfields
// colour mask enums, use bits to represent bgra for each render target.
// ordered so that least significant bit is MRT0 red. e.g. 0x0700 enables writing to rgb of MRT2
// All functions that use these enums must deal with every combination, not just the ones listed here.

enum ASURA_PS3_MRT_COMBINATION
{
	ASURA_PS3_MRT_NONE							=0x0000,	// MRT0123 none
	ASURA_PS3_MRT_MRT0_ALL						=0x000f,	// MRT0 all only
	ASURA_PS3_MRT_MRT1_ALL						=0x00f0,	// MRT1 rgba only
	ASURA_PS3_MRT_MRT2_ALL						=0x0f00,	// MRT2 rgba only
	ASURA_PS3_MRT_MRT3_ALL						=0xf000,	// MRT3 rgba only
	ASURA_PS3_MRT_MRT0123_ALL					=0xffff,	// All on
	ASURA_PS3_MRT_MRT02_ALL_MRT13_NONE			=0x0f0f,	// MRT 0 and 2 all, MRT 1 and 3 None
	ASURA_PS3_MRT_MRT012_ALL_MRT3_NONE			=0x0fff,	// MRT 0, 1 and 2 all, MRT 3 None
	ASURA_PS3_MRT_MRT0_ALL_MRT13_NONE_MRT2_RGB	=0x0e0f,	// MRT0 All, MRT13 none and MRT2 RGB
	ASURA_PS3_MRT_MRT02_RGB_MRT13_NONE			=0x0e0e,	// MRT02 RGB, MRT13 none
	ASURA_PS3_MRT_MRT0_ALPHA					=0x0001,	// MRT0 only Alpha
	ASURA_PS3_MRT_MRT2_ALPHA					=0x0100,	// MRT2 only Alpha
	ASURA_PS3_MRT_MRT2_RGB						=0x0e00,	// MRT2 only RGB
};

//mask a specific render target given it's index
#define ASURA_PS3_MRT_MASK(uRenderTarget)	(0xf<<(uRenderTarget*4))

// subset of the full range, just corresponding to MRT0
enum ASURA_PS3_COLOR_MASK_MRT0
{
	ASURA_PS3_COLOR_MASK_MRT0_NONE		=0x0,
	ASURA_PS3_COLOR_MASK_MRT0_ALPHA		=0x1,
	ASURA_PS3_COLOR_MASK_MRT0_RED  		=0x2,
	ASURA_PS3_COLOR_MASK_MRT0_GREEN		=0x4,
	ASURA_PS3_COLOR_MASK_MRT0_BLUE 		=0x8,
	ASURA_PS3_COLOR_MASK_MRT0_RGB		=0xe,
	ASURA_PS3_COLOR_MASK_MRT0_ALL		=0xf,
};

// subset of the full range, just corresponding to MRT's 123
enum ASURA_PS3_COLOR_MASK_MRT123
{
	ASURA_PS3_COLOR_MASK_MRT123_ALL					=0xfff0,
	ASURA_PS3_COLOR_MASK_MRT123_MRT13_NONE_MRT2_RGB	=0x0e00,
	ASURA_PS3_COLOR_MASK_MRT13_NONE_MRT2_ALPHA		=0x0100,
	ASURA_PS3_COLOR_MASK_MRT123_MRT13_NONE_MRT2_ALL	=0x0f00,
	ASURA_PS3_COLOR_MASK_MRT123_MRT3_NONE_MRT12_ALL	=0x0ff0,
	ASURA_PS3_COLOR_MASK_MRT123_NONE				=0x0000,
};


enum ASURA_PS3_TEXTURE_OPTIMIZATION
{
	ASURA_PS3_TEXTURE_OPTIMIZATION_LOW_QUALITY,
	ASURA_PS3_TEXTURE_OPTIMIZATION_MEDIUM_QUALITY,
	ASURA_PS3_TEXTURE_OPTIMIZATION_HIGH_QUALITY,
};

enum ASURA_PS3_STENCIL_FUNCTION
{
	ASURA_PS3_STENCIL_NEVER		= CELL_GCM_NEVER,
	ASURA_PS3_STENCIL_LESS		= CELL_GCM_LESS,
	ASURA_PS3_STENCIL_LEQUAL	= CELL_GCM_LEQUAL,
	ASURA_PS3_STENCIL_GREATER	= CELL_GCM_GREATER,
	ASURA_PS3_STENCIL_GEQUAL	= CELL_GCM_GEQUAL,
	ASURA_PS3_STENCIL_EQUAL		= CELL_GCM_EQUAL,
	ASURA_PS3_STENCIL_NOTEQUAL	= CELL_GCM_NOTEQUAL,
	ASURA_PS3_STENCIL_ALWAYS	= CELL_GCM_ALWAYS,
};

enum ASURA_PS3_STENCIL_OPERATION
{
	ASURA_PS3_STENCIL_OPERATION_KEEP		= CELL_GCM_KEEP,
	ASURA_PS3_STENCIL_OPERATION_ZERO		= CELL_GCM_ZERO,
	ASURA_PS3_STENCIL_OPERATION_REPLACE		= CELL_GCM_REPLACE,
	ASURA_PS3_STENCIL_OPERATION_INCR		= CELL_GCM_INCR,
	ASURA_PS3_STENCIL_OPERATION_DECR		= CELL_GCM_DECR,
	ASURA_PS3_STENCIL_OPERATION_INCR_WRAP	= CELL_GCM_INCR_WRAP,
	ASURA_PS3_STENCIL_OPERATION_DECR_WRAP	= CELL_GCM_DECR_WRAP,
	ASURA_PS3_STENCIL_OPERATION_INVERT		= CELL_GCM_INVERT,
};

class Asura_PS3_RenderingStates
{
public:
	static void		Initialise				( void );
	static void		Shutdown				( void );

	static void		BeginFrame				( void );

	static void		SetBlendEnableMrt		( bool bTarget1, bool bTarget2, bool bTarget3 );

	static void		SetColorMaskMrtState	( u_int eMrtState );
	static void		SetColorMaskMrt0		( u_int eColorMask );
	static void		SetColorMaskMrt123		( u_int eColorMask );

	static void		SetTextureFilter		( u_char ucTextureIndex, CellGcmEnum eMinFilter, CellGcmEnum eMagFilter, CellGcmEnum eConvolutionFilter );
	static void		SetTextureOptimization	( u_char ucTextureIndex, ASURA_PS3_TEXTURE_OPTIMIZATION eTextureOptimization );
	static void		SetTextureControl		( u_char ucTextureIndex, bool bEnable, CellGcmEnum eTextureAniso = CELL_GCM_TEXTURE_MAX_ANISO_1 );
	static void		SetTextureAddressMode	( u_char ucTextureIndex, CellGcmEnum eAddressModeS, CellGcmEnum eAddressModeT, CellGcmEnum eAddressModeR, bool bUse_sRGBConversion );
	static void		SetTextureBorderColour	( u_char ucTextureIndex, u_int uColour );

	static void		SetTexture				( u_char ucTextureChannel, const CellGcmTexture* pxTexture, bool bNormalizedCoordinates );
	static Asura_PS3_Texture* RequestTextureIndex ( int iTextureChannel, int iTextureIndex );
	static void		ClearTexture			( u_char ucTextureIndex );
	static void		SetVertexDataArray		( u_char ucIndex, u_short usFrequency, u_char ucStride, u_char ucSize, u_char ucType, u_char ucLocation, u_int uiOffset);
	static bool		SetVertexAttributeNeeded( u_char ucIndex, u_short usFrequency, u_char ucStride, u_char ucSize, u_char ucType );
	static bool		SetVertexOffsetNeeded	( u_char ucIndex, u_char ucLocation, u_int uiOffset );

	static void		SetVertexShader			( const void* pxVertexShaderConfig, const void* pxVertexShaderAddress, Asura_PS3_GCM_VertexShader* pxVertexShader );
	static void		SetFragmentShader		( const void* pxFragmentShaderConfig, bool bFPInMainMemory = false );
	static void		ClearLastFragmentShader	( void ) { s_pxFragmentShaderConfig = NULL; }

	static void		SetInRecordMode			( bool bInRecordMode ) { s_bInRecordMode = bInRecordMode; }

	static void		SetUseDepthBias			( bool bEnabled );
	static void		SetDepthBias			( float fUnits, float fFactor );

	static bool		GetStencilTestEnabled	( void ) { return s_bStencilEnabled; }
	static void		SetStencilTestEnabled	( bool bEnable );
	static void		SetStencilMask			( u_int uMask );
	static void		SetStencilFunction		( ASURA_PS3_STENCIL_FUNCTION eStencilFunction, u_int uiRef, u_int uiMask );
	static void		SetStencilOperation		( ASURA_PS3_STENCIL_OPERATION eStencilFail, ASURA_PS3_STENCIL_OPERATION eDepthFail, ASURA_PS3_STENCIL_OPERATION eDepthPass );

	static CellGcmSurface* GetSurface		( void ) { return s_pxSurface; };
	static void		SetSurface				( CellGcmSurface* pxSurface );
	static void		ClearSurface			( void ) { s_pxSurface = NULL; }

    static void SetViewport( u_int uX, u_int uY, u_int uWidth, u_int uHeight,
                             float fViewportOutputMinZ = fASURA_PS3_DEFAULT_VIEWPORT_MIN_Z, float fViewportOutputMaxZ = fASURA_PS3_DEFAULT_VIEWPORT_MAX_Z,
                             float fViewportClipMinZ = fASURA_PS3_DEFAULT_VIEWPORT_MIN_Z, float fViewportClipMaxZ = fASURA_PS3_DEFAULT_VIEWPORT_MAX_Z,
                             bool bScaleToSurface = true );

    static void SetViewport( u_int uWidth, u_int uHeight )
	{
		SetViewport( 0, 0, uWidth, uHeight );
	}
    static u_int GetViewportX( void ) { return s_uViewportX; }
    static u_int GetViewportY( void ) { return s_uViewportY; }
    static u_int GetViewportWidth( void ) { return s_uViewportWidth; }
    static u_int GetViewportHeight( void ) { return s_uViewportHeight; }
    static float GetViewportOutputMinZ( void ) { return s_fViewportOutputMinZ; }
    static float GetViewportOutputMaxZ( void ) { return s_fViewportOutputMaxZ; }
    static float GetViewportClipMinZ( void ) { return s_fViewportClipMinZ; }
    static float GetViewportClipMaxZ( void ) { return s_fViewportClipMaxZ; }


	static void		RequestWireFrameMode	( bool bWireFrameMode );
	static void		RequestZBufferEnabled	( bool bZBufferEnabled );
	static void		RequestZBufferCompareMode( enum ASURA_ZBUFFERCMP_ID eMode );
	static void		RequestZBufferWriteEnabled( bool bZBufferWriteEnabled );
	static bool		GetZBufferWriteEnabled() { return s_bZBufferWriteEnabled; }
	static void		RequestTranslucencyMode	( enum ASURA_TRANSLUCENCY_MODE eMode );
	static void		InvalidateTranslucencyMode	() { s_eTranslucencyMode = ASURA_TRANSLUCENCY_NOT_SET; }
	static void		SetAlphaBlending		( bool bAlphaBlending );
	static void		RequestAlphaTest		( bool bAlphaTest, int iRefValue = iASURA_ALPHATEST_REF_DEFAULT );
	static void		SetAlphaTestRefValue	( int iRefValue );
	static void		RequestCullMode			( enum ASURA_CULLMODE_ID eMode );
	static void		SetCullFace				( bool bCullFace );
	static void		SetRestartIndex			( u_int uiRestartIndex );

	static bool		SetTextureOffsetNeeded	( u_char ucTextureIndex, u_int uTextureOffset );
	static bool		SetTextureFormatNeeded	( u_char ucTextureIndex, u_int uTextureFormat );
	static bool		SetTextureAddressNeeded	( u_char ucTextureIndex, u_int uTextureAddress );
	static bool		SetTextureControl0Needed( u_char ucTextureIndex, u_int uTextureControl0 );
	static bool		SetTextureControl1Needed( u_char ucTextureIndex, u_int uTextureControl1 );
	static bool		SetTextureControl2Needed( u_char ucTextureIndex, u_int uTextureControl2 );
	static bool		SetTextureControl3Needed( u_char ucTextureIndex, u_int uTextureControl3 );
	static bool		SetTextureFilterNeeded	( u_char ucTextureIndex, u_int uTextureFilter );
	static bool		SetTextureRectNeeded	( u_char ucTextureIndex, u_int uTextureRect );
	static void		SetTextureMacro			( u_char iTextureChannel, Asura_PS3_Texture* pxTexture, u_int uiTextureAddress, u_int uiTextureControl0, u_int uiTextureControl2, u_int uiTextureFilter );
	static void		SetSRGBWriteEnabled		( bool bEnabled );
	static bool		GetSRGBWriteEnabled		( void ) { return s_bSRGBWriteEnabled; }
	
	static void		SetLineWidth			( float fLineWidth );
	
protected:
private:
	static bool									s_BlendEnableMrt1;
	static bool									s_BlendEnableMrt2;
	static bool									s_BlendEnableMrt3;

	static u_int								s_uColorMaskMRT0;
	static u_int								s_uColorMaskMRT123;

	static CellGcmEnum							s_eMinFilter[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static CellGcmEnum							s_eMagFilter[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static CellGcmEnum							s_eConvolutionFilter[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static ASURA_PS3_TEXTURE_OPTIMIZATION		s_eTextureOptimization[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static bool									s_bUse_sRGBConversion[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static bool									s_bTextureEnable[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static CellGcmEnum							s_eTextureAniso[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static CellGcmEnum							s_eTextureAddressModeS[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static CellGcmEnum							s_eTextureAddressModeT[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static CellGcmEnum							s_eTextureAddressModeR[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static u_int								s_uiTextureOffset[ ASURA_PS3_MAXIMUM_TEXTURES ]; // offset
	static u_int								s_uiTextureFormat[ ASURA_PS3_MAXIMUM_TEXTURES ]; // format (location, cubemap, dimension, format, mipmap)
	static u_int								s_uiTextureAddress[ ASURA_PS3_MAXIMUM_TEXTURES ]; // address (wraps, wrapt, wrapr, ...)
	static u_int								s_uiTextureControl0[ ASURA_PS3_MAXIMUM_TEXTURES ]; //  minlod, maxlod, maxaniso
	static u_int								s_uiTextureControl1[ ASURA_PS3_MAXIMUM_TEXTURES ]; //Remap
	static u_int								s_uiTextureControl2[ ASURA_PS3_MAXIMUM_TEXTURES ]; //minlod, maxlod, maxaniso
	static u_int								s_uiTextureControl3[ ASURA_PS3_MAXIMUM_TEXTURES ]; // pitch, depth
	static u_int								s_uiTextureFilter[ ASURA_PS3_MAXIMUM_TEXTURES ]; // filter ( min, mag, conv )
	static u_int								s_uiTextureImageRect[ ASURA_PS3_MAXIMUM_TEXTURES ]; // width, height
	static u_int								s_auTextureBorderColour[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static const void*							s_pxTexture[ ASURA_PS3_MAXIMUM_TEXTURES ];
	static bool									s_abNormalizedCoordinates[ ASURA_PS3_MAXIMUM_TEXTURES ];

	static u_short								s_usVertexBufferFrequency[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];
	static u_char								s_ucVertexBufferStride[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];
	static u_char								s_ucVertexBufferSize[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];
	static u_char								s_ucVertexBufferType[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];
	static u_char								s_ucVertexBufferLocation[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];
	static u_int								s_uiVertexBufferOffset[ ASURA_PS3_MAXIMUM_VERTEX_BUFFER_ARRAYS ];

	static u_int								s_uiRestartIndex;

	static bool									s_bInRecordMode;
	static bool									s_bUseDepthBias;
	static bool									s_bWireFrameMode;
	static bool									s_bZBufferEnabled;
	static bool									s_bZBufferWriteEnabled;
	static bool									s_bAlphaBlending;
	static bool									s_bAlphaTest;
	static bool									s_bCullFace;
	static bool									s_bSRGBWriteEnabled;

	static bool									s_bStencilEnabled;
	static ASURA_PS3_STENCIL_FUNCTION			s_eStencilFunction;
	static ASURA_PS3_STENCIL_OPERATION			s_eStencilFail;
	static ASURA_PS3_STENCIL_OPERATION			s_eDepthFail;
	static ASURA_PS3_STENCIL_OPERATION			s_eDepthPass;
	static u_int								s_uiStencilRef;
	static u_int								s_uiStencilFunctionMask;
	static u_int								s_uiStencilMask;

	static int									s_iAlphaTestRef;

	static enum	ASURA_ZBUFFERCMP_ID				s_eZBufferCompareMode;
	static enum ASURA_TRANSLUCENCY_MODE			s_eTranslucencyMode;
	static enum ASURA_CULLMODE_ID				s_eCullMode;

	static float								s_fDepthBiasFactor;
	static float								s_fDepthBiasUnits;

	static int									s_iLineWidth;

	static const void*							s_pxFragmentShaderConfig;
	static const void*							s_pxVertexShaderConfig;
	static const void*							s_pxVertexShaderAddress;
	
	static CellGcmSurface*						s_pxSurface;

	static u_int								s_uViewportX;
    static u_int								s_uViewportY;
    static u_int								s_uViewportWidth;
    static u_int								s_uViewportHeight;
    static float								s_fViewportOutputMinZ;
    static float								s_fViewportOutputMaxZ;
    static float								s_fViewportClipMinZ;
    static float								s_fViewportClipMaxZ;
    static bool									s_bViewportScaleToSurface;


	Asura_PS3_RenderingStates();
	~Asura_PS3_RenderingStates();
};

#endif //#ifndef __ASURA_PS3_RENDERING_STATES_H__
