
#ifndef _INC_MRender_Classes
#define _INC_MRender_Classes

/*ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ*\
	File:			Classes related to the render context interface.

	Author:			Magnus Högdahl

	Copyright:		1996-2001 Starbreeze Studios AB

	History:
		010827:		Created file. Moved stuff from MRender.h

\*____________________________________________________________________________________________*/

#if defined( PLATFORM_XBOX1 ) || defined(PLATFORM_PS2)
#define	DEF_CRC_MAXTEXTURES	4
#else
#define	DEF_CRC_MAXTEXTURES	8
#endif

enum
{
	CRC_MAXTEXTUREENV			= 4,	// Maximum number of supported textures coordinates.
#if	(DEF_CRC_MAXTEXTURES==4)
	CRC_MAXTEXCOORDS			= 4,	// Maximum number of supported textures coordinates.
	CRC_MAXTEXTURES				= 4,	// Maximum number of supported textures channels. (Multitexture) Affects CRC_MATRIXSTACKS
#else
	CRC_MAXTEXCOORDS			= 8,	// Maximum number of supported textures coordinates.
	CRC_MAXTEXTURES				= 16,	// Maximum number of supported textures channels. (Multitexture) Affects CRC_MATRIXSTACKS
#endif
	CRC_MAXLIGHTS				= 8,	// Maximum simultaneous lights.
	CRC_NUMTEXCOORDCOMP			= 4,	// U,V,W,?  ehum...   S,T,R,Q..

	CRC_ATTRIBSTACKDEPTH		= 48,
	CRC_MATRIXSTACKDEPTH		= 12,
	CRC_VIEWPORTSTACKDEPTH		= 4,
	CRC_MATRIXSTACKS			= 2 + CRC_MAXTEXCOORDS,

	CRC_MAXPOLYGONVERTICES		= 32,

	CRC_DEFAULT_FRONTPLANE		= 4,
	CRC_DEFAULT_BACKPLANE		= 2048,
	CRC_DEFAULT_FOV				= 90,

	CRC_MAXPICMIPS				= 16,
};

//----------------------------------------------------------------
// Instructions for RenderIndexedPrimitives()
//----------------------------------------------------------------
enum
{
	CRC_RIP_END				= 0,
	CRC_RIP_TRIANGLES		= 1,
	CRC_RIP_QUADS			= 2,
	CRC_RIP_TRISTRIP		= 3,
	CRC_RIP_TRIFAN			= 4,
	CRC_RIP_QUADSTRIP		= 5,
	CRC_RIP_POLYGON			= 6,
	CRC_RIP_PRIMLIST		= 7,		// A primitive list in a prim list
	CRC_RIP_TEXT			= 8,
	CRC_RIP_PARTICLES		= 9,
	CRC_RIP_TYPEMASK		= 0x0f,


	CRC_RIP_COPLANAR		= 0x40,		// All faces in primitive lay in the same plane.
	CRC_RIP_COPLANARLAST	= 0x80,		// All faces in primitive lay in last primitive's plane.
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_ClipVolume
|__________________________________________________________________________________________________
\*************************************************************************************************/
#define CRC_CLIPVOLUME_MAXPLANES 16

class SYSTEMDLLEXPORT CRC_ClipVolume:public CReferenceCount
{
public:

	DECLARE_OPERATOR_NEW


	int m_nPlanes;
	CVec3Dfp4 m_POV;
	CVec3Dfp4 m_Vertices[CRC_CLIPVOLUME_MAXPLANES];
	CPlane3Dfp4 m_Planes[CRC_CLIPVOLUME_MAXPLANES];

	CRC_ClipVolume();
	const CRC_ClipVolume& operator = (const CRC_ClipVolume &ToCopy)
	{
#ifdef	PLATFORM_PS2
		PS2WordCopy( this, &ToCopy, sizeof(*this) / 4 );
#else
		memcpy(this, &ToCopy, sizeof(*this));
#endif

		return *this;
	}

	CRC_ClipVolume(const CRC_ClipVolume &ToCopy)
	{
#ifdef	PLATFORM_PS2
		PS2WordCopy( this, &ToCopy, sizeof(*this) / 4 );
#else
		memcpy(this, &ToCopy, sizeof(*this));
#endif
	}


	void Init(const CVec3Dfp4& _POV);
	void GetVertices(const CVec3Dfp4* _pVertices, int _nVertices, const CVec3Dfp4& _POV, bool _bFlipDirection);
	void CreateFromVertices();
	void CreateFromVertices2();
	void CreateFromVertices3(const CPlane3Dfp4& _ProjPlane);

	void Invert();
	void Transform(const CMat43fp4& _Mat);

	void Copy(const CRC_ClipVolume& _SrcClip);
	void CopyAndTransform(const CRC_ClipVolume& _SrcClip, const CMat43fp4& _pMat);

	int BoxInVolume(const CBox3Dfp4& _Box) const;
	int SphereInVolume(const CVec3Dfp4& _v, fp4 _r) const;
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_Light
|__________________________________________________________________________________________________
\*************************************************************************************************/
#define CRC_LIGHTTYPE_POINT			0
#define CRC_LIGHTTYPE_SPOT			1
#define CRC_LIGHTTYPE_PARALLELL		2
#define CRC_LIGHTTYPE_AMBIENT		3

class CRC_Light		// 12*4 = 48 bytes
{
public:
	int32 m_Type;
	CPixel32 m_Color;
	CPixel32 m_Ambient;
	CVec3Dfp4 m_Pos;
	CVec3Dfp4 m_Direction;
	fp4 m_Attenuation[3];		// Constant, Linear and Quadratic attenuation.

	CRC_Light()
	{
		m_Type = CRC_LIGHTTYPE_POINT;
		m_Color = 0xffffffff;
		m_Ambient = 0x00000000;
		m_Pos = 0;
		m_Direction = 0;
		m_Attenuation[0] = 0;
		m_Attenuation[1] = 0;
		m_Attenuation[2] = 0;
	}
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_VertexBuffer
|__________________________________________________________________________________________________
\*************************************************************************************************/
class SYSTEMDLLEXPORT CRC_VertexBuffer
{
public:
	uint32 m_nV:16;
	uint32 m_nMWComp:16;		// Weight components per vertex, allowed range is [0..4] (works as m_nTVComp)

	CVec3Dfp4* m_pV;
	fp4* m_pTV[CRC_MAXTEXCOORDS];
	uint8  m_nTVComp[CRC_MAXTEXCOORDS];
	CVec3Dfp4* m_pN;
	CPixel32* m_pCol;

	CPixel32* m_pSpec;
/*	fp4* m_pFog;
	*/

	uint32* m_pMI;		// Matrix index array, Points to an array of uint32[nV] (uint8[nV][4])  256 matrices _should_ be enough for a while, but I'll probably regrett this much sooner than I think.  /mh
	fp4* m_pMW;			// Matrix weight array, Points to an array of fp4[nV][m_nMatricesPerVertex];

	// Disable the color because it does not belong here
//	CPixel32 m_Color;	// Constant color, ignored if m_pCol != NULL;

	uint16* m_piPrim;
	uint16 m_nPrim;
	int16 m_PrimType;

	void Clear()
	{
		m_nV = 0;
		m_pV = NULL;
		for(int i = 0; i < CRC_MAXTEXCOORDS; i++) { m_pTV[i] = NULL; m_nTVComp[i] = 0; }
		m_pN = NULL;
		m_pCol = NULL;
		m_pSpec = NULL;
//		m_pFog = NULL;
		m_pMI = NULL;
		m_pMW = NULL;
		m_nMWComp = 0;

//		m_Color = 0xffffffff;

		m_piPrim = NULL;
		m_nPrim = NULL;
		m_PrimType = NULL;
	}

