
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_PFX_RenderQueue.cpp
// Author : Andy Tate
// Date   : 19-Jun-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "SpecialFX/PFX/Asura_PFX_RenderQueue.h"

// Asura independent header-files...
#include "SpecialFX/PFX/Asura_PFX_Effect.h"
#include "SpecialFX/PFX/Asura_PFX_Templates.h"


////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue::CommandListCompare
// Author       : Andy Tate
// Date         : 25-Jun-2008
////////////////////////////////////////////////////////////////////////////////

int Asura_PFX_RenderQueue::CommandListCompare(Asura_PFX_Particle_Template const* const& pxTemplate1,
											  Asura_PFX_Particle_Template const* const& pxTemplate2)
{
	if(pxTemplate1 == pxTemplate2)
	{
		return(0);
	}
	else
	{
		const bool bSolid1 	= (pxTemplate1->m_eTranslucency == ASURA_TRANSLUCENCY_OFF);
		const bool bSolid2 	= (pxTemplate2->m_eTranslucency == ASURA_TRANSLUCENCY_OFF);

		// Solid comes first...
		if(bSolid1 && !bSolid2)
		{
			return(-1);
		}
		else if(bSolid2 && !bSolid1)
		{
			return(1);
		}
		else
		{
			const bool bRenderEarly1 	= pxTemplate1->m_bRenderEarly;
			const bool bRenderEarly2 	= pxTemplate2->m_bRenderEarly;

			// Render early comes next.
			if(bRenderEarly1 && !bRenderEarly2)
			{
				return(-1);
			}
			else if(bRenderEarly2 && !bRenderEarly1)
			{
				return(1);
			}
			else
			{
				const int	iTextureHandleDifference	= pxTemplate1->m_iTextureHandle - pxTemplate2->m_iTextureHandle;

				// Then sort by texture...
				if(iTextureHandleDifference == 0)
				{
					const int	iTemplate1	= reinterpret_cast<int>(pxTemplate1);
					const int	iTemplate2	= reinterpret_cast<int>(pxTemplate2);

					// As a last resort - sort by pointers...
					return(iTemplate1 - iTemplate2);
				}
				else
				{
					return(iTextureHandleDifference);
				}
			}
		}
	}
}

/// End of function 'Asura_PFX_RenderQueue::CommandListCompare'. ///



////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue_Command::Initialise
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue_Command::Initialise(const Asura_PFX_Particle* pxParticles,
											   const u_int uNumParticles,
											   const Asura_RGBA& xLightColour,
											   Asura_PFX_Effect& xEffect,
											   void* pPlatformRenderData)
{
	m_pxParticles			= pxParticles;
	m_uNumParticles			= uNumParticles;
	m_xLightColour			= xLightColour;
	m_pxEffect				= &xEffect;
#if defined(ASURA_SUPPORT_MULTITHREADED_JOB_QUEUE)
	m_pPlatformRenderData	= pPlatformRenderData;
#endif	//defined(ASURA_SUPPORT_MULTITHREADED_JOB_QUEUE)
	m_pxNextCommand			= NULL;
}

/// End of function 'Asura_PFX_RenderQueue_Command::Initialise'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue_Command::RenderParticles
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue_Command::RenderParticles(const Asura_PFX_Particle_Template& xParticleTemplate)
{
#if defined(ASURA_SUPPORT_MULTITHREADED_JOB_QUEUE)
	void*	pPlatformRenderData	= m_pPlatformRenderData;
#else
	void*	pPlatformRenderData	= NULL;
#endif	//defined(ASURA_SUPPORT_MULTITHREADED_JOB_QUEUE)

	m_pxEffect->RenderParticles(m_pxParticles, m_uNumParticles, &xParticleTemplate, m_xLightColour, pPlatformRenderData);
}

/// End of function 'Asura_PFX_RenderQueue_Command::RenderParticles'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue_CommandList::AddCommand
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue_CommandList::AddCommand(Asura_PFX_RenderQueue_Command& xCommand)
{
	xCommand.SetNextCommand(m_pxFirstCommand);
	m_pxFirstCommand	= &xCommand;
}

