//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "cbase.h"
#include "particles_ez.h"
#include "igamesystem.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"


// Singletons for each type of particle system.
// 0 = world, 1 = skybox
static CSmartPtr<CSimpleEmitter> g_pSimpleSingleton[2];
static CSmartPtr<CEmberEffect> g_pEmberSingleton[2];
static CSmartPtr<CFireSmokeEffect> g_pFireSmokeSingleton[2];
static CSmartPtr<CFireParticle> g_pFireSingleton[2];


class CEZParticleInit : public CAutoGameSystem
{
public:
	CEZParticleInit() : CAutoGameSystem( "CEZParticleInit" )
	{
	}

	template< class T >
	CSmartPtr<T> InitSingleton( CSmartPtr<T> pEmitter )
	{
		if ( !pEmitter )
		{
			Error( "InitSingleton: pEmitter is NULL" );
		}
	
		pEmitter->GetBinding().SetDrawThruLeafSystem( false );				// Draw in DrawSingletons instead.
		pEmitter->SetSortOrigin( Vector( 0, 0, 0 ) );

		// Since we draw manually in DrawSingletons, we don't care about
		// the bbox, so don't waste cycles inserting it into the leaf system
		// when it's not going to draw through that anyway.
		// (TODO: SetDrawThruLeafSystem(false) should trigger this automatically
		// in CParticleMgr).
		pEmitter->GetBinding().SetBBox( Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
		return pEmitter;
	}

	virtual void LevelInitPreEntity()
	{
		g_pSimpleSingleton[0] = InitSingleton( CSimpleEmitter::Create( "Simple Particle Singleton" ) );
		g_pSimpleSingleton[1] = InitSingleton( CSimpleEmitter::Create( "Simple Particle Singleton [sky]" ) );
		
		g_pEmberSingleton[0] = InitSingleton( CEmberEffect::Create( "Ember Particle Singleton" ) );
		g_pEmberSingleton[1] = InitSingleton( CEmberEffect::Create( "Ember Particle Singleton [sky]" ) );
		
		g_pFireSmokeSingleton[0] = InitSingleton( CFireSmokeEffect::Create( "Fire Smoke Particle Singleton" ) );
		g_pFireSmokeSingleton[1] = InitSingleton( CFireSmokeEffect::Create( "Fire Smoke Particle Singleton [sky]" ) );
		
		g_pFireSingleton[0] = InitSingleton( CFireParticle::Create( "Fire Particle Singleton" ) );
		g_pFireSingleton[1] = InitSingleton( CFireParticle::Create( "Fire Particle Singleton [sky]" ) );
	}


	virtual void LevelShutdownPreEntity()
	{
		g_pSimpleSingleton[0] = g_pSimpleSingleton[1] = NULL;
		g_pEmberSingleton[0] = g_pEmberSingleton[1] = NULL;
		g_pFireSmokeSingleton[0] = g_pFireSmokeSingleton[1] = NULL;
		g_pFireSingleton[0] = g_pFireSingleton[1] = NULL;
	}
};

static CEZParticleInit g_EZParticleInit;


template<class T>
inline void CopyParticle( const T *pSrc, T *pDest )
{
	if ( pDest )
	{
		// Copy the particle, but don't screw up the linked list it's in.
		Particle *pPrev = pDest->m_pPrev;
		Particle *pNext = pDest->m_pNext;
		PMaterialHandle pSubTexture = pDest->m_pSubTexture;
		
		*pDest = *pSrc;
		
		pDest->m_pPrev = pPrev;
		pDest->m_pNext = pNext;
		pDest->m_pSubTexture = pSubTexture;
	}
}
		


void AddSimpleParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox )
{
	if ( g_pSimpleSingleton[bInSkybox].IsValid() )
	{
		SimpleParticle *pNew = g_pSimpleSingleton[bInSkybox]->AddSimpleParticle( hMaterial, pParticle->m_Pos );
		CopyParticle( pParticle, pNew );
	}
}


void AddEmberParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox )
{
	if ( g_pEmberSingleton[bInSkybox].IsValid() )
	{
		SimpleParticle *pNew = g_pEmberSingleton[bInSkybox]->AddSimpleParticle( hMaterial, pParticle->m_Pos );
		CopyParticle( pParticle, pNew );
	}
}


void AddFireSmokeParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox )
{
	if ( g_pFireSmokeSingleton[bInSkybox].IsValid() )
	{
		SimpleParticle *pNew = g_pFireSmokeSingleton[bInSkybox]->AddSimpleParticle( hMaterial, pParticle->m_Pos );
		CopyParticle( pParticle, pNew );
	}
}


void AddFireParticle( const SimpleParticle *pParticle, PMaterialHandle hMaterial, bool bInSkybox )
{
	if ( g_pFireSingleton[bInSkybox].IsValid() )
	{
		SimpleParticle *pNew = g_pFireSingleton[bInSkybox]->AddSimpleParticle( hMaterial, pParticle->m_Pos );
		CopyParticle( pParticle, pNew );
	}
}


void DrawParticleSingletons( bool bInSkybox )
{
	if ( g_pSimpleSingleton[bInSkybox].IsValid() )
	{
		g_pSimpleSingleton[bInSkybox]->GetBinding().DrawModel( 1 );
	}

	if ( g_pEmberSingleton[bInSkybox].IsValid() )
	{
		g_pEmberSingleton[bInSkybox]->GetBinding().DrawModel( 1 );
	}

	if ( g_pFireSmokeSingleton[bInSkybox].IsValid() )
	{
		g_pFireSmokeSingleton[bInSkybox]->GetBinding().DrawModel( 1 );
	}
	
	if ( g_pFireSingleton[bInSkybox].IsValid() )
	{
		g_pFireSingleton[bInSkybox]->GetBinding().DrawModel( 1 );
	}
}