	CRC_VertexBuffer()
	{
		Clear();
	}
};

#ifdef	PLATFORM_PS2
typedef CMat4Dfp4 CMat43fp4_MP;
#else
typedef TMatrix43<fp4> CMat43fp4_MP;
#endif

/***************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_MatrixPalette
|___________________________________________________________________________________________________
\***************************************************************************************************/

enum ERC_MatrixPaletteFlags
{
	 ERC_MatrixPaletteFlags_SpecialCubePosition = DBit(0)
	,ERC_MatrixPaletteFlags_SpecialCubeTexture = DBit(1)
	,ERC_MatrixPaletteFlags_SpecialCubeTextureScaleByZ = DBit(2)
	,ERC_MatrixPaletteFlags_SpecialCubeTextureScale2 = DBit(3)
	,ERC_MatrixPaletteFlags_DoNotCache = DBit(4)
	,ERC_MatrixPaletteFlags_SpecialCubeFlags = ERC_MatrixPaletteFlags_SpecialCubePosition | ERC_MatrixPaletteFlags_SpecialCubeTexture | ERC_MatrixPaletteFlags_SpecialCubeTextureScale2 | ERC_MatrixPaletteFlags_SpecialCubeTextureScaleByZ
};

class SYSTEMDLLEXPORT CRC_MatrixPalette
{
public:
    const void* m_pMatrices;
    const uint16* m_piMatrices;
    uint32 m_nMatrices;
	uint32 m_Flags;

	const CMat43fp4_MP &Index(int _Index) const
	{
		if (m_piMatrices)
			return ((const CMat43fp4_MP*)m_pMatrices)[m_piMatrices[_Index]];
		else
			return ((const CMat43fp4_MP*)m_pMatrices)[_Index];
	}
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_Viewport
|__________________________________________________________________________________________________
\*************************************************************************************************/
class SYSTEMDLLEXPORT CRC_Viewport
{
	// Big stuff first
	CMat4Dfp4 m_PMat;					// Projection matrix
	CVec3Dfp4 m_VViewVertices[8];		// Viewport space by vertices
	CPlane3Dfp4 m_VViewPlanes[4];		// Viewport space
	CVec2Dfp4 m_PixelAspect;
	CClipRect m_Clip;					// The clipping area.

	enum
	{
		VP_MODE_FOV = 0,
		VP_MODE_SCALE,
	};

	int m_Mode;
	fp4 m_FOV;
	fp4 m_FOVAspect;
	fp4 m_Scale;
	fp4 m_AspectRatio;
	fp4 m_xScale;
	fp4 m_yScale;
	fp4 m_FrontPlane;
	fp4 m_BackPlane;
	CRct m_Rect;						// The desired view, before clipping.
	// Viewport geometry, in view-space
	int m_nViewVertices;
	bool m_bVPChanged;

	void Update();

public:


	DECLARE_OPERATOR_NEW

	CRC_Viewport();
	~CRC_Viewport();
	
	const CRC_Viewport& operator = (const CRC_Viewport &ToCopy)
	{
		memcpy(this, &ToCopy, sizeof(CRC_Viewport));

		return *this;
	}

	CRC_Viewport(const CRC_Viewport &ToCopy)
	{
		memcpy(this, &ToCopy, sizeof(CRC_Viewport));
	}


	void SetBorder(CVec2Dfp4 _Border, bool _bRemove = false); // Adds a border to the viewport, (0, 0) removes it
		
	void SetFOV(fp4 _fp);
	void SetFOVAspect(fp4 _Aspect);
	void SetScale(fp4 _Scale);
	void SetAspectRatio(fp4 _Aspect);
	void SetPixelAspect(fp4 _AspectX, fp4 _AspectY);
	void SetFrontPlane(fp4 _FrontPlane);
	void SetBackPlane(fp4 _BackPlane);
	void SetView(const CClipRect& clip, const CRct& rect);
	void SetView(CImage* pImg);

	const CMat4Dfp4& GetProjectionMatrix();
	void GetClipVolume(CRC_ClipVolume& _Clip, const CMat43fp4* _pViewWMat = NULL);

	int GetNumViewVertices();
	const CVec3Dfp4* GetViewVertices();
	const CPlane3Dfp4* GetViewPlanes();

	static void DebugViewControl(CMat4Dfp4& mat, fp4 Ctrl_x, fp4 Ctrl_z, fp4 Ctrl_y, fp4 Ctrl_xaxis, fp4 Ctrl_yaxis, fp4 _apan1);

	fp4 GetFOV() const { return m_FOV; };
	fp4 GetFOVAspect() const { return m_FOVAspect; };
	fp4 GetScale() { Update(); return m_Scale; };
	fp4 GetAspectRatio() const { return m_AspectRatio; };
	fp4 GetFrontPlane() const { return m_FrontPlane; };
	fp4 GetBackPlane() const { return m_BackPlane; };
	fp4 GetXScale() { Update(); return m_xScale; };
	fp4 GetYScale() { Update(); return m_yScale; };
	const CClipRect& GetViewClip() const { return m_Clip; };
	const CRct& GetViewRect() const { return m_Rect; };
	CRct GetViewArea() const;

	int SphereInView(const CVec3Dfp4& p, fp4 _Radius);
};

// -------------------------------------------------------------------
//  Caps & GlobalVar enums
// -------------------------------------------------------------------
//#if !defined(PLATFORM_CONSOLE) || defined(PLATFORM_XENON) || defined()
#define SUPPORT_FRAGMENTPROGRAM
//#endif

enum
{
	CRC_GLOBALFLAGS_WIRE		= 1,
	CRC_GLOBALFLAGS_TEXTURE		= 2,

	CRC_GLOBALVAR_FILTER		= 0,
	CRC_GLOBALVAR_GAMMARAMPSCALE = 1,
	CRC_GLOBALVAR_GAMMARAMPADD	= 2,
	CRC_GLOBALVAR_GAMMA			= 3,
	CRC_GLOBALVAR_WIRE			= 4,
	CRC_GLOBALVAR_ALLOWTEXTURELOAD = 5,

	CRC_GLOBALVAR_NUMTEXTURES	= 10,				// Number of multitexture units
	CRC_GLOBALVAR_NUMAUTOMIP	= 11,
	CRC_GLOBALVAR_NUMTEXTUREENV	= 12,				// Number of texture environments
	CRC_GLOBALVAR_NUMTEXTURECOORDS = 13,			// Number of texture coordinates
	CRC_GLOBALVAR_TOTALTRIANGLES = 20, 

	CRC_GLOBALFILTER_POINT		= 0,
	CRC_GLOBALFILTER_BILINEAR	= 1,
	CRC_GLOBALFILTER_TRILINEAR	= 2,

