/**
*
* \file Asura_PlatformRenderObject.h
*
* Created by Kevin Lea - 04/07/2002 17:57:39
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
* \brief
*
**/
#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif

#ifndef __ASURA_PLATFORMRENDEROBJECT_H__
#define __ASURA_PLATFORMRENDEROBJECT_H__

#include "Core/Asura_HashTree.h"
#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Direct3D.h"


class Asura_Mesh;
class Asura_Shape;
class Asura_Stream;


#ifdef ASURA_TARGET_SM3

#pragma pack(push, 1)

class Asura_Direct3D_ObjectVertex
{
	/// Kevin Lea - 05/07/2002 11:45:11 - position, normal, texture coords
	/// As floats this comes out to a nice 32 bytes, which is optimal for
	/// hardware. If we need a diffuse colour component per vertex too
	/// (e.g. for an object which doesn't move and can be lit like the 
	/// environment) we'll probably want a different vertex format and 
	/// shader

	// RJF - 04 August 2005 - This is being compressed from 32 bytes down to
	// 20 bytes, partly to save memory and partly to be more efficient on hardware
	// (grab more vertices per fetch). Ideally we'd slim it down to 16 bytes.
	// We could trim two from the normal (8 bits for x/y, calc z in shader) and probably
	// six more from the position (pack normal into shorts per component instead of floats)
	// but we're lacking the formats we need to really make it good. Ah well, someday...
	
	public:
	
		Asura_Vector_3 m_xPosition;	
		Asura_Vector_3 m_xNormal;
		float m_fU,m_fV;
		float m_fAlpha;
};

#pragma pack(pop)

class Asura_Direct3D_ObjectVertex_NormalMapped
{
	public:
	
		Asura_Vector_3 m_xPosition;	
		Asura_Vector_3 m_xNormal;
		float U,V;
		float U2,V2;
		float fAlpha;
		Asura_Vector_3 m_xBinormal;
		Asura_Vector_3 m_xTangent;
};

#else

#pragma pack(push, 1)

class Asura_Direct3D_ObjectVertex
{
	/// Kevin Lea - 05/07/2002 11:45:11 - position, normal, texture coords
	/// As floats this comes out to a nice 32 bytes, which is optimal for
	/// hardware. If we need a diffuse colour component per vertex too
	/// (e.g. for an object which doesn't move and can be lit like the 
	/// environment) we'll probably want a different vertex format and 
	/// shader

	// RJF - 04 August 2005 - This is being compressed from 32 bytes down to
	// 20 bytes, partly to save memory and partly to be more efficient on hardware
	// (grab more vertices per fetch). Ideally we'd slim it down to 16 bytes.
	// We could trim two from the normal (8 bits for x/y, calc z in shader) and probably
	// six more from the position (pack normal into shorts per component instead of floats)
	// but we're lacking the formats we need to really make it good. Ah well, someday...
	
	public:
	
		Asura_Vector_3 m_xPosition;	
		u_int m_uNormal;			// 8/8/8/X
		short m_sU, m_sV;
};

#pragma pack(pop)

#endif //#ifdef ASURA_TARGET_SM3

class Asura_Direct3D_Object_Strip
{
	public:
		Asura_Direct3D_Object_Strip()
		{
			m_pxVertexBuffer=0;
			m_pxIndexBuffer=0;

#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
			m_auMaterialResponseHashID[0] = ASURA_HASH_ID_UNSET;
			m_auMaterialResponseHashID[1] = ASURA_HASH_ID_UNSET;
#else
			m_iMaterialIndex=0;
#endif

			m_uNumberOfIndices=0;
			m_uNumberOfVertices=0;
			m_uNumberOfTriangles=0;

			m_ePrimitiveType = D3DPT_TRIANGLESTRIP;

			m_fMinDistance = 0;
			m_pxNextLowerStrip = 0;

#ifdef ASURA_TARGET_SM3
			m_bNormalMapped = false;
#endif //#ifdef ASURA_TARGET_SM3
		}
		~Asura_Direct3D_Object_Strip()
		{
			if (m_pxVertexBuffer)
			{
				m_pxVertexBuffer->Release();
			}
			if (m_pxIndexBuffer)
			{
				m_pxIndexBuffer->Release();
			}
		}
		
		const Asura_Direct3D_Object_Strip* GetDetailMeshFromDistance(float fDistance) const
		{
			fDistance *= Asura_Camera::GetLODMetric(Asura_Camera::GetCameraIndex()); //Asura_Mesh_System::Project_GetLODMetric(Asura_Camera::GetCameraIndex());

			const Asura_Direct3D_Object_Strip* pxStrip = this;
			while(pxStrip->m_pxNextLowerStrip)
			{
				if(pxStrip->m_pxNextLowerStrip->m_fMinDistance > fDistance) break;
				pxStrip = pxStrip->m_pxNextLowerStrip;
			}
			return pxStrip;
		}

		
		Direct3D_VertexBuffer*				m_pxVertexBuffer;
		Direct3D_IndexBuffer*				m_pxIndexBuffer;
		
#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		Asura_Hash_ID						m_auMaterialResponseHashID[2];
#else
		int									m_iMaterialIndex;
#endif

