//
// Asura_Direct3D_LineRendering.cpp
//
// Created by RJF - 07 September 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Rendering/Asura_Direct3D_LineRendering.h"

#include "Rendering/Asura_Render.h"

#include "Rendering/Asura_Direct3D_Shaders.h"
#include "Rendering/Asura_Direct3D_StoreRenderTargets.h"

#ifndef ASURA_DIRECT3D_LINERENDERER_2D_BATCH_SIZE 
#define ASURA_DIRECT3D_LINERENDERER_2D_BATCH_SIZE 1024
#endif

#ifndef ASURA_DIRECT3D_LINERENDERER_3D_BATCH_SIZE 
#define ASURA_DIRECT3D_LINERENDERER_3D_BATCH_SIZE 1024
#endif

// Static members
// Add one entry per line class here
Asura_Direct3D_LineRenderer::BatchBuffer<Asura_Direct3D_LineRenderer::Line2D>* Asura_Direct3D_LineRenderer::BatchBuffer<Asura_Direct3D_LineRenderer::Line2D>::s_pxBatchBuffers = NULL;
Asura_Direct3D_LineRenderer::BatchBuffer<Asura_Direct3D_LineRenderer::Line3D>* Asura_Direct3D_LineRenderer::BatchBuffer<Asura_Direct3D_LineRenderer::Line3D>::s_pxBatchBuffers = NULL;

// 2D Lines

Asura_Direct3D_LineRenderer::Line2D::Line2D( const Asura_Vector_2& xP1, const Asura_Vector_2& xP2, u_int uColour )
: m_xP1(xP1), m_xP2(xP2), m_uColour1(uColour), m_uColour2(uColour)
{ }

Asura_Direct3D_LineRenderer::Line2D::Line2D( const Asura_Vector_2& xP1, const Asura_Vector_2& xP2, u_int uColour1, u_int uColour2 )
: m_xP1(xP1), m_xP2(xP2), m_uColour1(uColour1), m_uColour2(uColour2)
{ }

void Asura_Direct3D_LineRenderer::Line2D::ToVertices(Vertex& xP1, Vertex& xP2, const Asura_Bounding_Rectangle& xSwapChainBounds) const
{
	xP1.fX = m_xP1.x - xSwapChainBounds.MinX;
	xP1.fY = m_xP1.y - xSwapChainBounds.MinY;
	xP1.fZ = 0;
	xP1.fRhw = 1e6f;
	xP1.uColour = m_uColour1;

	xP2.fX = m_xP2.x - xSwapChainBounds.MinX;
	xP2.fY = m_xP2.y - xSwapChainBounds.MinY;
	xP2.fZ = 0;
	xP2.fRhw = 1e6f;
	xP2.uColour = m_uColour2;
}

void Asura_Direct3D_LineRenderer::Line2D::Render( const Line2D::Vertex* const pxVertexData, const u_int uNumVertices )
{
#if defined( ASURA_TARGET_SM3)
	// DLH - 14 February 2007 12:33:53 - Store and Clear all the RenderTargets after the first one
	Asura_Direct3D_StoreRenderTargets xRenderTargetStore;
	
	xRenderTargetStore.StoreRenderTargets();
	Asura_Direct3D::ClearRenderTargets( 1);

	// Disable sRGB here to preserve Tools' interface colours
	DWORD uOldSRGBWrite;
	Asura_Direct3D::D3DDevice->GetRenderState( D3DRS_SRGBWRITEENABLE, &uOldSRGBWrite );
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_SRGBWRITEENABLE, FALSE );
#endif

	Asura_Direct3D_Shaders::RequestFixedFunctionVertexShader( Line2D::Vertex::FVF );
	Asura_Render::CurrentStates.RequestTextureOpMode( ASURA_TEXTUREOP_COLOUR );
	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
	Asura_Render::CurrentStates.RequestZBufferEnabled( true );
	Asura_Direct3D::D3DDevice->DrawPrimitiveUP( D3DPT_LINELIST, uNumVertices / 2, (void*)pxVertexData, sizeof(Line2D::Vertex) );
	
#if defined( ASURA_TARGET_SM3)
	xRenderTargetStore.RestoreRenderTargets();
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_SRGBWRITEENABLE, uOldSRGBWrite );
#endif
}

// 3D Lines

Asura_Direct3D_LineRenderer::Line3D::Line3D( const Asura_Vector_3& xP1, const Asura_Vector_3& xP2, u_int uColour )
: m_xP1(xP1), m_xP2(xP2), m_uColour1(uColour), m_uColour2(uColour)
{ }

