/**
*
* \file Asura_Platform_Decal.cpp
*
* Created by Kevin Lea - 19/11/2002 16:18:30
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
* \brief
*
**/

#include "Core/Asura.h"
#include "SpecialFX/Asura_Decal_System.h"
#include "SpecialFX/Asura_Decal_Template.h"

#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Direct3D_Shaders.h"
#include "Core/Asura_TextureManagement.h"

#ifndef ASURA_TARGET_SM3

/////////////////////
// D3D_DecalVertex //
/////////////////////
#define D3DFVF_DECALVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)

class D3D_DecalVertex
{
public:

	float X,Y,Z;
	float U,V;

	
	inline bool operator == ( const D3D_DecalVertex& v) const
	{
	    return (X == v.X && Y == v.Y && Z == v.Z
			 && U == v.U && V == v.V);
	}


};

////////////////////////////////
// Asura_Direct3D_DecalBuffer //
////////////////////////////////
class Asura_Direct3D_DecalBuffer : public Asura_DecalBuffer
{
public:

	Asura_Direct3D_DecalBuffer(const Asura_Decal_Template* pxDecalTemplate)
	{
		uMaxNumberOfIndices = 1000;
		VertexStripIndex = 0;
		NumberOfStripTris = 0;
	
		uCurrentIndex = 0;
		uMaxIndex = 0;

		m_pxDecalTemplate = pxDecalTemplate;
		m_pxNextDecalBuffer = 0;
	}

	~Asura_Direct3D_DecalBuffer()
	{
		delete m_pxNextDecalBuffer;
	}

	void AddStrip(const Asura_Decal_Vertex* pxStrip, const u_int uNumberOfVertices)
	{
		if (uCurrentIndex + uNumberOfVertices+2 > uMaxNumberOfIndices)
		{
			uCurrentIndex = 0;
		}

		vertices[uCurrentIndex].X = pxStrip[0].m_xPosition.x;
		vertices[uCurrentIndex].Y = pxStrip[0].m_xPosition.y;
		vertices[uCurrentIndex].Z = pxStrip[0].m_xPosition.z;
		vertices[uCurrentIndex].U = pxStrip[0].m_fU;
		vertices[uCurrentIndex].V = pxStrip[0].m_fV;
		uCurrentIndex++;

		for(u_int i=0; i<uNumberOfVertices; i++)
		{
			u_int v = i + uCurrentIndex;
			vertices[v].X = pxStrip[i].m_xPosition.x;
			vertices[v].Y = pxStrip[i].m_xPosition.y;
			vertices[v].Z = pxStrip[i].m_xPosition.z;
			vertices[v].U = pxStrip[i].m_fU;
			vertices[v].V = pxStrip[i].m_fV;
		}
		
		uCurrentIndex+= uNumberOfVertices;
		
		vertices[uCurrentIndex].X = pxStrip[uNumberOfVertices-1].m_xPosition.x;
		vertices[uCurrentIndex].Y = pxStrip[uNumberOfVertices-1].m_xPosition.y;
		vertices[uCurrentIndex].Z = pxStrip[uNumberOfVertices-1].m_xPosition.z;
		vertices[uCurrentIndex].U = pxStrip[uNumberOfVertices-1].m_fU;
		vertices[uCurrentIndex].V = pxStrip[uNumberOfVertices-1].m_fV;
		uCurrentIndex++;
			
		// KJL - 29/04/2003 10:32:10 - if wrapped we have to tidy up any decals we've half-overwritten
		if (uCurrentIndex<uMaxIndex)
		{
			u_int u = uCurrentIndex;

			while (!(vertices[u]==vertices[u+1]) && u<uMaxIndex-1)
			{
				vertices[u].X		= vertices[u-1].X;
				vertices[u].Y		= vertices[u-1].Y;
				vertices[u].Z		= vertices[u-1].Z;
				vertices[u].U		= vertices[u-1].U;			
				vertices[u].V		= vertices[u-1].V;
				u++;
			}
		}
		else
		{
			uMaxIndex = uCurrentIndex;
		}
		
		if (uCurrentIndex>NumberOfStripTris+2)
		{
			NumberOfStripTris = uCurrentIndex - 2;
		}
	}

