//*******************************************************************
//
// File: Asura_PS3_Carpet.h
//
// Created: 31 July 2007 Catalin Arsenescu
//
// Description: 
//
//*******************************************************************

#ifndef __ASURA_PS3_CARPET_H__
#define __ASURA_PS3_CARPET_H__

#if defined( ASURA_USE_CARPET)
// other libraries

#include "Carpet/Asura_Carpet_MeshManager.h"

#include "Rendering/Asura_PS3_Graphics.h"
#include "Rendering/Asura_PS3_GCM_IndexBuffer.h"
#include "Rendering/Asura_PS3_GCM_VertexBuffer.h"

// internal dependencies

// forward declarations
class Asura_Chunk_Stream;
class Asura_PS3_CGR_Mesh;
class Asura_Photon;


//*******************************************************************
// Constants
//*******************************************************************

#define ASURA_PS3_CGR_POLYGONSTYLE_LOOKUP_LENGTH 16


//*******************************************************************
// Class Definitions
//*******************************************************************

class Asura_Carpet_Mesh_Data_Frame
{
public:
	Asura_Carpet_Mesh_Data_Frame( const float fTime);

public:

	const float m_fTime;

	// DLH - 17 January 2006 11:26:57 - Camera Related Data
	Asura_Vector_3 m_xCameraForwards;
	Asura_Vector_3 m_xCameraPosition;
	float m_fCameraPlaneDistance;

	// DLH - 17 January 2006 11:48:48 - Billboards
	Asura_Vector_3 m_xBillboardUp;
	Asura_Vector_3 m_xBillboardRight;

	// DLH - 17 January 2006 11:26:41 - Wind wave animation data
	float m_afWaveX[ ASURA_CARPET_MESH_DATA_FRAME_SIZE_WAVEX];
	float m_afWaveY[ ASURA_CARPET_MESH_DATA_FRAME_SIZE_WAVEX];
	float m_afWaveZ[ ASURA_CARPET_MESH_DATA_FRAME_SIZE_WAVEX];
};

class Asura_PS3_CGR_Camera
{
public:
	bool GetCurrentCamera( const float fFarPlane);
	
	Asura_Matrix_3x3 m_xOrientation;

	Asura_Vector_3 m_xPosition;

	float m_fOneOverCosHalfFovX;
	float m_fTanHalfFovX;
	float m_fYOverXAspectRatio;
	float m_fOneOverCosHalfFovY;
	float m_fFarPlane;
};

class Asura_PS3_CGR_Camera_And_Box : public Asura_PS3_CGR_Camera
{
public:
	Asura_Bounding_Box m_xBoundingBox;
};

struct Asura_PS3_CGR_RTreeNode
{
public:
	Asura_PS3_CGR_RTreeNode();
	
	bool Process( Asura_Chunk_Stream &xStream, Asura_PS3_CGR_RTreeNode* pxRTreeNodeBase);
public:
	Asura_Bounding_Box m_xBoundingBox;
	Asura_PS3_CGR_RTreeNode* m_pxSibling;
	Asura_PS3_CGR_RTreeNode* m_pxChild;
	uint32 m_uData;
};

struct Asura_PS3_CGR_PolygonBatch
{
public:
	Asura_PS3_CGR_PolygonBatch();
	
	bool Process( Asura_Chunk_Stream &xStream);

public:
	// DLH - 31 January 2006 14:19:32 - Offset and run length of polygons in the Mesh structure
	uint32 m_uDataOffset;
	uint32 m_uDataSize;
	
	// DLH - 31 January 2006 14:20:06 - Information about the location of the data run on directX buffers
	uint32 m_uTimeStampLastUsed;
	uint32 m_uVertexBufferOffset;
	uint32 m_uVertexBufferSize;
};

class Asura_PS3_CGR_RangeManager
{
public:
	Asura_PS3_CGR_RangeManager();
	void Clear();
	void SetMaxRange( const uint32 uMaxRange);
	