	// -------------------------------------------------------------------
	CRC_CAPS_FLAGS_HWAPI					= DBit(0),
//	CRC_CAPS_FLAGS_FULLBLENDING				= DBit(1),		// I don't think this is relevant any longer  :)   -mh
	CRC_CAPS_FLAGS_RENDERTEXTUREVERTICALFLIP= DBit(1),
	CRC_CAPS_FLAGS_GAMMARAMP				= DBit(2),
	CRC_CAPS_FLAGS_SPECULARCOLOR			= DBit(3),
	CRC_CAPS_FLAGS_COPYDEPTH				= DBit(4),
	CRC_CAPS_FLAGS_CUBEMAP					= DBit(5),
	CRC_CAPS_FLAGS_MATRIXPALETTE			= DBit(6),
	CRC_CAPS_FLAGS_OFFSCREENTEXTURERENDER	= DBit(7),
	CRC_CAPS_FLAGS_OCCLUSIONQUERY			= DBit(8),
	CRC_CAPS_FLAGS_READDEPTH				= DBit(9),
	CRC_CAPS_FLAGS_TEXGENMODE_ENV			= DBit(10),
	CRC_CAPS_FLAGS_TEXGENMODE_ENV2			= DBit(11),
	CRC_CAPS_FLAGS_TEXGENMODE_LINEARNHF     = DBit(12),
	CRC_CAPS_FLAGS_TEXGENMODE_BOXNHF        = DBit(13),
	CRC_CAPS_FLAGS_EXTATTRIBUTES_TEXENV		= DBit(14), // 65536
	CRC_CAPS_FLAGS_EXTATTRIBUTES_NV10		= DBit(15),
	CRC_CAPS_FLAGS_EXTATTRIBUTES_NV20		= DBit(16),
	CRC_CAPS_FLAGS_GAMECUBE					= DBit(17),
	CRC_CAPS_FLAGS_TEXENVMODE_COMBINE		= DBit(18),
	CRC_CAPS_FLAGS_TEXENVMODE2	 			= DBit(19),
	CRC_CAPS_FLAGS_VBOPERATOR_WAVE			= DBit(20),
	CRC_CAPS_FLAGS_ARBITRARY_TEXTURE_SIZE	= DBit(21),
	CRC_CAPS_FLAGS_BACKBUFFERASTEXTURE		= DBit(22),
	CRC_CAPS_FLAGS_FRONTBUFFERASTEXTURE		= DBit(23),
	CRC_CAPS_FLAGS_SEPARATESTENCIL 			= DBit(24),
	CRC_CAPS_FLAGS_FRAGMENTPROGRAM11	 	= DBit(25),
	CRC_CAPS_FLAGS_FRAGMENTPROGRAM14		= DBit(26),
	CRC_CAPS_FLAGS_FRAGMENTPROGRAM20		= DBit(27),
	CRC_CAPS_FLAGS_FRAGMENTPROGRAM30 		= DBit(28),
	CRC_CAPS_FLAGS_PRIMITIVERESTART			= DBit(29),

};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_Attributes
|__________________________________________________________________________________________________
\*************************************************************************************************/

/*
	if "RasterMode" != CRC_RASTERMODE_NONE
		Attemps to modify the following attributes are ignored;

	Flag: CRC_FLAGS_BLEND
	Flag: CRC_FLAGS_ALPHA
	SourceBlend,
	DestBlend
*/

// --- FLAGS ---

enum
{
	CRC_FLAGS_0x00000001			= 0x00000001,	// <- Free enum
	CRC_FLAGS_ZCOMPARE				= 0x00000002,
	CRC_FLAGS_ZWRITE				= 0x00000004,
	CRC_FLAGS_BLEND					= 0x00000008,
	CRC_FLAGS_SMOOTH				= 0x00000010,
	CRC_FLAGS_SCISSOR				= 0x00000020,
	CRC_FLAGS_FOG					= 0x00000040,
	CRC_FLAGS_SEPARATESTENCIL		= 0x00000080,	// m_StencilBackXxx attributes should be used
//	CRC_FLAGS_LIGHTMAP_COLORFIT		= 0x00000100,
	CRC_FLAGS_PERSPECTIVE			= 0x00000200,
	CRC_FLAGS_ALPHAWRITE			= 0x00000400,
	CRC_FLAGS_CULL					= 0x00000800,	// Face-culling
	CRC_FLAGS_CULLCW				= 0x00001000,	// Cull counter clockwise.
	CRC_FLAGS_CLIP					= 0x00002000,	// Clip all geometry to clipping planes..
	CRC_FLAGS_STENCIL				= 0x00004000,
	CRC_FLAGS_COLORWRITE			= 0x00008000,
	CRC_FLAGS_SECONDARYCOLOR		= 0x00010000,
//	CRC_FLAGS_FOGCOORD				= 0x00020000,
	CRC_FLAGS_POLYGONOFFSET			= 0x00040000,
	CRC_FLAGS_LIGHTING				= 0x00080000,	// Enable vertex lighting using lights provided with Attrib_SetLights. Normals must be supplied.

	// --- RASTERMODES ---
	CRC_RASTERMODE_NONE				= 0,		//  D = S,
	CRC_RASTERMODE_ALPHABLEND		= 1,		//  D = D*S.InvAlpha + S*S.Alpha,
	CRC_RASTERMODE_LIGHTMAPBLEND	= 2,		//  D = D*S, or  D*S.InvAlpha + S*SrcAlpha,
	CRC_RASTERMODE_MULTIPLY			= 3,		//  D = D*S,
	CRC_RASTERMODE_ADD				= 4,		//  D = D + S,
	CRC_RASTERMODE_ALPHAADD			= 5,		//  D = D + S*S.Alpha,
	CRC_RASTERMODE_ALPHAMULTIPLY	= 6,		//  D = D*S.InvAlpha + S*D,
	CRC_RASTERMODE_MULTIPLY2		= 7,		//  D = D*S + S*D,
	CRC_RASTERMODE_MULADD			= 8,		//  D = D + S*D,
	CRC_RASTERMODE_ONE_ALPHA		= 9,		//  D = S + D*S.Alpha,
	CRC_RASTERMODE_ONE_INVALPHA		= 10,		//  D = S + D*S.InvAlpha,
	CRC_RASTERMODE_DESTALPHABLEND	= 11,		//  D = D*D.InvAlpha + S*D.Alpha,
	CRC_RASTERMODE_DESTADD			= 12,		//  D = D + D*S.Alpha
	CRC_RASTERMODE_MULADD_DESTALPHA = 13,		//  D = D + S*D.Alpha

	// Clear What
	CRC_CLEAR_COLOR					= DBit(0),
	CRC_CLEAR_ZBUFFER				= DBit(1),
	CRC_CLEAR_STENCIL				= DBit(2),

	// _CopyType enums for RenderTarget_Copy
	CRC_COPYTYPE_NORMAL				= 0,
	CRC_COPYTYPE_DEPTHTOCOLOR		= 1,

	// --- BLENDINGMODES ---
	CRC_BLEND_ZERO				= 1,
	CRC_BLEND_ONE				= 2,
	CRC_BLEND_SRCCOLOR			= 3,
	CRC_BLEND_INVSRCCOLOR		= 4,
	CRC_BLEND_SRCALPHA			= 5,
	CRC_BLEND_INVSRCALPHA		= 6,
	CRC_BLEND_DESTALPHA			= 7,
	CRC_BLEND_INVDESTALPHA		= 8,
	CRC_BLEND_DESTCOLOR			= 9,
	CRC_BLEND_INVDESTCOLOR		= 10,
	CRC_BLEND_SRCALPHASAT		= 11,

	// --- Z/ALPHA-COMPARES ---
	CRC_COMPARE_NEVER			= 1,
	CRC_COMPARE_LESS			= 2,
	CRC_COMPARE_EQUAL			= 3,
	CRC_COMPARE_LESSEQUAL		= 4,
	CRC_COMPARE_GREATER			= 5,
	CRC_COMPARE_NOTEQUAL		= 6,
	CRC_COMPARE_GREATEREQUAL	= 7,
	CRC_COMPARE_ALWAYS			= 8,

	// --- TEXTURE-ENVIRONMENT MODES ---
	CRC_TEXENVMODE_MULTIPLY		= 0,
	CRC_TEXENVMODE_BLEND		= 1,
	CRC_TEXENVMODE_REPLACE		= 2,
	CRC_TEXENVMODE_COMBINE_ADD		= 3,			// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required (Note: Supported on GameCube)
	CRC_TEXENVMODE_COMBINE_SUBTRACT	= 4,			// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required (Note: Supported on GameCube)
	CRC_TEXENVMODE_COMBINE_DOT3		= 5,			// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required
	CRC_TEXENVMODE_COMBINE_LERP		= 6,			// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required, Src0*Src2 + Src1*(1-Src2)
	CRC_TEXENVMODE_COMBINE_MULTIPLY2 = 7,			// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required
	CRC_TEXENVMODE_COMBINE_SUBTRACTREVERSE= 8,		// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required

	// Combine default setting:
	//   Source0 = PREVIOUS
	//   Source1 = TEXTURE
	//   Source2 = CONSTANT
	//

	// Combine mode modifiers:						// CRC_CAPS_FLAGS_TEXENVMODE_COMBINE required for modifiers
	CRC_TEXENVMODE_RGB_SOURCE0_ALPHA			= 0x0080,
	CRC_TEXENVMODE_RGB_SOURCE1_ALPHA			= 0x0100,
	CRC_TEXENVMODE_RGB_SOURCE2_ALPHA			= 0x0200,
	CRC_TEXENVMODE_ALPHA_SOURCE0_COMPLEMENT		= 0x0400,
	CRC_TEXENVMODE_ALPHA_SOURCE1_COMPLEMENT		= 0x0800,
	CRC_TEXENVMODE_ALPHA_SOURCE2_COMPLEMENT		= 0x1000,
	CRC_TEXENVMODE_SOURCE1_CONSTANT				= 0x2000,
	CRC_TEXENVMODE_SOURCE1_PRIMARY				= 0x4000,
	CRC_TEXENVMODE_SOURCE2_PRIMARY				= 0x8000,

