
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Animation_PrimaryWrapper.cpp
// Author : Andy Tate
// Date   : 19-Sep-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Animation/Asura_Animation_PrimaryWrapper.h"

// Asura independent header-files...
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_AnimationBlend.h"
#include "Animation/Asura_AnimationController_Animation.h"

// Asura platform header-files...

// Game independent header-files...

// Game platform header-files...

// Tools header-files...


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

static const u_int	g_uPrimaryAnimationPriority		= 0x00008000;
static const u_int	g_uSecondaryAnimationPriority	= 0x00000000;


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

Asura_Hash_ID	Asura_Animation_PrimaryWrapper::s_uUniqueAnimationHash	= 1;


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

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetAnimationFromHandle
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_AnimationController_Animation* Asura_Animation_PrimaryWrapper::GetAnimationFromHandle (const Asura_Handle iHandle)
{
	// Is this the primary animation?
	if(iHandle == ASURA_PRIMARY_ANIMATION_HANDLE)
	{
		return(m_pxAnimation->GetControllerAnimationFromHash(m_uPrimaryControllerHash));
	}
	else
	{
		const Asura_Hash_ID	uControllerHash	= iHandle;

		// Assume that the handle is the hash-ID, slightly dangerous...
		return(m_pxAnimation->GetControllerAnimationFromHash(uControllerHash));
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetAnimationFromHandle'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetAnimationFromHandle
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

const Asura_AnimationController_Animation* Asura_Animation_PrimaryWrapper::GetAnimationFromHandle (const Asura_Handle iHandle) const
{
	// Is this the primary animation?
	if(iHandle == ASURA_PRIMARY_ANIMATION_HANDLE)
	{
		return(m_pxAnimation->GetControllerAnimationFromHash(m_uPrimaryControllerHash));
	}
	else
	{
		const Asura_Hash_ID	uControllerHash	= iHandle;

		// Assume that the handle is the hash-ID, slightly dangerous...
		return(m_pxAnimation->GetControllerAnimationFromHash(uControllerHash));
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetAnimationFromHandle'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToControllerFlags
// Author       : Andy Tate
// Date         : 20-Sep-2006
////////////////////////////////////////////////////////////////////////////////

u_int Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToControllerFlags (const int iAnimFlags)
{
	u_int	uControllerFlags	= AAC_FLAG_ACTIVE;

	// Animation control flags...
	if((iAnimFlags & AsuraAnimationFlag_Loop) != 0)
	{
		uControllerFlags	|= AACA_FLAG_LOOPED;
	}

	if((iAnimFlags & AsuraAnimationFlag_Reversed) != 0)
	{
		uControllerFlags	|= AACA_FLAG_REVERSED;
	}

	if((iAnimFlags & AsuraAnimationFlag_Mirror) != 0)
	{
		uControllerFlags	|= AACA_FLAG_MIRRORED;
	}

	// Animation clean-up flags...
	// KOR - the tween out will take care of things if it's turned on.
	if((iAnimFlags & AsuraAnimationFlag_AutoRemove) != 0 && (iAnimFlags & AsuraAnimationFlag_TweenOut) == 0)
	{
		uControllerFlags	|= AAC_FLAG_DESTROY_WHEN_FINISHED;
	}
	else
	{
		uControllerFlags	|= AAC_FLAG_ALLOW_DESTROY_FROM_MESSAGE;
	}

	// Movement offset flags...
	if((iAnimFlags & AsuraAnimationFlag_UseMovementOffset) != 0)
	{
		// The new system has separate flags for all three.
		uControllerFlags	|= AACA_FLAG_CALCULATE_VELOCITY | AACA_FLAG_CALCULATE_ANGULAR_VELOCITY | AACA_FLAG_CALCULATE_MOVEMENT_OFFSET;
	}

	// Root tweening flags...
	if((iAnimFlags & AsuraAnimationFlag_DontTweenRoot) == 0)
	{
		if((iAnimFlags & AsuraAnimationFlag_DontTweenRootPos) != 0)
		{
			uControllerFlags	|= AACA_FLAG_DONT_TWEEN_ROOT_POSITION;
		}

		if((iAnimFlags & AsuraAnimationFlag_DontTweenRootOrient) != 0)
		{
			uControllerFlags	|= AACA_FLAG_DONT_TWEEN_ROOT_ORIENTATION;
		}
	}
	else
	{
		uControllerFlags	|= AACA_FLAG_DONT_TWEEN_ROOT_POSITION | AACA_FLAG_DONT_TWEEN_ROOT_ORIENTATION;
	}

	// Return the controller flags...
	return(uControllerFlags);
}

/// End of function 'Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToControllerFlags'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToBlend
// Author       : Andy Tate
// Date         : 21-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_AnimationBlend* Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToBlend (const int iAnimFlags,
																			   const float fTweenDuration)
{
	if((iAnimFlags & AsuraAnimationFlag_Tween) != 0)
	{
		Asura_AnimationBlend_Tween* pxTween = new Asura_AnimationBlend_Tween (fTweenDuration, false);
		return pxTween;
	}
	else if((iAnimFlags & AsuraAnimationFlag_SyncWithPrimary) != 0)
	{
		Asura_AnimationBlend_Tween* pxTween  = new Asura_AnimationBlend_Tween (fTweenDuration, true);
		return pxTween;
	}
	else if((iAnimFlags & AsuraAnimationFlag_TweenOut) != 0)
	{
		return(new Asura_AnimationBlend_TweenOut (fTweenDuration));
	}
	else if((iAnimFlags & AsuraAnimationFlag_AnimatedTween) != 0)
	{
		Asura_AnimationBlend_Tween* pxTween = new Asura_AnimationBlend_AnimatedTween (fTweenDuration, false);
		return pxTween;
	}
	else if((iAnimFlags & AsuraAnimationFlag_AnimatedTween_SyncTimers) != 0)
	{
		Asura_AnimationBlend_Tween* pxTween = new Asura_AnimationBlend_AnimatedTween (fTweenDuration, true);
		return pxTween;
	}
	else
	{
		//RAR 24/11/2006 Need a fake blend to prevent secondary animations from being obliterated
		Asura_AnimationBlend_Tween* pxTween = new Asura_AnimationBlend_Tween (0.0f, false);
		//RAR 22/01/2009 Set tween weight to 1 , so that our zero-lengthed tween behaves correctly
		//if accessed before its first update.
		pxTween->SetWeight(1.0f);
		return pxTween;
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::ConvertAnimFlagsToBlend'. ///



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


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

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::PlayAnimToPos
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Handle Asura_Animation_PrimaryWrapper::PlayAnimToPos (const Asura_Hash_ID uAnimHash,
															float fStartTimer,
															float fEndTimer,
															const int iAnimFlags,
															const float fTweenDuration)
{
	u_int									uControllerFlags	= ConvertAnimFlagsToControllerFlags(iAnimFlags) | AAC_FLAG_ALLOW_DESTROY_FROM_MESSAGE | AACA_FLAG_LOOPED;
	if(fStartTimer > fEndTimer)
	{
		//If the start time is greater than the end time then the animation is reversed.
		//Due to the way the parametric timer always goes up with the new animation system we need to 'reverse'
		//the timers by subtracting from 1
		//RAR 15/08/2007
		fStartTimer = 1.0f - fStartTimer;
		fEndTimer = 1.0f - fEndTimer;
		uControllerFlags |= AACA_FLAG_REVERSED;
	}

	Asura_AnimationBlend*					pxBlend				= ConvertAnimFlagsToBlend(iAnimFlags, fTweenDuration);
	Asura_AnimationController_Animation*	pxNewAnimation		= m_pxAnimation->CreateControllerAnimation(s_uUniqueAnimationHash++, uControllerFlags, g_uPrimaryAnimationPriority, uAnimHash, pxBlend);

	// Did we create the animation?
	if(pxNewAnimation != NULL)
	{
		// Generate the appropriate tween...
		if( (pxBlend == NULL) &&
			(m_uPrimaryControllerHash != ASURA_HASH_ID_UNSET) )
		{
			m_uPrimaryControllerHash	= ASURA_HASH_ID_UNSET;
		}

		// Finally, play the animation...
		pxNewAnimation->SetParametricTimer(fStartTimer);
		if(!(iAnimFlags & AsuraAnimationFlag_Loop))
		{
			pxNewAnimation->SetParametricTargetTime(fEndTimer);
		}

		if(pxNewAnimation->Play())
		{
			m_uPrimaryControllerHash	= pxNewAnimation->GetControllerHash();
		}
	}

	// Return the handle...
	return(m_uPrimaryControllerHash);
}

/// End of function 'Asura_Animation_PrimaryWrapper::PlayAnimToPos'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::StartAnim
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Handle Asura_Animation_PrimaryWrapper::StartAnim (const Asura_Hash_ID uAnimHash,
														const bool bLooped,
														const float fTweenDuration,
														const bool bReversed,
														const float fTimeDelay)
{
	const int								iAnimFlags			= ((bLooped) ? AsuraAnimationFlag_Loop : 0) | ((bReversed) ? AsuraAnimationFlag_Reversed : 0) | ((fTweenDuration > 0.0f) ? AsuraAnimationFlag_Tween : 0);
	const u_int								uControllerFlags	= ConvertAnimFlagsToControllerFlags(iAnimFlags) | AAC_FLAG_ALLOW_DESTROY_FROM_MESSAGE;
	Asura_AnimationBlend*					pxBlend				= ConvertAnimFlagsToBlend(iAnimFlags, fTweenDuration);
	Asura_AnimationController_Animation*	pxNewAnimation		= m_pxAnimation->CreateControllerAnimation(s_uUniqueAnimationHash++, uControllerFlags, g_uPrimaryAnimationPriority, uAnimHash, pxBlend);

	// Did we create the animation?
	if(pxNewAnimation != NULL)
	{
		// Generate the appropriate tween...
		if( (pxBlend == NULL) &&
			(m_uPrimaryControllerHash != ASURA_HASH_ID_UNSET) )
		{
			m_uPrimaryControllerHash	= ASURA_HASH_ID_UNSET;
		}

		// Finally, play the animation...
		pxNewAnimation->SetTimeDelay(fTimeDelay);

		if(pxNewAnimation->Play())
		{
			m_uPrimaryControllerHash	= pxNewAnimation->GetControllerHash();
		}
	}

	// Return the handle...
	return(m_uPrimaryControllerHash);
}

/// End of function 'Asura_Animation_PrimaryWrapper::StartAnim'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::StartAnim2
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Handle Asura_Animation_PrimaryWrapper::StartAnim2 (const Asura_Hash_ID uAnimHash,
														 const int iAnimFlags,
														 const float fTweenDuration,
														 const float fTimeDelay)
{
	const u_int								uControllerFlags	= ConvertAnimFlagsToControllerFlags(iAnimFlags) | AAC_FLAG_ALLOW_DESTROY_FROM_MESSAGE;
	Asura_AnimationBlend*					pxBlend				= ConvertAnimFlagsToBlend(iAnimFlags, fTweenDuration);
	Asura_AnimationController_Animation*	pxNewAnimation		= m_pxAnimation->CreateControllerAnimation(s_uUniqueAnimationHash++, uControllerFlags, g_uPrimaryAnimationPriority, uAnimHash, pxBlend);

	// Did we create the animation?
	if(pxNewAnimation != NULL)
	{
		// Generate the appropriate tween...
		if( (pxBlend == NULL) &&
			(m_uPrimaryControllerHash != ASURA_HASH_ID_UNSET) )
		{
			m_uPrimaryControllerHash	= ASURA_HASH_ID_UNSET;
		}

		// Finally, play the animation...
		pxNewAnimation->SetTimeDelay(fTimeDelay);

		if(pxNewAnimation->Play())
		{
			m_uPrimaryControllerHash	= pxNewAnimation->GetControllerHash();
		}
	}

	// Return the handle...
	return(m_uPrimaryControllerHash);
}

/// End of function 'Asura_Animation_PrimaryWrapper::StartAnim2'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::AddOneShotAnim2
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////
Asura_Handle Asura_Animation_PrimaryWrapper::AddOneShotAnim2 (const Asura_Hash_ID uAnimHash,
															  const float fWeight,
															  const int iAnimFlags,
															  const float fTweenDuration,
															  const float fTimeDelay)
{
	u_int uControllerFlags = ConvertAnimFlagsToControllerFlags(iAnimFlags);
	if((iAnimFlags & AsuraAnimationFlag_AutoRemove))
	{
		//The anim flag conversion only pays attention to autoremove if tween out is also set , but
		//for secondaries it should be removed regardless in this case.
		//RAR 25/04/2008
		uControllerFlags |= AAC_FLAG_DESTROY_WHEN_FINISHED;
	}


	// TODO - handle these flags.
	//const bool bSync = (iAnimFlags & AsuraAnimationFlag_SyncWithPrimary) != 0;

	const float fTweenInDuration = ((iAnimFlags & (AsuraAnimationFlag_Tween|AsuraAnimationFlag_AnimatedTween)) != 0) ? fTweenDuration : 0.0f;
	const float fTweenOutDuration = ((iAnimFlags & AsuraAnimationFlag_TweenOut) != 0) ? fTweenDuration : 0.0f;
	
	Asura_AnimationBlend* pxBlend = new Asura_AnimationBlend_Secondary(fWeight,fTweenInDuration, fTweenOutDuration);
	
	Asura_AnimationController_Animation*	pxNewAnimation		= m_pxAnimation->CreateControllerAnimation(s_uUniqueAnimationHash++, uControllerFlags, g_uSecondaryAnimationPriority, uAnimHash, pxBlend);

	// Did we create the animation?
	if(pxNewAnimation == NULL)
	{
		return(ASURA_INVALID_HANDLE);
	}
	//CLF (03.08.2007) - If anim not found then destroy controller
	else if(pxNewAnimation->GetAnimation() == NULL)
	{
		RemoveOneShotAnim(pxNewAnimation->GetControllerHash());
		return(ASURA_INVALID_HANDLE);
	}
	else
	{
		// Finally, play the animation...
		pxNewAnimation->SetTimeDelay(fTimeDelay);
		pxNewAnimation->Play();
		return(pxNewAnimation->GetControllerHash());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::AddOneShotAnim2'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::ChangeOneShotAnimPriority
// Author       : Craig Flaherty
// Date         : 03-Sep-2007
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::ChangeOneShotAnimPriority(Asura_Handle iHandle, int iPriority)
{
	Asura_Assert( iHandle != ASURA_INVALID_HANDLE, "invalid handle" );
	Asura_AnimationController_Animation* pxControllerAnimation = GetAnimationFromHandle(iHandle);

	if(pxControllerAnimation)
	{
		pxControllerAnimation->SetPriority(iPriority);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::ChangeOneShotAnimPriority'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetAnimHashID
// Author       : Craig Flaherty
// Date         : 03-Sep-2007
////////////////////////////////////////////////////////////////////////////////

Asura_Hash_ID Asura_Animation_PrimaryWrapper::GetAnimHashID( Asura_Handle iAnimHandle ) const
{
	Asura_Assert( iAnimHandle != ASURA_INVALID_HANDLE, "invalid handle" );
	const Asura_AnimationController_Animation* pxControllerAnimation = GetAnimationFromHandle(iAnimHandle);

	if( pxControllerAnimation )
	{
		return pxControllerAnimation->GetAnimationHash();
	}

	return ASURA_HASH_ID_UNSET;
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetAnimHashID'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetAutoRemove
// Author       : Craig Flaherty
// Date         : 03-Sep-2007
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetAutoRemove(bool bRemove,Asura_Handle iHandle)
{
	Asura_Assert( iHandle != ASURA_INVALID_HANDLE, "invalid handle" );
	Asura_AnimationController_Animation* pxControllerAnimation = GetAnimationFromHandle(iHandle);

	if(pxControllerAnimation)
	{
		u_int uControllerFlags = pxControllerAnimation->GetControllerFlags();

		if(bRemove)
		{
			uControllerFlags |= AAC_FLAG_DESTROY_WHEN_FINISHED;
		}
		else
		{
			uControllerFlags &= (~AAC_FLAG_DESTROY_WHEN_FINISHED);
		}

		pxControllerAnimation->SetControllerFlags(uControllerFlags);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetAutoRemove'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetOneShotAnimWeighting
// Author       : Craig Flaherty
// Date         : 03-Sep-2007
////////////////////////////////////////////////////////////////////////////////
float Asura_Animation_PrimaryWrapper::GetOneShotAnimWeighting( Asura_Handle iHandle )
{
	const Asura_AnimationController_Animation* pxControllerAnimation = GetAnimationFromHandle(iHandle);

	if(pxControllerAnimation)
	{
		if(pxControllerAnimation->GetBlendToNextController())
		{
			return pxControllerAnimation->GetBlendToNextController()->GetWeight();
		}
	}

	return 0.0f;
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetOneShotAnimWeighting'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::PlayOneShotAnimToPos
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Handle Asura_Animation_PrimaryWrapper::PlayOneShotAnimToPos (const Asura_Hash_ID uAnimHash,
																   const float fWeight,
																   float fStartTimer,
																   float fEndTimer,
																   const int iAnimFlags)
{
	u_int								uControllerFlags	= ConvertAnimFlagsToControllerFlags(iAnimFlags);
	if(fStartTimer > fEndTimer)
	{
		//If the start time is greater than the end time then the animation is reversed.
		//Due to the way the parametric timer always goes up with the new animation system we need to 'reverse'
		//the timers by subtracting from 1
		//RAR 15/08/2007
		fStartTimer = 1.0f - fStartTimer;
		fEndTimer = 1.0f - fEndTimer;
		uControllerFlags |= AACA_FLAG_REVERSED;
	}

	Asura_AnimationBlend*					pxBlend				= new Asura_AnimationBlend (fWeight);
	Asura_AnimationController_Animation*	pxNewAnimation		= m_pxAnimation->CreateControllerAnimation(s_uUniqueAnimationHash++, uControllerFlags, g_uSecondaryAnimationPriority, uAnimHash, pxBlend);

	// Did we create the animation?
	if(pxNewAnimation == NULL)
	{
		return(ASURA_INVALID_HANDLE);
	}
	else
	{
		// Finally, play the animation...
		pxNewAnimation->SetParametricTimer(fStartTimer);
		if(!(iAnimFlags & AsuraAnimationFlag_Loop))
		{
			pxNewAnimation->SetParametricTargetTime(fEndTimer);
		}

		pxNewAnimation->Play();
		return(pxNewAnimation->GetControllerHash());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::PlayOneShotAnimToPos'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::ChangeOneShotAnimWeighting
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::ChangeOneShotAnimWeighting (const Asura_Handle iHandle,
																 const float fWeight)
{
	Asura_AnimationController*	pxController	= m_pxAnimation->GetControllerAnimationFromHash(iHandle);

	// Modify the appropriate weight...
	if(pxController != NULL)
	{
		Asura_AnimationBlend*	pxBlend	= pxController->GetBlendToPreviousController();

		if(pxBlend == NULL)
		{
			Asura_Assert(false, "No blending is present from this controller.");
		}
		else
		{
			pxBlend->SetWeight(fWeight);
		}
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::ChangeOneShotAnimWeighting'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::RemoveOneShotAnim
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::RemoveOneShotAnim (const Asura_Handle iHandle)
{
	// Remove the appropriate controller...
	m_pxAnimation->DestroyController(iHandle);
}

/// End of function 'Asura_Animation_PrimaryWrapper::RemoveOneShotAnim'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::DestroyOneShotAnimation_Traverse
// Author       : Andy Tate
// Date         : 27-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::DestroyOneShotAnimation_Traverse (Asura_Hash_ID uHash,
																	   Asura_AnimationController_Animation** ppxAnimation,
																	   void* pAnimation)
{
	Asura_AnimationController_Animation*	pxAnimation	= (ppxAnimation == NULL) ? NULL : *ppxAnimation;

	// Do we have a one-shot animation?
	if( (pxAnimation != NULL) &&
		(pxAnimation->GetPriority() == g_uSecondaryAnimationPriority) )
	{
		Asura_Animation*	pxParentAnimation	= reinterpret_cast<Asura_Animation*>(pAnimation);

		pxParentAnimation->DestroyController(uHash);
	}

	return(true);
}

/// End of function 'Asura_Animation_PrimaryWrapper::DestroyOneShotAnimation_Traverse'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::RemoveAllOneShotAnims
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::RemoveAllOneShotAnims (void)
{
	// Remove all secondary animations...
	m_pxAnimation->TraverseControllerAnimations(DestroyOneShotAnimation_Traverse);
}

/// End of function 'Asura_Animation_PrimaryWrapper::RemoveAllOneShotAnims'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetLooped
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetLooped (const bool bLooped,
												const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetLooped(bLooped);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetLooped'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetLooped
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetLooped (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(false);
	}
	else
	{
		return(pxAnimation->IsLooped());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetLooped'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetPaused
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetPaused (const bool bPaused,
												const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else if(bPaused != pxAnimation->IsPaused())
	{
		if(bPaused)
		{
			pxAnimation->Pause();
		}
		else
		{
			pxAnimation->Play();
		}
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetPaused'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetPaused
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetPaused (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(false);
	}
	else
	{
		return(pxAnimation->IsPaused());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetPaused'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetMirrored
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetMirrored (const bool bMirrored,
												  const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetMirrored(bMirrored);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetMirrored'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetMirrored
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetMirrored (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(false);
	}
	else
	{
		return(pxAnimation->IsMirrored());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetMirrored'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetAnimDuration
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetAnimDuration (const float fDuration,
													  const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetDuration(fDuration);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetAnimDuration'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetAnimDuration
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

float Asura_Animation_PrimaryWrapper::GetAnimDuration (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(0.0f);
	}
	else
	{
		return(pxAnimation->GetDuration());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetAnimDuration'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetTimer
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetTimer (const float fTimer,
											   const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetParametricTimer(fTimer);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetTimer'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetTimer
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

float Asura_Animation_PrimaryWrapper::GetTimer (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(0.0f);
	}
	else
	{
		return(pxAnimation->GetParametricTimer());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetTimer'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetEndTime
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetEndTime (const float fEndTime,
												 const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetParametricEndTime(fEndTime);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetEndTime'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetEndTime
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

float Asura_Animation_PrimaryWrapper::GetEndTime (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(0.0f);
	}
	else
	{
		return(pxAnimation->GetParametricEndTime());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetEndTime'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetTimeDelay
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetTimeDelay (const float fTimeDelay,
												 const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetTimeDelay(fTimeDelay);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetTimeDelay'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetTimeDelay
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

float Asura_Animation_PrimaryWrapper::GetTimeDelay (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(0.0f);
	}
	else
	{
		return(pxAnimation->GetTimeDelay());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetTimeDelay'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::HasFinished
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::HasFinished (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(true);
	}
	else
	{
		return(pxAnimation->IsFinished());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::HasFinished'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetAnimDurationBySpeed
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetAnimDurationBySpeed (const float fSpeed,
															 const Asura_Handle iHandle)
{
	Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
	}
	else
	{
		pxAnimation->SetDurationFromSpeed(m_pxAnimation->GetSkin(),fSpeed);
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetAnimDurationBySpeed'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::SetTweenDuration
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Animation_PrimaryWrapper::SetTweenDuration (const float fTweenDuration,
													   const Asura_Handle iHandle)
{
	Asura_Assert(false, "Not yet implemented.");	// ARTTODO - Tween the primary animations.
}

/// End of function 'Asura_Animation_PrimaryWrapper::SetTweenDuration'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetAngularVelocity
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetAngularVelocity (Asura_Vector_3* pxOutputAxis,
														 Asura_Angle* pfOutputAngle) const
{
	return(m_pxAnimation->GetAngularVelocity(pxOutputAxis, pfOutputAngle));
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetAngularVelocity'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetMovementOffset
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetMovementOffset (Asura_Vector_3* pxOutputPos,
														Asura_Quat* pxOutputQuat) const
{
	return(m_pxAnimation->GetMovementOffset(pxOutputPos, pxOutputQuat));
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetMovementOffset'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetVelocity
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Animation_PrimaryWrapper::GetVelocity (Asura_Vector_3* pxOutput) const
{
	return(m_pxAnimation->GetVelocity(pxOutput));
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetVelocity'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetPrimaryAnimHashID
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Hash_ID Asura_Animation_PrimaryWrapper::GetPrimaryAnimHashID (void) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= m_pxAnimation->GetControllerAnimationFromHash(m_uPrimaryControllerHash);

	// Return the hash-ID...
	return((pxAnimation == NULL) ? ASURA_HASH_ID_UNSET : pxAnimation->GetAnimationHash());
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetPrimaryAnimHashID'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetFlagsForLastFrame
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

int Asura_Animation_PrimaryWrapper::GetFlagsForLastFrame (const Asura_Handle iHandle) const
{
	const Asura_AnimationController_Animation*	pxAnimation	= GetAnimationFromHandle(iHandle);

	if(pxAnimation == NULL)
	{
		Asura_Assert(false, "Cannot find animation to match specified handle.");
		return(true);
	}
	else
	{
		return(pxAnimation->GetFlagsForLastFrame());
	}
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetFlagsForLastFrame'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Animation_PrimaryWrapper::GetFlagsForAllAnimsLastFrame
// Author       : Andy Tate
// Date         : 19-Sep-2006
////////////////////////////////////////////////////////////////////////////////

int Asura_Animation_PrimaryWrapper::GetFlagsForAllAnimsLastFrame (void) const
{
	return(m_pxAnimation->GetFlagsForAllAnimsLastFrame());
}

/// End of function 'Asura_Animation_PrimaryWrapper::GetFlagsForAllAnimsLastFrame'. ///


/// End of file. ///