	bool FindFreeRange( const Asura_PS3_CGR_Mesh& xCGRMesh, Asura_PS3_CGR_PolygonBatch* pxCGRBatch, const uint32 uRequiredSize, uint32& uFounfOffset);
	bool AddBatch( const uint32 uTimeStampLast, Asura_PS3_CGR_Mesh& xCGRMesh, Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	bool RemoveBatch( Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	bool DeleteOldBatches( const uint32 uTimeStampLast);
	bool DeleteAllBatches( void);

	uint32 m_uRangeMaxCount;
	uint32 m_uRangeUsedCount;
	
//	uint32 m_uBlockMaxCount;
	uint32 m_uBlockUsedCount;
	
	Asura_LinkList< Asura_PS3_CGR_PolygonBatch* > m_xListBatches;
};

struct Asura_PS3_CGR_StreamVertexSimple
{
	float m_fX, m_fY, m_fZ;													// Position 0
	float m_afDiffuse[4];													// Color 0 XYZW
	uint8 m_ucStyleIndex,m_ucWaveTableIndex,  m_ucCornerIndex, m_ucScale;	// Color 1 XYZW
	//uint8 m_ucScale, m_ucStyleIndex, m_ucWaveTableIndex, m_ucCornerIndex;	// Color 1 XYZW
};

class Asura_PS3_CGR_Vertex
{
public:
	Asura_PS3_CGR_Vertex();
	
	bool Process( Asura_Chunk_Stream &xStream);
public:
	Asura_Vector_3 m_xPosition;
	
	Asura_Vector_3 m_xColourRGB;
	float m_fDensity;
};

class Asura_PS3_CGR_Polygon
{
public:
	Asura_PS3_CGR_Polygon();
	
	bool Process( Asura_Chunk_Stream &xStream);

public:
	float m_fLodFadeFar;
	float m_fDenisty;
	uint32 m_uInstanceCount;
	uint32 m_uRandomSeed;
	uint32 m_uPolygonStyle;
	
	uint32 m_uVertexIndex[3];
};

class Asura_PS3_CGR_PolygonStyle
{
public:
	Asura_PS3_CGR_PolygonStyle();
	
	bool Process( Asura_Chunk_Stream &xStream);

public:
	static const uint32 uiInvalidStyleIndex;

	uint32 m_aucStyleLookup[ ASURA_PS3_CGR_POLYGONSTYLE_LOOKUP_LENGTH];
};

class Asura_PS3_CGR_Style
{
public:
	Asura_PS3_CGR_Style();
	
	bool Process( Asura_Chunk_Stream &xStream);

public:
	float m_fWidth;
	float m_fHeight;
	float m_afU[2];
	float m_afV[2];
	float m_fScaleMin; // DLH - 0-255 encoded 0.0f-1.0f
	float m_fLodFadeFar;
	float m_fLodFadeNear;
	float m_fLodFadeDelta;
	float m_fMovementScale;
};

class Asura_PS3_CGR_Mesh
{
public:
	Asura_PS3_CGR_Mesh();
	~Asura_PS3_CGR_Mesh();
	
	bool Process( Asura_Chunk_Stream &xStream);

public:
	Asura_Hash_ID m_xTextureHash;
	
	uint32 m_uVertexCount;
	uint32 m_uPolygonCount;
	uint32 m_uPolygonStyleCount;
	uint32 m_uStyleCount;
	uint32 m_uRTreeCount;
	uint32 m_uPolygonBatchCount;
	
	Asura_PS3_CGR_Vertex* m_pxVertices;
	Asura_PS3_CGR_Polygon* m_pxPolygons;
	Asura_PS3_CGR_PolygonStyle* m_pxPolygonStyles;
	Asura_PS3_CGR_Style* m_pxStyles;
	Asura_PS3_CGR_RTreeNode* m_pxRTree;
	Asura_PS3_CGR_PolygonBatch* m_pxPolygonBatches;
	
	uint32 m_uBatchVertexBufferSize;
	Asura_PS3_GCM_VertexBuffer	m_xBatchVertexBuffer;
	
	float m_fLodFadeFar;
	
	Asura_Bounding_Box m_xBoundingBox;
	Asura_PS3_CGR_RangeManager m_xVBRangeManager;
};

class Asura_PS3_Carpet_Game_Render
{
public:
	enum VertexMode 
	{
		SHADER_SIMPLE,
		SHADER_MULTIPLE,
		SHADER_MODULUS
	};
	
	enum CullState
	{
		CULL_INSIDE,
		CULL_OUTSIDE,
		CULL_TOUCHING
	};
	

public:
	static bool Initialise();
	static void ShutDown();
	
	static bool PreD3DReset();
	static bool PostD3DReset();
	
	static bool ClearDataSet();
	static bool HasDataSet() { return( 0 != s_uMeshesCount);}
	
	static uint32 GetMeshCount() { return( s_uMeshesCount);}
	static const Asura_PS3_CGR_Mesh& GetMesh( const uint32 uiMeshIndex) { Asura_Assert( NULL != s_pxMeshes, "Mesh Array has not been setup"); Asura_Assert( uiMeshIndex < s_uMeshesCount, "Mesh Index is out of range"); return( s_pxMeshes[ uiMeshIndex]);}
	
	static uint32 GetBatchIndexBufferSize( void) { return( s_uBatchIndexBufferSize);}

	static bool Render();

	static Asura_PS3_GCM_IndexBuffer* GetIndexBuffer( void ) { return &s_xBatchIndexBuffer; }
	static Asura_PS3_GCM_VertexBuffer* GetVertexBuffer( void ) { return s_pxBatchVertexBuffer; }
	
private:
	static bool BeginRenderStatic( const Asura_Carpet_Mesh_Data_Frame& xDataFrame);
	static void EndRenderStatic();
	static void EndRenderDynamic();
	static void EndRender( void);
	
	static bool RenderSetShaderConstantsStatic( const Asura_Carpet_Mesh_Data_Frame& xDataFrame, const Asura_Photon* pxPhoton);
	static bool RenderSetShaderConstantsStyles( const uint32 uiStylesCounts, const Asura_PS3_CGR_Style* pxStyles );
	template< class Tcamera> static bool RenderMesh( const Asura_Carpet_Mesh_Data_Frame& xDataFrame, const Tcamera& tCamera, Asura_PS3_CGR_Mesh& xCGRMesh);
	static bool RenderMeshBatch( const Asura_PS3_CGR_Mesh& xCGRMesh, const Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	
	static bool CopyMeshPolygonToVertex( const Asura_PS3_CGR_Mesh& xCGRMesh, const Asura_PS3_CGR_Polygon& xCGRPolygon, Asura_PS3_CGR_StreamVertexSimple* pxVertex0, uint32& uVertexMaxCount);
	
	static CullState GetCullStateOfSphereInFrustum( const Asura_PS3_CGR_Camera& xCamera, const Asura_Vector_3& xCentre, const float fRadius);
	static CullState GetCullStateOfAABBInFrustum( const Asura_PS3_CGR_Camera& xCamera, const Asura_Bounding_Box& xBB );
	static CullState GetCullStateOfAABBInFrustum( const Asura_PS3_CGR_Camera_And_Box& xCamera, const Asura_Bounding_Box& xBB );
	template< class TvisibleBounds, bool bCheckVisability> static bool CalcVisibleBatches( const TvisibleBounds& xCamera, const Asura_PS3_CGR_RTreeNode* pxRTree, uint32* puiBatchIndices, uint32& uiBatchCount);
	
	static bool CreateVertexFormat();
	static bool CreateIndexBuffer();
	static bool CreateVertexBufferMesh( Asura_PS3_CGR_Mesh& xCGRMesh);
	static bool CreateVertexBuffer();
	static bool CreateDirect3DData();
	static bool ClearDirect3DData();
	static bool ClearDirect3DData_AllBuffers();
	
	static bool BatchRemoveFromBuffers( Asura_PS3_CGR_Mesh& xCGRMesh, Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	static bool BatchAddToBuffers( Asura_PS3_CGR_Mesh& xCGRMesh, Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	static bool BatchGetRequiredBufferSize( const Asura_PS3_CGR_Mesh& xCGRMesh, const Asura_PS3_CGR_PolygonBatch& xCGRBatch, uint32& uIndexCount, uint32& uVertexCount);
	static bool BatchCopyToBuffers( Asura_PS3_CGR_Mesh& xCGRMesh, const Asura_PS3_CGR_PolygonBatch& xCGRBatch);
	static bool BatchCopyAllToBuffers();
	static bool BatchFindOldBatches( Asura_PS3_CGR_Mesh& xCGRMesh, Asura_PS3_CGR_PolygonBatch** ppxCGRBatchs, uint32& uBatchCount);

	static void SetTextureID( const int iTextureID);
	static void RenderCache();

private:	
	static uint32 s_uTimeStampLast;
	static uint32 s_uMeshesCount;
	static Asura_PS3_CGR_Mesh* s_pxMeshes;
	
	static int s_iDrawCacheTextureID;
	static int s_iAttenuationMap;


	static uint32 s_uBatchIndexBufferSize;
	static Asura_PS3_GCM_IndexBuffer	s_xBatchIndexBuffer;
	static Asura_PS3_GCM_VertexBuffer*	s_pxBatchVertexBuffer;
	
	friend class Asura_PS3_CGR_RangeManager;
	friend class Asura_Chunk_ResourceFile_PS3_Carpet;
};


//*******************************************************************
// Inline Function Definitions
//*******************************************************************


//*******************************************************************
//
// (c) 2006 Rebellion
//
// Warning: This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution
// of this program, or any portion of it, may result in severe civil and
// criminal penalties, and will be prosecuted to the maximum extent 
// possible under the law.
//
//*******************************************************************

#endif //defined( ASURA_USE_CARPET)

#endif // __ASURA_PS3_CARPET_H__