	/* The diffrent texturechannels in TEXENVMODE2
	CRC_TEXENVMODE2_NONE0		= 6,			// Out.rgb = Texture.rgb * Primary.rgb;
	CRC_TEXENVMODE2_NONE1		= 7,			// Out.rgb = Previus.rgb; Out.a = Texture.a * Primary.a;
	CRC_TEXENVMODE2_ALPHABLEND0	= 8,			// Out.rgb = Texture.rgb * Primary.rgb; Out.a = Texture.a * Primary.a;
	CRC_TEXENVMODE2_ALPHABLEND1	= 9,			// Tmp.rgb = Texture.rgb * Primary.rgb; Tmp.a = Texture.a * Primary.a;
	CRC_TEXENVMODE2_ALPHABLEND2	= 10,			// Current.rgb = Tmp.rgb*(1-Current.a) + Current.rgb*Current.a;
	CRC_TEXENVMODE2_MULADD0		= 11,			// Tmp.rgb = Texture.rgb;
	CRC_TEXENVMODE2_MULADD1		= 12,			// Out.rgb = Texture.rgb * Primary.rgb; Out.a = Texture.a * Primary.a;
	CRC_TEXENVMODE2_MULADD2		= 13,			// Out.rgb = Current.rgb + Current.rgb * Tmp.rgb; Out.a = Current.a
	CRC_TEXENVMODE2_MULTIPLY2_0	= 14,			// Out.rgb = Texture.rgb * Primary.rgb; 
	CRC_TEXENVMODE2_MULTIPLY2_1	= 15,			// Out.rgb = Texture.rgb * Current.rgb * 2; Out.a = Texture.a * Primary.a;
	*/
	CRC_TEXENVMODE2_NONE		= 12,			// Avail only if the CRC_CAPS_FLAGS_TEXENVMODE2 capability is set.
	CRC_TEXENVMODE2_ALPHABLEND	= 13,			// Avail only if the CRC_CAPS_FLAGS_TEXENVMODE2 capability is set.
	CRC_TEXENVMODE2_MULADD		= 14,			// Avail only if the CRC_CAPS_FLAGS_TEXENVMODE2 capability is set.
	CRC_TEXENVMODE2_MULTIPLY2	= 15,			// Avail only if the CRC_CAPS_FLAGS_TEXENVMODE2 capability is set.

	
	

	// --- PS2 TEXTURE ENVIRONMENT/RASTER MODES ---
	CRC_PS2_TEXENVMODE_REPLACE			= 0,	// bit 0-2 	-> TexEnvMode		
	CRC_PS2_TEXENVMODE_ADD				= 1,
	CRC_PS2_TEXENVMODE_BLEND			= 2,
	CRC_PS2_TEXENVMODE_ADDALPHA			= 3,
	CRC_PS2_TEXENVMODE_DESTADD			= 4,
	CRC_PS2_TEXENVMODE_ONEALPHA			= 5,
	CRC_PS2_TEXENVMODE_MULADD_DESTALPHA = 6,	// Dest = Dest.RGB + Source.RGB * Dest.A
	CRC_PS2_TEXENVMODE_INVISIBLE		= 7,
	
	CRC_PS2_TEXENVMODE_COLORBUFFER	= 8,		// bit 3 	-> mask/adr to FRAMEBUFFER/COLORBUFFER

	CRC_PS2_TEXENVMODE_RGBMASK		= 16,		// bit 4	-> bits 0-23 will be affected
	CRC_PS2_TEXENVMODE_ALPHAMASK	= 32,		// bit 5	-> bits 24-30 will be affected
	CRC_PS2_TEXENVMODE_STENCILMASK	= 64,		// bit 6	-> bit 31 will be affected

	CRC_PS2_TEXENVMODE_ADTEST		= 128,		// bit 7	-> alpha destination test is on
	CRC_PS2_TEXENVMODE_ASTEST		= 256,		// bit 8	-> alpha source test is on
	CRC_PS2_TEXENVMODE_ZWRITE		= 512,		// bit 9	-> zbuffer is written to

	CRC_PS2_TEXENVMODE_MODULATE		= 1024,		// bit 5	-> DECAL / MODULATE
	CRC_PS2_TEXENVMODE				= 0x8000,	// bit 15	-> TexEnvMode is a PS2 format

	// syntactic sugar
	CRC_PS2_TEXENVMODE_RGBAMASK		= CRC_PS2_TEXENVMODE_RGBMASK | CRC_PS2_TEXENVMODE_ALPHAMASK,
	CRC_PS2_TEXENVMODE_RGBASMASK	= CRC_PS2_TEXENVMODE_RGBMASK | CRC_PS2_TEXENVMODE_ALPHAMASK | CRC_PS2_TEXENVMODE_STENCILMASK,

	// --- TEXTURE-GENERATION MODES ---
	CRC_TEXGENMODE_TEXCOORD			= 0,		// TexCoord = TV
	CRC_TEXGENMODE_LINEAR			,			// VP-Mode only, TexCoord = V * M, modelspace
	CRC_TEXGENMODE_LINEARNHF		,			// VP-Mode only, TexCoord = ...
	CRC_TEXGENMODE_BOXNHF			,			// VP-Mode only, TexCoord = ...
	CRC_TEXGENMODE_VOID				,			// VP-Mode only, TexCoord is not written.
	CRC_TEXGENMODE_ENV2				,			// VP-Mode only, Q3 style dual-hemisphere-fake-env?

	CRC_TEXGENMODE_SCREEN			,			// GAMECUBE SPECIFIC TEXGENMODE.
	CRC_TEXGENMODE_SHADOWVOLUME2	,			// VP-Mode only
	CRC_TEXGENMODE_MSPOS			,			// VP-Mode only, Modelspace pixel position
	CRC_TEXGENMODE_CONSTANT			,			// VP-Mode only, TexCoord = Constant

	// Modes from here on use normal
	CRC_TEXGENMODE_NORMALMAP		,			// VP-Mode only, TexCoord = N, modelspace
	CRC_TEXGENMODE_REFLECTION		,			// VP-Mode only, TexCoord = V - 2*N*(V dot N), viewspace
	CRC_TEXGENMODE_ENV				,			// VP-Mode only, TexCoord.x = N.x, TexCoord.y = -N.y, viewspace
	CRC_TEXGENMODE_SHADOWVOLUME		,			// VP-Mode only
	CRC_TEXGENMODE_LIGHTING			,			// VP-Mode only, TexCoord.rgb = Diffuse lighting, 6 TexGenAttr

	// Modes from here on use tangents
	CRC_TEXGENMODE_BUMPCUBEENV		,			// VP-Mode only, TexCoord = <insert lots of math here>
	CRC_TEXGENMODE_TSREFLECTION		,			// VP-Mode only, TSREFLECTION = Tangent-space reflection vector, modelspace:
	CRC_TEXGENMODE_TSLV			    ,			// VP-Mode only, TSLV = Tangent-space light vector, modelspace:
                								//		TexCoord.x = (L - V) dot TangU
                								//		TexCoord.y = (L - V) dot TangV
                								//		TexCoord.z = (L - V) dot N
	CRC_TEXGENMODE_PIXELINFO		,			// VP-Mode only, Creates 4 sets of texture coordinates, Mat is typically a model-space to world transform.
                								//	this + 0: AnimatedVertexPosition * Mat
                								//	this + 1: Normal * Mat
                								//	this + 2: TangentU * Mat
                								//	this + 3: TangentV * Mat

	CRC_TEXGENMODE_DEPTHOFFSET		,			// VP-Mode only, Creates depth offseted texture coordinates
												//		TexCoord.x = TexCoord.x + EyeVecTangU * OffsetU / EyeVecN
												//		TexCoord.y = TexCoord.y + EyeVecTangV * OffsetV / EyeVecN
	CRC_TEXGENMODE_TANG_U			,			// VP-Mode only, TexCoord = TangU, Modelspace
	CRC_TEXGENMODE_TANG_V			,			// VP-Mode only, TexCoord = TangV, Modelspace
	CRC_TEXGENMODE_NULL			    ,			// VP-Mode only, TexCoord is written with 0
	CRC_TEXGENMODE_DECALTSTRANSFORM	,			// Texparam0..1 are transformed to tangent-space and used as tangents