/// End of function 'Asura_PFX_RenderQueue_CommandList::AddCommand'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue_CommandList::RenderParticles
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue_CommandList::RenderParticles(void)
{
	Asura_PFX_RenderQueue_Command*	pxCommand	= m_pxFirstCommand;

	while(pxCommand != NULL)
	{
		pxCommand->RenderParticles(*m_pxParticleTemplate);

		pxCommand	= pxCommand->GetNextCommand();
	}
}

/// End of function 'Asura_PFX_RenderQueue_CommandList::RenderParticles'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue::Asura_PFX_RenderQueue
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

Asura_PFX_RenderQueue::Asura_PFX_RenderQueue(void)
: m_xCommandListContainer(CommandListCompare)
#if defined(ASURA_PFX_RENDER_QUEUE_SIZE)
, m_xCommandMempool(sizeof(Asura_PFX_RenderQueue_Command), ASURA_PFX_RENDER_QUEUE_SIZE)
#else
#if defined(ASURA_MEMORYMANAGEMENT_ENABLED)
, m_xCommandMempool(sizeof(Asura_PFX_RenderQueue_Command), 128, __FILE__, __LINE__)
#else
, m_xCommandMempool(sizeof(Asura_PFX_RenderQueue_Command), 128)
#endif	//defined(ASURA_MEMORYMANAGEMENT_ENABLED)
#endif	//defined(ASURA_PFX_RENDER_QUEUE_SIZE)
{
}

/// End of function 'Asura_PFX_RenderQueue::Asura_PFX_RenderQueue'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue::AddParticles
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue::AddParticles(const Asura_PFX_Particle_Template& xParticleTemplate,
										 const Asura_PFX_Particle* pxParticles,
										 const u_int uNumParticles,
										 const Asura_RGBA& xLightColour,
										 Asura_PFX_Effect& xEffect,
										 void* pPlatformRenderData)
{
	const Asura_PFX_Particle_Template*	pxParticleTemplate	= &xParticleTemplate;
	Asura_PFX_RenderQueue_CommandList*	pxCommandList		= m_xCommandListContainer.GetData(pxParticleTemplate);

	Asura_PFX_RenderQueue_Command*		pxNewCommand;

#if defined(ASURA_PFX_RENDER_QUEUE_SIZE)
	if(m_xCommandMempool.GetNumAllocated() == ASURA_PFX_RENDER_QUEUE_SIZE)
	{
		Flush();
	}
#endif	//defined(ASURA_PFX_RENDER_QUEUE_SIZE)
	pxNewCommand	= static_cast<Asura_PFX_RenderQueue_Command*>(m_xCommandMempool.Allocate());

	// Has this particle-template already been added for render...
	if(pxCommandList == NULL)
	{
		pxCommandList	= m_xCommandListContainer.AddNode(pxParticleTemplate);
		pxCommandList->SetParticleTemplate(pxParticleTemplate);
	}

	// Initialise the command-data...
	pxNewCommand->Initialise(pxParticles, uNumParticles, xLightColour, xEffect, pPlatformRenderData);
	pxCommandList->AddCommand(*pxNewCommand);
}

/// End of function 'Asura_PFX_RenderQueue::AddParticles'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PFX_RenderQueue::Flush
// Author       : Andy Tate
// Date         : 19-Jun-2008
////////////////////////////////////////////////////////////////////////////////

void Asura_PFX_RenderQueue::Flush(void)
{
	CommandListIterator	xIterator(m_xCommandListContainer);

	// Render all of the particles in our command-list...
	while(!xIterator.Done())
	{
		Asura_PFX_RenderQueue_CommandList*	pxCommandList	= xIterator.GetCurrent();

		if(pxCommandList != NULL)
		{
			pxCommandList->RenderParticles();
		}

		xIterator.Next();
	}

	// Reset the command-list AND the memory-pool where our commands are stored...
	m_xCommandListContainer.Reset();
#if defined(ASURA_PFX_RENDER_QUEUE_SIZE)
	m_xCommandMempool.Reset();
#else
	m_xCommandMempool.ForceReset();
#endif	//defined(ASURA_PFX_RENDER_QUEUE_SIZE)
}

/// End of function 'Asura_PFX_RenderQueue::Flush'. ///


/// End of file. ///
