//////////////////////////////////////////////////////////////////////////////
//
// Asura_PFX_Templates.cpp
//
// Copyright (c) 2006 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header.
#include "SpecialFX/Pfx/Asura_PFX_Templates.h"

// Asura includes
#include "Debugging/Asura_Assert.h"
#include "SpecialFX/Pfx/Asura_PFX_System.h"

//Get texture coordinates for current and next texture frame with weight of first one.
// This is to allow 2-pass rendering with alpha blend between frames.
void Asura_PFX_Particle_Template::GetTextureFramesForCrossfadeAtTime( float fTime, 
	const Asura_PFX_TextureFrame*& pxFrame0, const Asura_PFX_TextureFrame*& pxFrame1, float& fWeight) const
{
	Asura_Assert(m_uNumTextureFrames >= 2, "can't crossfade with less than 2 frames");
	if(m_bUseFPS)
	{
		// Use frames per second
		// TODO - handling for random lifetime, if desired
		const float fFrame = m_fMinLifetime * fTime * m_fFPS;
		const int iFrame = Asura_Maths::FloatToInt_Chop( fFrame );
		// use remainder to compute weight
		fWeight = 1.0f - (fFrame - static_cast<float>(iFrame));
		if(m_bLoopAnimation)
		{
			pxFrame0 = &m_pxTextureFrames[iFrame % m_uNumTextureFrames];
			pxFrame1 = &m_pxTextureFrames[(iFrame + 1) % m_uNumTextureFrames];
		}
		else
		{
			const int iMaxFrame = static_cast<int>(m_uNumTextureFrames - 1);
			const int iFrame0 = Asura_Maths::ClampToRange(iFrame, 0, iMaxFrame);
			const int iFrame1 = Asura_Maths::ClampToRange(iFrame + 1, 0, iMaxFrame);
			pxFrame0 = &m_pxTextureFrames[iFrame0];
			pxFrame1 = &m_pxTextureFrames[iFrame1];
		}
	}
	else
	{
		// Use time offsets
		const int iLastFrame = static_cast<int>(m_uNumTextureFrames - 1);
		const float fLastFrameTime = m_pxTextureFrames[iLastFrame].m_fTime;
		if (fTime >= fLastFrameTime)
		{
			// we already passed the last frame, no further crossfade
			fWeight = 0.0f;
			pxFrame1 = &m_pxTextureFrames[iLastFrame];
			pxFrame0 = pxFrame1;
		}
		else
		{
			// we have at least 1 frame to crossfade to
			int iFrame0 = 0;
			int iFrame1;
			fWeight = 1.0f;	// initialise weight to avoid compiler warning.
			for(iFrame1 = iLastFrame; iFrame1 >= 1; --iFrame1)
			{
				iFrame0 = (iFrame1 - 1);
				float fThisFrameTime = m_pxTextureFrames[iFrame0].m_fTime;
				float fNextFrameTime = m_pxTextureFrames[iFrame1].m_fTime;

				if (fTime > fThisFrameTime)
				{
					Asura_Assert(fNextFrameTime > fThisFrameTime, "non-sequential frame times");
					float fCrossfadeDuration = fNextFrameTime - fThisFrameTime;
					float fCrossfadeTime = fTime - fThisFrameTime;
					Asura_Assert(fCrossfadeTime <= fCrossfadeDuration, "frame time mix-up");
					fWeight = (fCrossfadeDuration - fCrossfadeTime) / fCrossfadeDuration;
					break;
				}
			}
			pxFrame0 = &m_pxTextureFrames[iFrame0];
			pxFrame1 = &m_pxTextureFrames[iFrame1];
		}

	}
}

#ifdef ASURA_TOOLS
bool Asura_PFX_Effect_Template::IsModified() const
{
	if(m_bModified) return true;

	//check the source and particle templates that this uses as well
	for(u_int i=0;i<m_uNumSources;i++)
	{
		//check the source
		Asura_PFX_Source_Template* pxSource = Asura_PFX_System::GetSourceTempByHash(m_pxSources[i].m_uTemplate, true);
		if(!pxSource) continue;
		if(pxSource->m_bModified) return true;

		//and the particle it uses
		Asura_PFX_Particle_Template* pxParticle = Asura_PFX_System::GetParticleTempByHash(pxSource->m_uParticleTemplateHash, true);
		if(!pxParticle) continue;
		if(pxParticle->m_bModified) return true;
	}
	return false;
}

void Asura_PFX_Effect_Template::SetModified(bool bModified)
{
	m_bModified = bModified;

	//if setting to false , then also set the flag in any source/particle templates as well
	if(!bModified)
	{
		for(u_int i=0;i<m_uNumSources;i++)
		{
			//check the source
			Asura_PFX_Source_Template* pxSource = Asura_PFX_System::GetSourceTempByHash(m_pxSources[i].m_uTemplate);
			if(!pxSource) continue;
			pxSource->m_bModified = bModified;

			//and the particle it uses
			Asura_PFX_Particle_Template* pxParticle = Asura_PFX_System::GetParticleTempByHash(pxSource->m_uParticleTemplateHash);
			if(!pxParticle) continue;
			pxParticle->m_bModified = bModified;
		}
	}
}
#endif //ASURA_TOOLS

#ifndef ASURA_GRAPH_LEAN_AND_MEAN

// This function will run through all the sources and alter the samples in their particle templates. Currently it's an all-or-nothing
// thing: there's no way of specifying which sources should be colourised. Don't use this for editing code in tools as the discrete
// samples will be over-written with data from the splines.
void Asura_PFX_Effect_Template::ColouriseEffectTemplate( Asura_PFX_Effect_Template* pxEffectTemplate, const Asura_RGBA& xColour )
{
	for( u_int u=0; u<pxEffectTemplate->m_uNumSources; ++u )
	{
		// get the source data
		Asura_PFX_Source_Template* pxSourceTemplate	= Asura_PFX_System::GetSourceTempByHash( pxEffectTemplate->m_pxSources[u].m_uTemplate );				
		if( pxSourceTemplate )
		{
			// get the particle template
			Asura_PFX_Particle_Template* pxParticleTemplate	= Asura_PFX_System::GetParticleTempByHash( pxSourceTemplate->m_uParticleTemplateHash );
			if( pxParticleTemplate )
			{
				Asura_RGBA* pxColourSamples = pxParticleTemplate->m_xColour.GetDiscreteSamplesForEdit();
				for( u_int v=0; v<pxParticleTemplate->m_xColour.GetNumDiscreteSamples(); ++v )
				{
					Asura_RGBA& xColourSample = pxColourSamples[v];				

					xColourSample.m_fR *= xColour.m_fR;
					xColourSample.m_fG *= xColour.m_fG;
					xColourSample.m_fB *= xColour.m_fB;
				}
			}
		}
	}
}

#endif // #ifndef ASURA_GRAPH_LEAN_AND_MEAN