	CRC_TEXGENMODE_FIRSTUSENORMAL = CRC_TEXGENMODE_NORMALMAP,
	CRC_TEXGENMODE_FIRSTUSETANGENT = CRC_TEXGENMODE_BUMPCUBEENV,

	CRC_TEXGENCOMP_U				= 1,
	CRC_TEXGENCOMP_V				= 2,
	CRC_TEXGENCOMP_W				= 4,
	CRC_TEXGENCOMP_Q				= 8,
	CRC_TEXGENCOMP_ALL				= 15,
	CRC_TEXGENCOMP_MASK				= 15,

/*	CRC_TEXGENMODE_MASK			= 15,
	CRC_TEXGENMODE_SHIFT_U		= 0,
	CRC_TEXGENMODE_SHIFT_V		= 4,
	CRC_TEXGENMODE_SHIFT_W		= 8,
	CRC_TEXGENMODE_SHIFT_Q		= 12,
	CRC_TEXGENMODE_MASK_U		= (CRC_TEXGENMODE_MASK << CRC_TEXGENMODE_SHIFT_U),
	CRC_TEXGENMODE_MASK_V		= (CRC_TEXGENMODE_MASK << CRC_TEXGENMODE_SHIFT_V),
	CRC_TEXGENMODE_MASK_W		= (CRC_TEXGENMODE_MASK << CRC_TEXGENMODE_SHIFT_W),
	CRC_TEXGENMODE_MASK_Q		= (CRC_TEXGENMODE_MASK << CRC_TEXGENMODE_SHIFT_Q),*/

	// --- MATRIX MODES ---
	CRC_MATRIX_MODEL			= 0,
	CRC_MATRIX_PROJECTION		= 1,

	CRC_MATRIX_TEXTURE0			= 2, CRC_MATRIX_TEXTURE = 2,
	CRC_MATRIX_TEXTURE1			= 3,
	CRC_MATRIX_TEXTURE2			= 4,
	CRC_MATRIX_TEXTURE3			= 5,
#if	(DEF_CRC_MAXTEXTURES==4)
	CRC_MATRIX_PALETTE			= 6,			// Not in matrix stack, shift value used for update mask.
#else
	CRC_MATRIX_TEXTURE4			= 6,
	CRC_MATRIX_TEXTURE5			= 7,
	CRC_MATRIX_TEXTURE6			= 8,
	CRC_MATRIX_TEXTURE7			= 9,

	CRC_MATRIX_PALETTE			= 10,			// Not in matrix stack, shift value used for update mask.
#endif

	// --- STENCIL OPERATIONS ---
	CRC_STENCILOP_NONE			= 0,
	CRC_STENCILOP_ZERO			= 1,
	CRC_STENCILOP_REPLACE		= 2,
	CRC_STENCILOP_INC			= 3,
	CRC_STENCILOP_DEC			= 4,
	CRC_STENCILOP_INVERT		= 5,
	CRC_STENCILOP_INCWRAP		= 6,
	CRC_STENCILOP_DECWRAP		= 7,
};

//----------------------------------------------------------------
enum
{
	CRC_ATTRCHG_RASTERMODE		= DBit(0),
	CRC_ATTRCHG_BLEND			= DBit(1),
	CRC_ATTRCHG_ZCOMPARE		= DBit(2),
	CRC_ATTRCHG_TEXTUREID		= DBit(3),
	CRC_ATTRCHG_TEXENVMODE		= DBit(4),
	CRC_ATTRCHG_TEXENVCOLOR		= DBit(5),
	CRC_ATTRCHG_ALPHACOMPARE	= DBit(6),
	CRC_ATTRCHG_FOG				= DBit(7),
	CRC_ATTRCHG_POLYGONOFFSET	= DBit(8),
	CRC_ATTRCHG_STENCIL			= DBit(9),
	CRC_ATTRCHG_TEXGEN			= DBit(10),
	CRC_ATTRCHG_MATRIXPALETTE	= DBit(11),
	CRC_ATTRCHG_MATRIX			= DBit(12),	// Any transform
	CRC_ATTRCHG_SCISSOR			= DBit(13),
	CRC_ATTRCHG_EXATTR			= DBit(14),
	CRC_ATTRCHG_TEXGENCOMP		= DBit(15),
	CRC_ATTRCHG_TEXGENATTR		= DBit(16),
	CRC_ATTRCHG_TEXCOORDSET		= DBit(17),
	CRC_ATTRCHG_LIGHTING		= DBit(18),
	CRC_ATTRCHG_FLAG_FOG		= DBit(19),
	CRC_ATTRCHG_FLAG_STENCIL	= DBit(20),
	CRC_ATTRCHG_FLAG_ALHPAWRITE = DBit(21),
	CRC_ATTRCHG_FLAG_BLEND		= DBit(22),
	CRC_ATTRCHG_VB_FLAGS		= DBit(23),
	CRC_ATTRCHG_FLAG_OTHER		= DBit(24),

	CRC_ATTRCHG_OTHER			= CRC_ATTRCHG_EXATTR | CRC_ATTRCHG_TEXGENCOMP | CRC_ATTRCHG_TEXGENATTR | CRC_ATTRCHG_TEXCOORDSET | CRC_ATTRCHG_LIGHTING,

	CRC_ATTRCHG_FLAGS			= CRC_ATTRCHG_FLAG_FOG | CRC_ATTRCHG_FLAG_STENCIL | CRC_ATTRCHG_FLAG_ALHPAWRITE | CRC_ATTRCHG_FLAG_BLEND | CRC_ATTRCHG_FLAG_OTHER,
};

// -------------------------------------------------------------------
//  CRC_ExtAttributes
// -------------------------------------------------------------------
enum
{
	CRC_ATTRIBTYPE_INVALID				= 0,
	CRC_ATTRIBTYPE_NV10					= 1,
	CRC_ATTRIBTYPE_NV20					= 2,

	CRC_ATTRIBTYPE_FP11					= 3,
	CRC_ATTRIBTYPE_FP14					= 4,
	CRC_ATTRIBTYPE_FP20					= 5,
	CRC_ATTRIBTYPE_FP30					= 6,
};

class SYSTEMDLLEXPORT CRC_ExtAttributes
{
public:
	int m_AttribType;
};

// -------------------------------------------------------------------
//  CRC_ExtAttributes_FragmentProgram
// -------------------------------------------------------------------
class CRC_ExtAttributes_FragmentProgram11 : public CRC_ExtAttributes
{
public:
	const char *m_pProgramName;
	CPixel32 m_Colors[16];

	void Clear()
	{
		m_AttribType = CRC_ATTRIBTYPE_FP11;
		m_pProgramName = NULL;
	}
};

class CRC_ExtAttributes_FragmentProgram14 : public CRC_ExtAttributes
{
public:
	const char *m_pProgramName;
	uint32 m_ProgramNameHash;
	CVec4Dfp4* m_pParams;
	int m_nParams;

	void Clear()
	{
		m_AttribType = CRC_ATTRIBTYPE_FP14;
		m_pProgramName = NULL;
		m_ProgramNameHash = 0;
		m_pParams = NULL;
		m_nParams = 0;
	}

	void SetProgram(const char* _pProgramName, uint32 _ProgramNameHash)
	{
		m_pProgramName = _pProgramName;
		m_ProgramNameHash = _ProgramNameHash;
	}

	void SetParameters(CVec4Dfp4* _pParams, int _nParams)
	{
		m_pParams = _pParams;
		m_nParams = _nParams;
	}
};

class CRC_ExtAttributes_FragmentProgram20 : public CRC_ExtAttributes_FragmentProgram14
{
public:
	void Clear()
	{
		CRC_ExtAttributes_FragmentProgram14::Clear();
		m_AttribType = CRC_ATTRIBTYPE_FP20;
	}
};

class CRC_ExtAttributes_FragmentProgram30 : public CRC_ExtAttributes_FragmentProgram14
{
public:
	void Clear()
	{
		CRC_ExtAttributes_FragmentProgram14::Clear();
		m_AttribType = CRC_ATTRIBTYPE_FP30;
	}
};


//----------------------------------------------------------------
class SYSTEMDLLEXPORT CRC_Attributes// : public CObj
{
public:
	CRC_ExtAttributes* m_pExtAttrib;
	const CRC_Light* m_pLights;