	void Render(void)
	{
		Asura_Render::CurrentStates.RequestTextureIndex(0,m_pxDecalTemplate->m_iTextureIndex);
	
		for(int i=0; i<Asura_Camera::GetNumberOfCameras(); i++)
		{
			Asura_Camera::SetCameraIndex(i);

			if (Asura_Camera::IsCameraActive())
			{
				Asura_Render::ApplyCameraSettings();
				
				Asura_Direct3D::D3DDevice->DrawPrimitiveUP
				(
					D3DPT_TRIANGLESTRIP,
					NumberOfStripTris,
					(void*)vertices,
					sizeof(D3D_DecalVertex)
				);

			}
		}

		if (m_pxNextDecalBuffer)
		{
			m_pxNextDecalBuffer->Render();
		}
	}

	D3D_DecalVertex vertices[1024];
	u_int uMaxNumberOfIndices;
	u_int VertexStripIndex;
	u_int NumberOfStripTris;

	u_int uCurrentIndex;
	u_int uMaxIndex;

	const Asura_Decal_Template* m_pxDecalTemplate;

	Asura_Direct3D_DecalBuffer* m_pxNextDecalBuffer;
};


/// Kevin Lea - 19/11/2002 17:07:34 - test renderer for proof of concept: (very slow!)

void Asura_Decal_Handler::Platform_AddStrip(const Asura_Decal_Vertex* pxStrip,
										   u_int uNumVertices,
										   const Asura_RGBA& xDiffuseRGBA,
										   const Asura_Decal_Template* pxDecalTemplate )
{
	Asura_Direct3D_DecalBuffer* pxDecalBuffer = static_cast<Asura_Direct3D_DecalBuffer*>(m_pxFirstDecalBuffer);
		
	while (pxDecalBuffer)
	{
		if (pxDecalBuffer->m_pxDecalTemplate == pxDecalTemplate)
		{
			pxDecalBuffer->AddStrip(pxStrip, uNumVertices);
			return;
		}
		pxDecalBuffer = pxDecalBuffer->m_pxNextDecalBuffer;
	}

	pxDecalBuffer = new Asura_Direct3D_DecalBuffer(pxDecalTemplate);
	pxDecalBuffer->m_pxNextDecalBuffer = static_cast<Asura_Direct3D_DecalBuffer*>(m_pxFirstDecalBuffer);
	m_pxFirstDecalBuffer = pxDecalBuffer;

	pxDecalBuffer->AddStrip(pxStrip,uNumVertices);
}

void Asura_Decal_Handler::Platform_Render(void)
{
	if (m_pxFirstDecalBuffer == 0) return;

	SCOPEDPIXEVENT((0xff00ff00, L"Decal Handler"));
	
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, 0 );

	//	bool bIsNew = false;
//	int iTexture = Asura_Texture_Management::AddTexture("\\specialfx\\bullet_decal.tga", &bIsNew);
//	if (bIsNew)
//	{
//		Asura_Texture_Management::LoadTextures();
//	}


	Asura_Direct3D_Shaders::RequestFixedFunctionVertexShader(D3DFVF_DECALVERTEX);

//	Asura_Render::CurrentStates.RequestTextureIndex(0,ASURA_TEXTURE_NONE);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_DOUBLECOLOUR);
	Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);
	Asura_Render::CurrentStates.RequestCullMode(ASURA_CULLMODE_NONE);

	// offset Z closer to camera to avoid z-fighting
	float fZBias = -0.0001f;
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD *)&fZBias) );

	static_cast<Asura_Direct3D_DecalBuffer*>(m_pxFirstDecalBuffer)->Render();

	fZBias = 0.0f;
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD *)&fZBias) );
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);
	
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
}

void Asura_Decal_System::Platform_Initialise()
{
}

void Asura_Decal_System::Platform_Reset()
{
}

void Asura_Decal_System::Platform_Shutdown()
{
}


#endif // ASURA_TARGET_SM3