		u_int								m_uNumberOfIndices;
		u_int								m_uNumberOfVertices;
		u_int								m_uNumberOfTriangles;

		D3DPRIMITIVETYPE					m_ePrimitiveType;

		//LOD models
		float								m_fMinDistance;//Minimum distance at which this detail level should be visible
		const Asura_Direct3D_Object_Strip*	m_pxNextLowerStrip;

#ifdef ASURA_TARGET_SM3
		bool								m_bNormalMapped; // Must be set on initialisation, and never changed after then.
#endif //#ifdef ASURA_TARGET_SM3
};


class Asura_Direct3D_ObjectRender_Handler
{
	friend class Asura_Direct3D_ObjectRenderer;
	friend class Asura_Chunk_ResourceFile_PC_Object;

public:
	// Public functions...
	Asura_Direct3D_ObjectRender_Handler  (void)	{}
//	~Asura_Direct3D_ObjectRender_Handler ()		{}

	void								Reset									(void);

	bool								DoesObjectStripExist					(const Asura_Hash_ID uHash) const	{ return(m_xHashTree.GetDataByHash(uHash) != NULL); }
	int									GetMaterialIdx							(const Asura_Shape& xShape) const;

private:
	// Private variables...
	Asura_TemplateHashTree<Asura_Direct3D_Object_Strip>	m_xHashTree;

	// Private functions...
	Asura_Direct3D_Object_Strip*		AddObjectStrip							(const Asura_Hash_ID uHash);

	//Gets object strip from its hash ID. Unlike the other 2 versions of the function , no
	//attempt will be made to create the object strip if it doesn't already exist (since
	//not enough information is available). RAR 05/09/03
	const Asura_Direct3D_Object_Strip*	GetObjectStrip							(const Asura_Hash_ID uHash) const	{ return(m_xHashTree.GetDataByHash(uHash)); }

	// RJF - 24 June 2005 - Publicised this function so that project-specific shape renderers (i.e. rogue's silhouette renderer) can easily
	// use it
	const Asura_Direct3D_Object_Strip*	GetObjectStrip							(const Asura_Shape& xShape);

#if defined(ASURA_TOOLS)
	const Asura_Direct3D_Object_Strip*	GetObjectStrip							(Asura_Mesh* pxMesh);

	const Asura_Direct3D_Object_Strip*	InitialiseStripFromShape				(const Asura_Shape& xShape);
	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	const Asura_Direct3D_Object_Strip*	InitialiseStripFromRawData				(Asura_Mesh* pxMesh, const Asura_Hash_ID uMatResponse1, const Asura_Hash_ID uMatResponse2, const Asura_Hash_ID uHashID);
	#else
	const Asura_Direct3D_Object_Strip*	InitialiseStripFromRawData				(Asura_Mesh* pxMesh, const int iMaterialIndex, const Asura_Hash_ID uHashID);
	#endif
#if defined(ASURA_TARGET_SM3)
	const Asura_Direct3D_Object_Strip*	InitialiseNormalMappedStripFromRawData	(Asura_Mesh* pxMesh,
																				 const int iMaterialIndex,
																				 const Asura_Hash_ID uHashID,
																				 const Asura_Hash_ID uMaterialResponseHashID1 = ASURA_HASH_ID_UNSET,
																				 const Asura_Hash_ID uMaterialResponseHashID2 = ASURA_HASH_ID_UNSET);
#endif	// defined(ASURA_TARGET_SM3)
#endif	// defined(ASURA_TOOLS)
};


class Asura_Direct3D_ObjectRenderer
{
public:
	static void Initialise(void);
	static void Shutdown(void);
	static void Reset(void);


	static void RenderBasic(const Asura_Direct3D_Object_Strip* pxStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const Asura_Vector_2& xUVOffset, float fAlpha, bool bLight, float fScale = 1.0f);
	static void RenderBasic(const Asura_Direct3D_Object_Strip* pxStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const Asura_Vector_2& xUVOffset, float fAlpha, bool bLight, const Asura_Vector_3& xScale,int iTextureID);
#ifdef ASURA_TARGET_SM3
	static void RenderWithEffectSystem(const Asura_Direct3D_Object_Strip* pxStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const Asura_Vector_2& xUVOffset, float fAlpha, bool bLight, float fScale = 1.0f, bool bUsePerPixelFog = false);
	static void RenderWithEffectSystem(const Asura_Direct3D_Object_Strip* pxStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const Asura_Vector_2& xUVOffset, float fAlpha, bool bLight, const Asura_Vector_3& xScale, bool bUsePerPixelFog = false);