	uint16 m_TextureID[CRC_MAXTEXTURES];
	// Texture-state
	uint16 m_nLights;
#if	DEF_CRC_MAXTEXTURES == 4
	uint16 m_TexGenComp;																// 4-bit per texture coord, 4 * CRC_MAXTEXTURES = 16
#else
	uint32 m_TexGenComp : (CRC_NUMTEXCOORDCOMP*CRC_MAXTEXCOORDS);						// 4-bit per texture coord, 4 * CRC_MAXTEXCOORDS = 32
#endif
	uint8 m_lTexGenMode[CRC_MAXTEXCOORDS];
	uint8 m_iTexCoordSet[CRC_MAXTEXCOORDS];
#ifdef PLATFORM_PS2
	uint16 m_TexEnvMode[CRC_MAXTEXTUREENV];
#else
	uint16 m_TexEnvMode[CRC_MAXTEXTUREENV];
	CPixel32* m_pTexEnvColors;
#endif
//	fp4* m_pTexGenParams[CRC_MAXTEXTURES][CRC_NUMTEXCOORDCOMP];
	fp4* m_pTexGenAttr;
	uint32 m_AttribLock;
	uint32 m_AttribLockFlags;

	uint8 m_RasterMode;
	uint8 m_SourceBlend;
	uint16 m_DestBlend;

	uint32 m_VBFlags;

	uint32 m_Flags;
	uint8 m_ZCompare;
	uint8 m_AlphaCompare;
	uint16 m_AlphaRef;

	fp4 m_PolygonOffsetScale;
	fp4 m_PolygonOffsetUnits;

#ifndef PLATFORM_PS2
	CRect2Duint16 m_Scissor;

	// Stencil: 32bit + 16bit
	union
	{
		struct
		{
			uint8 m_StencilFrontFunc : 4;
			uint8 m_StencilFrontOpFail : 4;
			uint8 m_StencilFrontOpZFail : 4;
			uint8 m_StencilFrontOpZPass : 4;
			uint8 m_StencilBackFunc : 4;
			uint8 m_StencilBackOpFail : 4;
			uint8 m_StencilBackOpZFail : 4;
			uint8 m_StencilBackOpZPass : 4;
		};
		uint32 m_StencilDWord1;
	};
	uint8 m_StencilRef;
	uint8 m_StencilFuncAnd;
	uint8 m_StencilWriteMask;

#endif

	CPixel32 m_FogColor;
	fp4 m_FogStart;
	fp4 m_FogEnd;
	fp4 m_FogDensity;

#ifdef PLATFORM_PS2
	uint8 m_nChannels;
#endif


	CRC_Attributes();
	void Clear();
	void SetDefault();
	void ClearRasterModeSettings();

	int Compare(const CRC_Attributes& _Attr) const;

	// Attributes
	void Attrib_Lock(int _Flags)										{ m_AttribLock = _Flags; };
	void Attrib_LockFlags(int _Flags)									{ m_AttribLockFlags = _Flags; };

	M_INLINE void Attrib_Default()										{ m_Flags = CRC_FLAGS_ALPHAWRITE | CRC_FLAGS_COLORWRITE | CRC_FLAGS_ZWRITE | CRC_FLAGS_ZCOMPARE | CRC_FLAGS_SMOOTH | CRC_FLAGS_PERSPECTIVE; }
	void Attrib_Enable(int _Flags)										{ m_Flags |= _Flags; };
	void Attrib_Disable(int _Flags)										{ m_Flags &= ~_Flags; };
	void Attrib_Switch(int _Flags)										{ m_Flags ^= _Flags; };
	void Attrib_ZCompare(int _Compare)									{ m_ZCompare = _Compare; };
	void Attrib_AlphaCompare(int _Compare, int _AlphaRef)				{ m_AlphaCompare = _Compare; m_AlphaRef = _AlphaRef; };

#ifndef PLATFORM_PS2
	void Attrib_StencilWriteMask(int _Mask)								{ m_StencilWriteMask = _Mask; };
	void Attrib_StencilRef(int _Ref, int _FuncAnd)		{ m_StencilRef = _Ref; m_StencilFuncAnd = _FuncAnd; };
	void Attrib_StencilFrontOp(int _Func, int _OpFail, int _OpZFail, int _OpZPass) { m_StencilFrontFunc = _Func; m_StencilFrontOpFail = _OpFail; m_StencilFrontOpZFail = _OpZFail; m_StencilFrontOpZPass = _OpZPass; };
	void Attrib_StencilBackOp(int _Func, int _OpFail, int _OpZFail, int _OpZPass) { m_StencilBackFunc = _Func; m_StencilBackOpFail = _OpFail; m_StencilBackOpZFail = _OpZFail; m_StencilBackOpZPass = _OpZPass; };
#endif	// PLATFORM_PS2

	void Attrib_RasterMode(int _Mode)									{ m_RasterMode = _Mode; };

	void Attrib_SourceBlend(int _Blend)									{ m_SourceBlend = _Blend; };
	void Attrib_DestBlend(int _Blend)									{ m_DestBlend = _Blend; };
	void Attrib_FogColor(CPixel32 _FogColor)							{ m_FogColor = _FogColor; };
	void Attrib_FogStart(fp4 _FogStart)									{ m_FogStart = _FogStart; };
	void Attrib_FogEnd(fp4 _FogEnd)										{ m_FogEnd = _FogEnd; };
	void Attrib_FogDensity(fp4 _FogDensity)								{ m_FogDensity = _FogDensity; };
	void Attrib_PolygonOffset(fp4 _Scale, fp4 _Offset)					{ m_PolygonOffsetScale = _Scale; m_PolygonOffsetUnits = _Offset; m_Flags |= CRC_FLAGS_POLYGONOFFSET; };

	void Attrib_Lights(const CRC_Light* _pLights, int _nLights)			{ m_pLights = _pLights; m_nLights = _nLights; };

	// Texture-state
	void Attrib_TextureID(int _iTxt, int _TextureID)					{ m_TextureID[_iTxt] = _TextureID; };
	void Attrib_TexCoordSet(int _iTxt, int _iTexCoordSet)				{ m_iTexCoordSet[_iTxt] = _iTexCoordSet; };
	void Attrib_TexEnvMode(int _iTxt, int _TexEnvMode)					{ m_TexEnvMode[_iTxt] = _TexEnvMode; };
//	void Attrib_TexEnvColor(int _iTxt, CPixel32 _TexEnvColor)			{ m_TexEnvColor[_iTxt] = _TexEnvColor; };
	void Attrib_TexEnvColors(CPixel32* _pTexEnvColors)					{ m_pTexEnvColors = _pTexEnvColors; };

	void Attrib_TexGen(int _iTxt, int _TexGen, int _CompMask)			{ m_TexGenComp = (m_TexGenComp & ~(CRC_TEXGENCOMP_MASK << (_iTxt * CRC_NUMTEXCOORDCOMP))) | (_CompMask << (_iTxt * CRC_NUMTEXCOORDCOMP)); m_lTexGenMode[_iTxt] = _TexGen; };
	void Attrib_TexGenAttr(fp4* _pTexGenAttr)							{ m_pTexGenAttr = _pTexGenAttr; };

	void Attrib_VBFlags(uint32 _Flags)									{ m_VBFlags = _Flags; }

	int GetTexGenComp(int _iTxt) const									{ return (m_TexGenComp >> (_iTxt * 4)) & CRC_TEXGENCOMP_MASK; };

	static int GetTexGenModeAttribSize(int _TexGenMode, int _TexGenComp);
};


/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| Vertex registers / format enums
|__________________________________________________________________________________________________
\*************************************************************************************************/

enum
{


	// Scalable
	CRC_VREG_POS			= 0,
	CRC_VREG_TEXCOORD0		= 1,
	CRC_VREG_TEXCOORD1		= 2,
	CRC_VREG_TEXCOORD2		= 3,
	CRC_VREG_TEXCOORD3		= 4,

	CRC_MAXVERTEXREGSCALE,

	// NonScalable
	CRC_VREG_TEXCOORD4		= 5,
	CRC_VREG_TEXCOORD5		= 6,
	CRC_VREG_TEXCOORD6		= 7,
	CRC_VREG_TEXCOORD7		= 8,

