//
// Asura_Direct3D_EnvironmentRenderer.h
//
// Created by KJFL - 04 May 2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __Asura_Direct3D_EnvironmentRenderer_H__
#define __Asura_Direct3D_EnvironmentRenderer_H__

#include "Core/Asura_Maths.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Direct3D_EffectParameterBlock.h"
#include "Rendering/Asura_Direct3D_MaterialResponse.h"

#define ASURA_MAX_VISIBLE_WATER_STRIPS 128

class Asura_Local_Photon;
class Asura_DIPCache_DIPData;
class Asura_Direct3D_Effect;
class Asura_Direct3D_EnvironmentRenderer_Strip;
class Asura_Direct3D_IndexBuffer_Dynamic;
class Asura_Direct3D_Water_ParamBlockData;
class Asura_MaterialResponse;

class Asura_Direct3D_EnvironmentRenderer
{
	friend class Asura_Chunk_ResourceFile_PC_Environment_SM3;

	public:

		static void Initialise( void );
		static void Reset( void );
		static void Shutdown( void );


		static void Render( const bool bTransparentStrips );
		static void RenderToShadow(float fNear, float fFar, bool bCubeMap);

		// DMR 17-05-07 - Render the water modules
		static void RenderWater( void );

		static Direct3D_VertexDeclaration* GetVD();
		static D3DPRIMITIVETYPE GetPrimType();
		static u_int GetNumStrips() { return s_uTotalNumberOfStrips; }
		static const Asura_Direct3D_EnvironmentRenderer_Strip& GetStrip( const u_int u );
		static Direct3D_VertexBuffer* GetVB( const u_int u );
		static Direct3D_IndexBuffer* GetIB( const u_int u );

		static void RenderGeometry();
	
		static bool RenderAABB( const Asura_Bounding_Box& xBB );

#ifdef ASURA_TOOLS
		//Gets the strings to be shown in the tools help system.
		static const char** GetRendererDebugHelpStrings();
		static void Tools_CreateData( void );

		static void Tools_CreateData( u_int uNumberOfModules );

		static void SetDisableDualPass(bool bSet) {s_bDisableDualPass = bSet;}
		static bool GetDisableDualPass() {return s_bDisableDualPass;}
#endif	// defined(ASURA_TOOLS)

private:

		friend class Asura_Environment_Renderer;

		static void Render_SetMaterials( const Asura_MaterialResponse* pxMaterial1, const Asura_MaterialResponse* pxMaterial2);
		
		static void Render_Normal( Asura_Direct3D_Effect* const pxEffect, const bool bTransparentStrips);
		
		static void SetStreams(const Asura_Direct3D_EnvironmentRenderer_Strip& xStrip);
		static void SetStreams(const Asura_Direct3D_Effect& xEffect, Direct3D_VertexBuffer* pxVertexBuffer, const u_int uVertexStride, Direct3D_IndexBuffer* pxIndexBuffer);

		static Asura_Direct3D_Effect*		 				s_pxEnvironmentEffect;
		static Asura_Direct3D_Effect*		 				s_pxEnvShadowEffect;
		
		static Direct3D_VertexBuffer*						s_pxAABBVertexBuffer;
		static Direct3D_IndexBuffer*						s_pxAABBIndexBuffer;

		static u_int										s_uTotalNumberOfStrips;
		static Asura_Direct3D_EnvironmentRenderer_Strip*	s_pxStrips;

		static u_int										s_uTotalNumberOfVertexBuffers;

		static Direct3D_VertexBuffer**						s_ppxVertexBuffer;

		static u_int										s_uTotalNumberOfIndexBuffers;
		static Direct3D_IndexBuffer**						s_ppxIndexBuffer;
		