	static bool ToggleNewRenderers()
	{
		if (s_bNewRenderersSupported)
		{
			s_bUseNewRenderers = !s_bUseNewRenderers;
		}
		return s_bUseNewRenderers;
	}
#endif //#ifdef ASURA_TARGET_SM3

#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	static void Render_MaterialResponse( const Asura_Direct3D_Object_Strip& xStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const Asura_Vector_3& xScale );
#endif

	static void Render(const class Asura_Shape* pxShape, const class Asura_Shape_Instance* pxShapeInst, const u_int uARGB);
	//static void RenderShadow(const class Asura_Shape* pxShape, const class Asura_Shape_Instance* pxShapeInst);
	static void RenderShadow(const Asura_Direct3D_Object_Strip* pxStrip, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation);
#if defined(ASURA_TARGET_SM3)
	static void RenderShadow(const class Asura_Shape& xShape, const class Asura_Shape_Instance& xShapeInst, const class Asura_Shadow& xShadow);
#endif

#ifdef ASURA_TOOLS
	static void ToolsRender(class Asura_Mesh* pxMesh, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, bool bWithLighting, const float fAlpha=1.0f, const float fScale = 1.0f, int iTextureID = ASURA_TEXTURE_NONE, u_int uColour  = 0xffffff);
	static void ToolsRender(class Asura_Mesh* pxMesh, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, bool bWithLighting, const float fAlpha, const Asura_Vector_3& xScale, int iTextureID = ASURA_TEXTURE_NONE, u_int uColour = 0xffffff);

	static void ToolsRender2ndOrderSH(Asura_Mesh* pxMesh, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const float fAlpha=1.0f );
#endif

	static bool DoesObjectStripExist(Asura_Hash_ID uHash)	{ return(GetCurrentHandler().DoesObjectStripExist(uHash)); }
	static int GetMaterialIdx( const Asura_Shape& xShape )	{ return(GetCurrentHandler().GetMaterialIdx(xShape)); }

	// RJF - 24 June 2005 - Publicised this function so that project-specific shape renderers (i.e. rogue's silhouette renderer) can easily
	// use it
	static const Asura_Direct3D_Object_Strip* GetObjectStrip(const Asura_Shape& xShape)	{ return(GetCurrentHandler().GetObjectStrip(xShape)); }

#if defined(ASURA_USE_MULTIPLE_HANDLERS)
	// Handler functions...
	static	void									ReparentHandler(const Asura_Hash_ID uSourceHash, const Asura_Hash_ID uNewParentHash);
	static	void									ReparentHandler(Asura_Direct3D_ObjectRender_Handler& xSourceHandler, const Asura_Hash_ID uNewParentHash);

	static	Asura_Direct3D_ObjectRender_Handler*	CreateHandler		(const Asura_Hash_ID uHash, const Asura_Hash_ID uParentHandlerHash);
	static	bool									DestroyHandler		(const Asura_Hash_ID uHash);
	static	void									WriteHandlerReport	(u_int uHandler, Asura_Stream& xLog);

	static	void									CreateAndSetHandler	(const Asura_Hash_ID uHash, const Asura_Hash_ID uParentHandlerHash)	{ s_pxCurrentHandler = CreateHandler(uHash, uParentHandlerHash); }
	static	void									SetCurrentHandler	(Asura_Direct3D_ObjectRender_Handler* pxHandler)					{ s_pxCurrentHandler = pxHandler; }
	static	void									SetCurrentHandler	(const Asura_Hash_ID uHash)											{ s_pxCurrentHandler = s_xHandlerTree.GetDataByHash(uHash); }
	static	Asura_Direct3D_ObjectRender_Handler&	GetCurrentHandler	(void)																{ return(*s_pxCurrentHandler); }
#else
	// Handler functions...
	static	Asura_Direct3D_ObjectRender_Handler&	GetCurrentHandler	(void)																{ return(s_xHandler); }
#endif


private:
#if defined(ASURA_USE_MULTIPLE_HANDLERS)
	// Private variables...
	static	Asura_Direct3D_ObjectRender_Handler*						s_pxCurrentHandler;		// Currently active handler.
	static	Asura_TemplateHashTree<Asura_Direct3D_ObjectRender_Handler>	s_xHandlerTree;			// Tree of all of the handlers available.
#else
	// Private variables...
	static	Asura_Direct3D_ObjectRender_Handler							s_xHandler;				// Single static-instance of a zone.
#endif

#ifdef ASURA_TARGET_SM3
	static bool s_bUseNewRenderers;
	static bool s_bNewRenderersSupported;
#endif //#ifdef ASURA_TARGET_SM3
};


#endif//__ASURA_PLATFORMRENDEROBJECT_H__


/// End of file. ///