	CRC_VREG_NORMAL			= 9,
	CRC_VREG_COLOR			= 10,
	CRC_VREG_SPECULAR		= 11,
	CRC_VREG_MI0			= 12,
	CRC_VREG_MW0			= 13,
	CRC_VREG_MI1			= 14,
	CRC_VREG_MW1			= 15,

	CRC_MAXVERTEXREG,


	CRC_VREGFMT_VOID = 0,
	CRC_VREGFMT_V1_F32,			// -_FP4_MAX.._FP4_MAX, 32-bits, 32
	CRC_VREGFMT_V2_F32,			// -_FP4_MAX.._FP4_MAX, 64-bits, 32,32
	CRC_VREGFMT_V3_F32,			// -_FP4_MAX.._FP4_MAX, 96-bits, 32,32,32
	CRC_VREGFMT_V4_F32,			// -_FP4_MAX.._FP4_MAX, 128-bits, 32,32,32,32
	CRC_VREGFMT_V1_I16,			// -32768..32767, 16-bits
	CRC_VREGFMT_V2_I16,			// -32768..32767, 32-bits (16,16)
	CRC_VREGFMT_V3_I16,			// -32768..32767, 48-bits (16,16,16)
	CRC_VREGFMT_V4_I16,			// -32768..32767, 64-bits (16,16,16,16)
	CRC_VREGFMT_V1_U16,			// 0..65536, 16-bits
	CRC_VREGFMT_V2_U16,			// 0..65536, 32-bits (16,16)
	CRC_VREGFMT_V3_U16,			// 0..65536, 48-bits (16,16,16)
	CRC_VREGFMT_V4_U16,			// 0..65536, 64-bits (16,16,16,16)
	CRC_VREGFMT_NS3_I16,		// Normalized signed, -1..1, 48-bits (16,16,16)
	CRC_VREGFMT_NS3_P32,		// Normalized signed, -1..1, 32-bits (11,11,10)
	CRC_VREGFMT_NU3_P32,		// Normalized unsigned, 0..1, 32-bits (11,11,10)
	CRC_VREGFMT_N4_UI8_P32_NORM,		// Normalized, 0..1, 32-bit, (8,8,8,8)
	CRC_VREGFMT_N4_UI8_P32,		// Normalized, 0..255, 32-bit, (8,8,8,8)
	CRC_VREGFMT_N4_COL,			// Normalized, 0..1, 32-bits, (8,8,8,8), BGRA byte order.

//	CRC_VREGFMT_V8_F32,				// Like ..N8.. but marks dual lists
//	CRC_VREGFMT_N8_UI8_P32_NORM,	// Like ..N4.. but marks dual lists

	CRC_VREGFMT_MAX,
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_VertexFormat
|__________________________________________________________________________________________________
\*************************************************************************************************/
class CRC_VRegTransform;
class CRC_VertexFormat
{
public:
	uint8 m_lVRegFormats[CRC_MAXVERTEXREG];
	static uint8 ms_lVRegFormatSizes[CRC_VREGFMT_MAX];
	static uint8 ms_lVRegFormatComp[CRC_VREGFMT_MAX];

	void Clear()
	{
		FillChar(this, sizeof(CRC_VertexFormat), 0);
	}

	M_INLINE int GetFormat(int _iVReg) const { return m_lVRegFormats[_iVReg]; };
	M_INLINE void SetFormat(int _iVReg, int _Format) { m_lVRegFormats[_iVReg] = _Format; };

	int GetStride() const;

	static int GetRegisterSize(uint32 _Format);
	static int GetRegisterComponents(uint32 _Format);

	static void ConvertRegisterFormat(
		const void* _pSrc, int _SrcFmt, int _SrcStride, const CRC_VRegTransform* _pSrcScale, 
		void* _pDst, int _DstFmt, int _DstStride, const CRC_VRegTransform* _pDstScale, int _nV);
};

/*************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
| CRC_BuildVertexBuffer
|__________________________________________________________________________________________________
\*************************************************************************************************/
#define CRC_BVB_SETVREG(Name, Type, VReg, VRegFormat)	\
void Geometry_##Name(Type* _p) { m_lpVReg[VReg] = _p; m_Format.SetFormat(VReg, VRegFormat); m_WantFormat.SetFormat(VReg, VRegFormat); }

#define CRC_BVB_SETVREG_TEX(Name, Type, VReg, VRegFormat)	\
void Geometry_##Name(Type* _p, int _iTxtChannel) { m_lpVReg[VReg+_iTxtChannel] = _p; m_Format.SetFormat(VReg+_iTxtChannel, VRegFormat); m_WantFormat.SetFormat(VReg+_iTxtChannel, VRegFormat); }

class CRC_VRegTransform
{
public:
	CVec4Dfp4 m_Scale;
	CVec4Dfp4 m_Offset;
};

class SYSTEMDLLEXPORT CRC_BuildVertexBuffer
{
public:

	CRC_BuildVertexBuffer()
	{
		Clear();
	}

	void* m_lpVReg[CRC_MAXVERTEXREG];
	CRC_VRegTransform m_lTransform[CRC_MAXVERTEXREGSCALE];
	CRC_VRegTransform m_lWantTransform[CRC_MAXVERTEXREGSCALE];
	uint32 m_TransformEnable;
	uint32 m_WantTransformEnable;
	CRC_VertexFormat m_Format;
	CRC_VertexFormat m_WantFormat;

	int m_nV;
	uint16* m_piPrim;
	uint16 m_nPrim;
	int16 m_PrimType;

	void Geometry_SetData(int _Register, int _Format, void *_Data)
	{
		m_WantFormat.SetFormat(_Register, _Format);
		m_lpVReg[_Register] = _Data;
	}

	void Geometry_SetWantFormat(int _Register, int _Format)
	{
		m_WantFormat.SetFormat(_Register, _Format);
	}

	void Geometry_SetTransform(int _Register, CRC_VRegTransform &_Transform)
	{
		M_ASSERT(_Register < CRC_MAXVERTEXREGSCALE, "Overflow");
		m_lTransform[_Register] = _Transform;
		m_TransformEnable |= 1 << _Register;
	}

	void Geometry_SetWantTransform(int _Register, CRC_VRegTransform &_Transform)
	{
		M_ASSERT(_Register < CRC_MAXVERTEXREGSCALE, "Overflow");
		m_lWantTransform[_Register] = _Transform;
		m_WantTransformEnable |= 1 << _Register;
	}

	void Clear()
	{
		FillChar(this, sizeof(CRC_BuildVertexBuffer), 0);
	}

	aint GetStride()
	{
		return m_Format.GetStride();
	}

	aint GetWantStride()
	{
		return m_WantFormat.GetStride();
	}