		// DLH - Data for Dynmic Index Buffer Rendering
		static u_int										s_uTotalNumberOfIndices;
		static uint16*										s_pusIndexData;
		static uint16**										s_ppusIndexData;


#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		static Asura_Direct3D_MaterialResponse_ShaderData s_xCacheMaterialShaderData_Base;
		static Asura_Direct3D_MaterialResponse_ShaderData_Env s_xCacheMaterialShaderData_Env;
		static Asura_Direct3D_MaterialResponse_ShaderData_Parallax s_xCacheMaterialShaderData_Parallax;
		static Asura_Direct3D_EffectParameterBlock*			s_pxParamBlock;
#endif //#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		
		// cache of the currently used material - used to see if the material has changed and the shader needs to be notified
		static int											s_iCurrentlyUsedMaterial;

		static bool											s_bDisplayOcclusionText;
		static bool											s_bXRayMode;
		static bool											s_bUsingPreloadedData;
		static bool											s_bVertexAndIndexBuffersCreatedInternally;
		static bool											s_bUseTriLists;

#ifdef ASURA_TOOLS
		//Used to determine whether the strip data needs to be (re)calculated in tools builds. It used to be
		//based on whether the number of strips was non-zero ,but that isn't entirely ideal in cases where there
		//are no strips , because everything is hidden. RAR 31/05/2006
		static bool											s_bStripsValid;

		//Tools option to disable rendering of the secondary material
		static bool											s_bDisableDualPass;
#endif

		// Water material effect/params
		static Asura_Direct3D_Effect*		 					s_pxWaterEffect;
		static Asura_Direct3D_EffectParameterBlock*				s_pxWaterParamBlock;
		static Asura_Direct3D_Water_ParamBlockData				s_xWaterParamData;
		static const Asura_Direct3D_EnvironmentRenderer_Strip*	s_pxQueuedWaterStrips[ASURA_MAX_VISIBLE_WATER_STRIPS];
		static int												s_iNumQueuedWaterStrips;

		static void HandleKeyPresses(void);
		static void CreateAABBBuffers( void );
		static void QueueWaterStrip(const Asura_Direct3D_EnvironmentRenderer_Strip *pxStrip);
};


class Asura_Direct3D_EnvironmentRenderer_Strip
{
	public:
		u_int				m_uNumberOfPrimitives;
		
		u_int				m_uVertexBuffer;
		u_int				m_uStartVertex;
		u_int				m_uNumberOfVertices;
		
		u_int				m_uIndexBuffer;
		u_int				m_uStartIndex;
		
#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM && !defined ASURA_MATERIAL_RESPONSE_CHARACTERS_ONLY
		Asura_Hash_ID		m_auMaterialResponseHashID[2];
#else
		int					m_iMaterial;
#endif

		u_int				m_uModule;

		Asura_Bounding_Box	m_xBB;
};


// Classes for storing vertex-data...

class Asura_Direct3D_EnvironmentRenderer_Vertex
{
public:
	// Set functions...
	void	SetPosition			(const Asura_Vector_3& xValue)						{ m_xPosition		= xValue; }
	void	SetDiffuseRGBA		(const u_int uValue)								{ m_uDiffuseRGBA	= uValue; }
	void	SetNormal			(const Asura_Vector_3& xValue)						
	{ 
		m_asNormal [0]	= (short)(xValue.x * 32767);	
		m_asNormal [1]	= (short)(xValue.y * 32767);	
		m_asNormal [2]	= (short)(xValue.z * 32767);	
		m_asNormal [3]	= 32767; 
	}
	void	SetTangentBinormal	(const Asura_Vector_3& xTangent, const Asura_Vector_3& xBinormal)						
	{ 
		m_asTangent [0]	= (short)(xTangent.x * 32767);	
		m_asTangent [1]	= (short)(xTangent.y * 32767);
		m_asTangent [2]	= (short)(xTangent.z * 32767);	
		
		const Asura_Vector_3& xNorm = xBinormal ^ xTangent;
		// checking handedness of normal, binormal, tangent set
		if (xNorm.GetX() * float(m_asNormal[0]) + xNorm.GetY() * float(m_asNormal[1]) + xNorm.GetZ() * float(m_asNormal[2]) < 0.0f)
		{
			m_asTangent [3] = -32767;
		}
		else
		{
			m_asTangent [3] = 32767;
		}
	}
	void	SetTangentBinormal2			(const Asura_Vector_3& xTangent, const Asura_Vector_3& xBinormal)						
	{ 
		m_asTangent2 [0] = (short)(xTangent.x * 32767);	
		m_asTangent2 [1] = (short)(xTangent.y * 32767);
		m_asTangent2 [2] = (short)(xTangent.z * 32767);	
		const Asura_Vector_3& xNorm = xBinormal ^ xTangent;
		// checking handedness of normal, binormal, tangent set
		if (xNorm.GetX() * float(m_asNormal[0]) + xNorm.GetY() * float(m_asNormal[1]) + xNorm.GetZ() * float(m_asNormal[2]) < 0.0f)
		{
			m_asTangent2 [3] = -32767;
		}
		else
		{
			m_asTangent2 [3] = 32767;
		}
	}