Asura_Direct3D_LineRenderer::Line3D::Line3D( const Asura_Vector_3& xP1, const Asura_Vector_3& xP2, u_int uColour1, u_int uColour2 )
: m_xP1(xP1), m_xP2(xP2), m_uColour1(uColour1), m_uColour2(uColour2)
{ }

void Asura_Direct3D_LineRenderer::Line3D::ToVertices(Line3D::Vertex& xP1, Line3D::Vertex& xP2, const Asura_Bounding_Rectangle& xSwapChainBounds) const
{
	xP1.fX = m_xP1.x;
	xP1.fY = m_xP1.y;
	xP1.fZ = m_xP1.z; 
	xP1.uColour = m_uColour1;

	xP2.fX = m_xP2.x;
	xP2.fY = m_xP2.y;
	xP2.fZ = m_xP2.z;
	xP2.uColour = m_uColour2;
}

void Asura_Direct3D_LineRenderer::Line3D::Render( const Line3D::Vertex* const pxVertexData, const u_int uNumVertices )
{
#if defined( ASURA_TARGET_SM3)
	// DLH - 14 February 2007 12:33:53 - Store and Clear all the RenderTargets after the first one
	Asura_Direct3D_StoreRenderTargets xRenderTargetStore;
	
	xRenderTargetStore.StoreRenderTargets();
	Asura_Direct3D::ClearRenderTargets( 1);

	// Disable sRGB here to preserve Tools' interface colours
	DWORD uOldSRGBWrite;
	Asura_Direct3D::D3DDevice->GetRenderState( D3DRS_SRGBWRITEENABLE, &uOldSRGBWrite );
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_SRGBWRITEENABLE, FALSE );
#endif

	Asura_Direct3D_Shaders::RequestFixedFunctionVertexShader( Line3D::Vertex::FVF );
	Asura_Render::CurrentStates.RequestTextureOpMode( ASURA_TEXTUREOP_COLOUR );
	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
	Asura_Render::CurrentStates.RequestZBufferEnabled( true );
	Asura_Direct3D::D3DDevice->DrawPrimitiveUP( D3DPT_LINELIST, uNumVertices / 2, (void*)pxVertexData, sizeof(Line3D::Vertex) );
	
#if defined( ASURA_TARGET_SM3)
	xRenderTargetStore.RestoreRenderTargets();
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_SRGBWRITEENABLE, uOldSRGBWrite );
#endif
}

// Batcher

const u_int uMAX_NUM_SWAP_CHAINS_2D = 16;
const u_int uMAX_NUM_SWAP_CHAINS_3D = 1;

void Asura_Direct3D_LineRenderer::Initialise( void )
{
	// JAT 27/11/06 for 2D lines let them go to lots of different swap chains
	BatchBuffer<Line2D>::Initialise( ASURA_DIRECT3D_LINERENDERER_2D_BATCH_SIZE, uMAX_NUM_SWAP_CHAINS_2D );
	// JAT 27/11/06 for 3D only have the lines going to swap chain 0 i.e. the primary device
	BatchBuffer<Line3D>::Initialise( ASURA_DIRECT3D_LINERENDERER_3D_BATCH_SIZE, uMAX_NUM_SWAP_CHAINS_3D );
}

void Asura_Direct3D_LineRenderer::Reset()
{
	Shutdown();
	Initialise();
}

// MGH 16/1/2008: Called before resetting the D3D device (i.e. changing video modes or Alt-Tabbing).
void Asura_Direct3D_LineRenderer::PreD3DReset()
{
}

// MGH 16/1/2008: Called after resetting the D3D device (i.e. changing video modes or Alt-Tabbing).
// We only want to reset this system if the number of swap chains have changed, otherwise the
// memory checkpoint debugging code would be affected every time that we Alt-Tabbed or hit a
// breakpoint in the debugger.
void Asura_Direct3D_LineRenderer::PostD3DReset()
{
	const bool bChanged2D = (BatchBuffer<Line2D>::ShouldReset(uMAX_NUM_SWAP_CHAINS_2D));
	const bool bChanged3D = (BatchBuffer<Line3D>::ShouldReset(uMAX_NUM_SWAP_CHAINS_3D));

	if (bChanged2D || bChanged3D)
	{
		// Number of swap chains has changed, need to reset.
		Reset();
	}
	else
	{
		// Just clear out any old data, to preserve the old behaviour.
		BatchBuffer<Line2D>::Clear();
		BatchBuffer<Line3D>::Clear();
	}
}

void Asura_Direct3D_LineRenderer::Shutdown()
{
	BatchBuffer<Line2D>::Shutdown();
	BatchBuffer<Line3D>::Shutdown();
}