	CRC_BVB_SETVREG(VertexArray, CVec3Dfp4, CRC_VREG_POS, CRC_VREGFMT_V3_F32);
	CRC_BVB_SETVREG(NormalArray, CVec3Dfp4, CRC_VREG_NORMAL, CRC_VREGFMT_V3_F32);
	CRC_BVB_SETVREG(ColorArray, CPixel32, CRC_VREG_COLOR, CRC_VREGFMT_N4_COL);
	CRC_BVB_SETVREG(ColorArray, uint32, CRC_VREG_COLOR, CRC_VREGFMT_N4_COL);
	CRC_BVB_SETVREG(ColorArray, int32, CRC_VREG_COLOR, CRC_VREGFMT_N4_COL);
	CRC_BVB_SETVREG(SpecularArray, CVec3Dfp4, CRC_VREG_SPECULAR, CRC_VREGFMT_N4_COL);
	CRC_BVB_SETVREG(MatrixIndex0, uint32, CRC_VREG_MI0, CRC_VREGFMT_N4_UI8_P32_NORM);
	CRC_BVB_SETVREG(MatrixIndex0Int, uint32, CRC_VREG_MI0, CRC_VREGFMT_N4_UI8_P32);
	CRC_BVB_SETVREG(MatrixIndex1, uint32, CRC_VREG_MI1, CRC_VREGFMT_N4_UI8_P32_NORM);
	CRC_BVB_SETVREG(MatrixIndex1Int, uint32, CRC_VREG_MI1, CRC_VREGFMT_N4_UI8_P32);
	CRC_BVB_SETVREG(MatrixWeight0, fp4, CRC_VREG_MW0, CRC_VREGFMT_V1_F32);
	CRC_BVB_SETVREG(MatrixWeight0, CVec2Dfp4, CRC_VREG_MW0, CRC_VREGFMT_V2_F32);
	CRC_BVB_SETVREG(MatrixWeight0, CVec3Dfp4, CRC_VREG_MW0, CRC_VREGFMT_V3_F32);
	CRC_BVB_SETVREG(MatrixWeight0, CVec4Dfp4, CRC_VREG_MW0, CRC_VREGFMT_V4_F32);
	CRC_BVB_SETVREG(MatrixWeight1, fp4, CRC_VREG_MW1, CRC_VREGFMT_V1_F32);
	CRC_BVB_SETVREG(MatrixWeight1, CVec2Dfp4, CRC_VREG_MW1, CRC_VREGFMT_V2_F32);
	CRC_BVB_SETVREG(MatrixWeight1, CVec3Dfp4, CRC_VREG_MW1, CRC_VREGFMT_V3_F32);
	CRC_BVB_SETVREG(MatrixWeight1, CVec4Dfp4, CRC_VREG_MW1, CRC_VREGFMT_V4_F32);
	CRC_BVB_SETVREG_TEX(TVertexArray, fp4, CRC_VREG_TEXCOORD0, CRC_VREGFMT_V1_F32);
	CRC_BVB_SETVREG_TEX(TVertexArray, CVec2Dfp4, CRC_VREG_TEXCOORD0, CRC_VREGFMT_V2_F32);
	CRC_BVB_SETVREG_TEX(TVertexArray, CVec3Dfp4, CRC_VREG_TEXCOORD0, CRC_VREGFMT_V3_F32);
	CRC_BVB_SETVREG_TEX(TVertexArray, CVec4Dfp4, CRC_VREG_TEXCOORD0, CRC_VREGFMT_V4_F32);

//	CRC_BVB_SETVREG(MatrixIndex2, uint32, CRC_VREG_TEXCOORD6, CRC_VREGFMT_N4_UI8_P32_NORM);
//	CRC_BVB_SETVREG(MatrixWeight2, CVec4Dfp4, CRC_VREG_TEXCOORD7, CRC_VREGFMT_V4_F32);

	void ConvertToInterleaved(void* _pDst, const CRC_VertexFormat& _DstFmt, CRC_VRegTransform* _pDstScale, uint32 _DestTransformEnable, int _nV);

	mint CRC_VertexBuffer_GetSize() const;
	void CRC_VertexBuffer_ConvertTo(void* _pDst, CRC_VertexBuffer& _DstBuffer) const;
};

/***************************************************************************************************\
|ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
|  CRC_Statistics
|___________________________________________________________________________________________________
\***************************************************************************************************/

template <typename t_CData, typename t_CDataIn, int t_nHistory>
class CRC_StatCounter
{
public:
	t_CData m_LastValue;
	t_CData m_AccValue;
	t_CData m_Average;
	t_CData m_History[t_nHistory];
	int m_iCurrentHistory;
	CRC_StatCounter()
	{
		m_LastValue = 0;
		m_Average = 0;
		m_AccValue = 0;
		for (int i = 0; i < t_nHistory; ++i)
			m_History[i] = 0;
		m_iCurrentHistory = 0;
	}

	void AddData(t_CDataIn _Value)
	{
		m_LastValue = _Value;

		++m_iCurrentHistory;
		if (m_iCurrentHistory == t_nHistory)
		{
			m_iCurrentHistory = 0;
		}

		m_AccValue -= m_History[m_iCurrentHistory];
		m_AccValue += _Value;
		m_History[m_iCurrentHistory] = _Value;
		m_Average = m_AccValue / t_CData(t_nHistory);
	}

	void FillHistory(fp4 *_pHistory, int _nMax)
	{
		int iCurrent = m_iCurrentHistory;
		for (int i = Min(_nMax, t_nHistory) - 1; i >= 0; --i)
		{
			_pHistory[i] = m_History[iCurrent];

			--iCurrent;
            if (iCurrent < 0)            
				iCurrent = t_nHistory - 1;
		}
	}

	void FillHistoryRelation(const CRC_StatCounter<t_CData, t_CDataIn, t_nHistory> &_Other, fp4 *_pHistory, int _nMax)
	{
		int iCurrent = m_iCurrentHistory;
		int iCurrent1 = _Other.m_iCurrentHistory;
		for (int i = Min(_nMax, t_nHistory) - 1; i >= 0; --i)
		{
			_pHistory[i] = 100.0 - (m_History[iCurrent] / _Other.m_History[iCurrent1]) * 100.0;

			--iCurrent1;
            if (iCurrent1 < 0)            
				iCurrent1 = t_nHistory - 1;

			--iCurrent;
            if (iCurrent < 0)            
				iCurrent = t_nHistory - 1;
		}
	}

	void FillHistoryRelationSub(const CRC_StatCounter<t_CData, t_CDataIn, t_nHistory> &_Other, const CRC_StatCounter<t_CData, t_CDataIn, t_nHistory> &_OtherSub, fp4 *_pHistory, int _nMax)
	{
		int iCurrent = m_iCurrentHistory;
		int iCurrent1 = _Other.m_iCurrentHistory;
		int iCurrent2 = _OtherSub.m_iCurrentHistory;
		for (int i = Min(_nMax, t_nHistory) - 1; i >= 0; --i)
		{
			_pHistory[i] = 100.0 - ((((m_History[iCurrent]) / _Other.m_History[iCurrent1]) * 100.0 + (100.0 - _OtherSub.m_History[iCurrent2])));

			--iCurrent1;
            if (iCurrent1 < 0)            
				iCurrent1 = t_nHistory - 1;
			--iCurrent2;
            if (iCurrent2 < 0)            
				iCurrent2 = t_nHistory - 1;

			--iCurrent;
            if (iCurrent < 0)            
				iCurrent = t_nHistory - 1;
		}
	}

	void FillHistoryInv(fp4 *_pHistory, int _nMax)
	{
		int iCurrent = m_iCurrentHistory;
		for (int i = Min(_nMax, t_nHistory) - 1; i >= 0; --i)
		{
			_pHistory[i] = 1.0/m_History[iCurrent];

			--iCurrent;
            if (iCurrent < 0)            
				iCurrent = t_nHistory - 1;
		}
	}

	void FillHistoryComplemnt(fp4 *_pHistory, int _nMax)
	{
		int iCurrent = m_iCurrentHistory;
		for (int i = Min(_nMax, t_nHistory) - 1; i >= 0; --i)
		{
			_pHistory[i] = 100.0 - m_History[iCurrent];

			--iCurrent;
            if (iCurrent < 0)            
				iCurrent = t_nHistory - 1;
		}
	}
};

class CRC_Statistics
{
public:
	CRC_StatCounter<fp8, fp4, 60> m_GPUUsage; // The fraction of the frame time the GPU did not spend waiting for the CPU
	CRC_StatCounter<fp8, fp4, 60> m_CPUUsage; // The fraction of the frame time the CPU did not spend waiting for the GPU
	CRC_StatCounter<fp8, fp4, 60> m_Time_FrameTime; // The frametime in seconds
	CRC_StatCounter<fp8, fp4, 60> m_BlockTime; // Should be avoidable (only includes blocking that stops the CPU until all GPU activity is finished)
	CRC_StatCounter<int64, int64, 60> m_nPixlesZPass;
	CRC_StatCounter<int64, int64, 60> m_nPixlesTotal;
};

class CRC_TextureMemoryUsage
{
public:
	CRC_TextureMemoryUsage()
	{
		m_Theoretical = 1;
		m_WorstCase = 1;
		m_BestCase = 1;
		m_pFormat = "";
	}
	const ch8 *m_pFormat;
	mint m_Theoretical;
	mint m_WorstCase;
	mint m_BestCase;
};

enum 
{
	CRC_RENDEROPTION_NOZBUFFER = DBit(0),
	CRC_RENDEROPTION_NOANTIALIAS = DBit(1),
	CRC_RENDEROPTION_PRESERVEZ = DBit(2),
	CRC_RENDEROPTION_CONTINUETILING = DBit(3),
};

#endif // _INC_MRender_Classes