	void	SetTextureCoord		(const int iIndex, const float fU, const float fV)	{ m_axTextureCoords [iIndex]	= Asura_Vector_2(fU, fV); }
	void	SetTextureCoord		(const int iIndex, const Asura_Vector_2& xValue)	{ m_axTextureCoords [iIndex]	= xValue; }
	void	SetDiffuseSH_Red	(const float afValues [4])							{ m_afDiffuseSH_Red [0]		= afValues [1];	m_afDiffuseSH_Red [1]	= afValues [2];	m_afDiffuseSH_Red [2]	= afValues [3];	m_afDiffuseSH_Red [3]	= afValues [0]; }
	void	SetDiffuseSH_Green	(const float afValues [4])							{ m_afDiffuseSH_Green [0]	= afValues [1];	m_afDiffuseSH_Green [1]	= afValues [2];	m_afDiffuseSH_Green [2]	= afValues [3];	m_afDiffuseSH_Green [3]	= afValues [0]; }
	void	SetDiffuseSH_Blue	(const float afValues [4])							{ m_afDiffuseSH_Blue [0]	= afValues [1];	m_afDiffuseSH_Blue [1]	= afValues [2];	m_afDiffuseSH_Blue [2]	= afValues [3];	m_afDiffuseSH_Blue [3]	= afValues [0]; }


private:
	// Vertex position and colour...
	Asura_Vector_3	m_xPosition;
	u_int			m_uDiffuseRGBA;

	// Vertex normal, binormal and tangent...
	short			m_asNormal [4];
	short			m_asTangent [4];
	short			m_asTangent2 [4];

	// Texture co-ordinated - only dual-pass allowed...
	Asura_Vector_2	m_axTextureCoords [2];

	// Diffuse spherical harmonics, R,G & B...
	float			m_afDiffuseSH_Red [4];
	float			m_afDiffuseSH_Green [4];
	float			m_afDiffuseSH_Blue [4];
};

extern const Direct3D_VertexElement axASURA_D3D_ENV_VERTEX_DECLARATION[];




// Shader parameter data for water materials

class Asura_Direct3D_Water_ParamBlockData
{
public:
	bool					m_bUseTransparencyMap;
	bool					m_bDualNormalMap;

	float					m_fWaterFogScale;
	float					m_fVolumetricDepthScale;
	float					m_fRippleScale;
	float					m_fDistortionScale;
	float					m_fTwoOverScreenWidth;
	float					m_fTwoOverScreenHeight;

	D3DXVECTOR4				m_xWaterReflectionColour;
	D3DXVECTOR4				m_xWaterRefractionColour;
	D3DXVECTOR4				m_xWaterFogColour;
	D3DXVECTOR4				m_xUVScroll;
	D3DXVECTOR4				m_xUVScroll2;
	D3DXVECTOR4				m_xWavesX;
	D3DXVECTOR4				m_xWavesZ;

	Direct3D_BaseTexture*	m_pxDepthTexture;
	Direct3D_BaseTexture*	m_pxBackBufferTexture;
	Direct3D_BaseTexture*	m_pxTransparencyMap;
	Direct3D_BaseTexture*	m_pxNormalMap;
	Direct3D_BaseTexture*	m_pxNormalMap2;
	Direct3D_BaseTexture*	m_pxReflectionMap;
};


#endif//__Asura_Direct3D_EnvironmentRenderer_H__
