//===========================================================================//
// File:	AnimationState.cpp											
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/23/999  JSE  Inital coding
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Microsoft Corp.										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "MW4Headers.hpp"


#include "MWObject.hpp"
#include "AnimationState.hpp"

#include <Adept\GUITextManager.hpp>
#include <Adept\GUITextObject.hpp>

#if 1
#define RUNSTATES_LOGIC(string) LOGIC("Animation::RunAnimStates::" string)
#else
#define RUNSTATES_LOGIC(string)
#endif

using namespace MW4Animation;

DEFINE_TIMER(MechWarrior4, RunAnimStates);
DEFINE_TIMER(MechWarrior4, Iterate);
DEFINE_TIMER(MechWarrior4, Blend);
DEFINE_TIMER(MechWarrior4, Apply);
DEFINE_TIMER(MechWarrior4, BlendAlloc);
DEFINE_TIMER(MechWarrior4, blendDealloc);
DEFINE_TIMER(MechWarrior4, BlendAnimCombine);
DEFINE_TIMER(MechWarrior4, BlendCombine);
DEFINE_TIMER(MechWarrior4, BlendAndApply);

//#############################################################################
//##########################    AnimationStateEngine    ########################
//#############################################################################

HermiteSpline1D 
	AnimCurve::BumpCurveMat,
	AnimCurve::EaseUpSplineCurveMat,
	AnimCurve::CurveUpCurveMat,
	AnimCurve::SpikeUpCurveMat,  
	AnimCurve::BellCurveMat,
	AnimCurve::SpikeCurveMat,
	AnimCurve::LongBumpCurveMat,
	AnimCurve::BumpSpikeCurveMat,
	AnimCurve::SpikeBellCurveMat;


AnimationStateEngine::ClassData*
	AnimationStateEngine::DefaultData = NULL;

const StateEngine::StateEntry
	AnimationStateEngine::StateEntries[]=
{
	STATE_ENTRY(AnimationStateEngine, NoAnimation),
	STATE_ENTRY(AnimationStateEngine, Test1),
	STATE_ENTRY(AnimationStateEngine, Test2),
	STATE_ENTRY(AnimationStateEngine, Test3),
	STATE_ENTRY(AnimationStateEngine, Test4),
	STATE_ENTRY(AnimationStateEngine, Test5),
	STATE_ENTRY(AnimationStateEngine, Test6),
	STATE_ENTRY(AnimationStateEngine, Test7),
	STATE_ENTRY(AnimationStateEngine, Test8)

};



HGOSHEAP
	MechWarrior4::g_AnimScript = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AnimationStateEngine::InitializeClass()
{
	Check_Object(StateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			AnimationStateEngineClassID,
			"AnimationStateEngine",
			StateEngine::DefaultData,
			ELEMENTS(StateEntries),
			StateEntries,
			NULL,
			NULL
		);
	Register_Object(DefaultData);

	AnimCurve::InitializeClass();

#if !defined(NO_TIMERS)
	StatisticFormat("");
	StatisticFormat("MW4 ANIMATION");
	StatisticFormat("=============");
	Initialize_Timer(RunAnimStates, "RunAnimStates");
	Initialize_Timer(Iterate, "Iterate Anims");
	
	Initialize_Timer(BlendAndApply, "BlendAndApply");

	Initialize_Timer(Apply, "Apply Anims");
	Initialize_Timer(BlendAlloc, "Alloc");
	Initialize_Timer(blendDealloc, "DeAlloc");
	
	Initialize_Timer(Blend, "Blend Anims");
	Initialize_Timer(BlendAnimCombine, "   Combine");
	Initialize_Timer(BlendCombine, "   AnimCombine");
#endif

	Verify(!g_AnimScript);
	g_AnimScript = gos_CreateMemoryHeap("Animation-Scripts", 0, g_AnimParentHeap);
	Check_Pointer(g_AnimScript);


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AnimationStateEngine::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Check_Pointer(g_AnimScript);
	gos_DestroyMemoryHeap(g_AnimScript);
	g_AnimScript = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AnimationStateEngine*
	AnimationStateEngine::Make(MWObject *vehicle, const FactoryRequest *request)
{
	Check_Object(request);
	Check_Object(vehicle);
	gos_PushCurrentHeap(g_AnimScript);
	AnimationStateEngine* engine = new AnimationStateEngine(vehicle, DefaultData, request);
	gos_PopCurrentHeap();
	return engine;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AnimationStateEngine::Save(FactoryRequest *request)
{
	Check_Object(this);
	Check_Object(request);
	
	StateEngine::Save(request);


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AnimationStateEngine::Reuse(const FactoryRequest *request)
{
	Check_Object(this);
	Check_Object(request);

	StateEngine::Reuse(request);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AnimationStateEngine::AnimationStateEngine(
	MWObject *vehicle,
	ClassData *class_data,
	const FactoryRequest *request
):
	StateEngine(class_data, request),
	statePlaying(NULL),
	transitionPlaying(NULL),
	expressionsPlaying(NULL),
	animStatesLoaded(NULL),
	transitionsLoaded(NULL),
	expressionsLoaded(NULL),
	newStatePlaying(NULL),
	animInstancesLoaded(NULL)
{
	Check_Pointer(this);
	Check_Object(class_data);
	Check_Object(vehicle);
	Check_Object(request);


	alreadyLoaded = false;

	vehicleParent = vehicle;
	
	iteratorManager = 
		new MW4Animation::AnimHierarchyIteratorManager( 
			(MW4Animation::AnimHierarchyIteratorManager::UserDefinedApplyChannelFunction)MWObject::ApplyChannel, 
			vehicle
		);
	Register_Object(iteratorManager);

	animHolderArray = NULL;
	animCurves = NULL;

	transitionFlag = false;
	quedCurrentState = false;
	quedNewState = false;
	quedTransState = false;
	transitionTo = -1;


	lastCurrentStatePosition = 0.0f;

#if 0
	GUITextManager::Instance->MakeNewDebugTextObject(
		"OldBlend",
		&oldBlendValue,
		GUIDebugText::ScalarType
	);

	GUITextManager::Instance->MakeNewDebugTextObject(
		"TrnsBlend",
		&transBlendValue,
		GUIDebugText::ScalarType
	);

	GUITextManager::Instance->MakeNewDebugTextObject(
		"NewBlend",
		&newBlendValue,
		GUIDebugText::ScalarType
	);
#endif


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

AnimationStateEngine::~AnimationStateEngine()
{


	// delete everything
	Stuff::ChainIteratorOf<AnimationState*> iterator1(&animStatesLoaded);
	AnimationState *state;

	while ((state = iterator1.GetCurrent()) != NULL)
	{
		state->UnloadIterators();
		iterator1.Remove();
		Unregister_Object(state);
		delete state;
	}

	Stuff::ChainIteratorOf<TransitionState*> iterator2(&transitionsLoaded);
	while ((state = iterator2.GetCurrent()) != NULL)
	{
		state->UnloadIterators();
		iterator2.Remove();
		Unregister_Object(state);
		delete state;
	}

	Stuff::ChainIteratorOf<AnimationState*> iterator3(&expressionsLoaded);
	while ((state = iterator3.GetCurrent()) != NULL)
	{
		state->UnloadIterators();
		iterator3.Remove();
		Unregister_Object(state);
		delete state;
	}

	Stuff::Plug *instance;
	Stuff::ChainIteratorOf<MW4Animation::AnimInstance*> iterator4(&animInstancesLoaded);
	while ((instance = iterator4.GetCurrent()) != NULL)
	{
		iterator4.Remove();
		Unregister_Object(instance);
		delete instance;
	}

	if (animHolderArray != NULL)
	{
		for (int i = 0; i < animHoldersCount; ++i)
		{
			Unregister_Pointer(animHolderArray[i]);
			delete animHolderArray[i];
		}
		Unregister_Pointer(animHolderArray);
		delete[] animHolderArray;
	}

	if (animCurves != NULL)
	{
		Unregister_Pointer(animCurves);
		delete[] animCurves;
	}

	Unregister_Object(iteratorManager);
	delete iteratorManager;
	

}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationStateEngine::Reset()
{
		// unload anything that may be running..
	AnimationState *state = statePlaying.GetCurrent();
	if (state != NULL)
	{
		//state->UnloadIterators();
		statePlaying.Remove();
	}

	state = newStatePlaying.GetCurrent();
	if (state != NULL)
	{
		//state->UnloadIterators();
		newStatePlaying.Remove();
	}

	state = transitionPlaying.GetCurrent();
	if (state != NULL)
	{
		//state->UnloadIterators();
		transitionPlaying.Remove();
	}

	Stuff::ChainIteratorOf<AnimationState*> state_iterator(&expressionsPlaying);
	while ((state = state_iterator.GetCurrent()) != NULL)
	{
		//state->UnloadIterators();
		state_iterator.Remove();
	}

	currentState = NoAnimationState;
	transitionFlag = false;
	quedCurrentState = false;
	quedNewState = false;
	quedTransState = false;
	transitionTo = -1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


int AnimationStateEngine::GetTransitionState()
{
	if (!transitionFlag)
		return NoAnimationState;

	return transitionTo;


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar AnimationStateEngine::GetCurrentStatePercentage()
{
	Check_Pointer(statePlaying.GetCurrent());
	return statePlaying.GetCurrent()->GetStatePercentage();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar AnimationStateEngine::GetTranistionStatePercentage()
{
	Check_Pointer(transitionPlaying.GetCurrent());
	return transitionPlaying.GetCurrent()->GetStatePercentage();
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar AnimationStateEngine::GetNewStatePercentage()
{
	Check_Pointer(newStatePlaying.GetCurrent());
	return newStatePlaying.GetCurrent()->GetStatePercentage();
}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool AnimationStateEngine::CurrentStateLoopedThisFrame()
{
	if (statePlaying.GetCurrent() == NULL)
		return true;

	return statePlaying.GetCurrent()->LoopedThisFrame();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AnimationState::AnimationState(AnimationStateEngine *anim_state_engine):
	Plug(DefaultData)
{
	Check_Object(anim_state_engine);
	animStateEngine = anim_state_engine;

	myState = -1;
	startTime = 0.0f;
	elapsedTime = 0.0f;

	animCount = 0;
	firstAnim = 0;

	justLooped = false;

	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

TransitionState::TransitionState(AnimationStateEngine *anim_state_engine):
	AnimationState(anim_state_engine)
{
	transitionToState = -1;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

AnimationState *
	AnimationStateEngine::FindAnimationState(int state_number)
{
	Stuff::ChainIteratorOf<AnimationState*> iterator(&animStatesLoaded);
	AnimationState *anim_state;
	while ((anim_state = iterator.ReadAndNext()) != NULL)
	{
		if (anim_state->myState == state_number)
		{
			return anim_state;
		}
	}

	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

TransitionState *
	AnimationStateEngine::FindTransitionState(int state_number, int trans_state)
{
	Stuff::ChainIteratorOf<TransitionState*> iterator(&transitionsLoaded);
	TransitionState *anim_state = NULL;
	TransitionState *best_match = NULL;
	
	while ((anim_state = iterator.ReadAndNext()) != NULL)
	{
		if (anim_state->myState == state_number && anim_state->transitionToState == trans_state)
		{
			return anim_state;
		}
		else if (anim_state->myState == -1 && anim_state->transitionToState == trans_state)
		{
			//this is the default so mark it but keep searching for the exact match
			best_match = anim_state;
		}
	}

	return best_match;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	AnimationStateEngine::RequestState(
		int new_state,
		bool run_minimal,
		void* data
		)
{
	Check_Object(this);
	Check_Object(GetClassData());
	Verify(new_state < GetClassData()->GetStateCount());

	//SPEW(("jerryeds","%d, request %d",  vehicleParent->GetReplicatorID().localID, new_state));


	if (new_state == currentState)
	{
		return currentState;
	}

	RUNSTATES_LOGIC("RequestState");
	Start_Timer(RunAnimStates);

	// All iterator loading happens in here

	// put the new state on the que...
	if (!transitionFlag)
	{
		transitionFlag = true;
		quedCurrentState = false;
		quedNewState = false;
		quedTransState = false;

		transitionTo = new_state;


		Verify(transitionPlaying.GetCurrent() == NULL);
		Verify(newStatePlaying.GetCurrent() == NULL);


		// state playing keeps playing....
		// load the transition and the new state...
		AnimationState *new_anim_state = FindAnimationState(new_state);

		if (new_anim_state == NULL)
		{
			//SPEW(("jerryeds","   NONE"));

			// Don't bother playing transitions to states we can't get to
			// just switch states and stop playing animations
			transitionFlag = false;
			
			AnimationState *playing_state = statePlaying.GetCurrent();
			if (playing_state != NULL)
			{
				Verify(playing_state->animCount > 0);
				//playing_state->UnloadIterators();
				statePlaying.Remove();
			}
			NewState(transitionTo);
			

			Stop_Timer(RunAnimStates);
			return -1;
		}
		else
		{
			Verify(new_anim_state->animCount > 0);

			#if defined(_ARMOR)
			AnimationState *current_state = statePlaying.GetCurrent();
			#endif

			if (statePlaying.GetCurrent() != NULL)
			{
				//SPEW(("jerryeds","   ADD"));

				Verify(current_state->animCount > 0);

				quedCurrentState = true;
				Check_Object(current_state);
				Verify(newStatePlaying.GetCurrent() == NULL);
				newStatePlaying.Add(new_anim_state);
				//new_anim_state->LoadIterators();
				
				
				TransitionState *trans_state = FindTransitionState(currentState, new_state);
				if (trans_state != NULL)
				{
					Verify(trans_state->animCount > 0);

					Verify(transitionPlaying.GetCurrent() == NULL);
					transitionPlaying.Add(trans_state);
					
					//trans_state->LoadIterators();
				}
				
			}
			else
			{
				//SPEW(("jerryeds","   FIRST"));
				// first pass and nothing is acutally playing on the stack
				transitionFlag = false;
				quedCurrentState = true;

				Verify(statePlaying.GetCurrent() == NULL);
				statePlaying.Add(new_anim_state);

				//new_anim_state->LoadIterators();
				new_anim_state->Que(0.0f, -1.0f, run_minimal);
				
				NewState(transitionTo);
			}
		}
	}

	Stop_Timer(RunAnimStates);
	return -1;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	AnimationStateEngine::GetStates(
		int &current_state, int &transition_state, 
		bool &cued_current, Scalar &current_position, 
		bool &cued_transition, Scalar &transition_position, 
		bool &cued_new, Scalar &new_position)
{
	

	current_state = AnimationStateEngine::NoAnimationState;
	transition_state = AnimationStateEngine::NoAnimationState;
	current_position = 0.0f;
	transition_position = 0.0f;
	new_position = 0.0f;
	cued_current = false;
	cued_transition = false;
	cued_new = false;


	// we should always have a current state
	// but it isn't always qued and playing
	current_state = GetState();


	// If there is a currentstate is playing mark it and it's position
	if (quedCurrentState)
	{
		cued_current = true;
		current_position = GetCurrentStatePercentage();
		Verify(current_state == statePlaying.GetCurrent()->myState);
	}
	else
	{
		cued_current = false;
		current_position = 0.0f;
	}


	// if we are transitioning
	if (transitionFlag)
	{

		// find out the state we are transitioning to
		transition_state = GetTransitionState();


		if (transition_state == current_state)
		{
			current_state = transitionPlaying.GetCurrent()->myState;
		}

		// if the transition is qued mark it and the position
		cued_transition = quedTransState;
		
		// we always need the position of the transition even if the animation isn't qued
		// since we use that also
		transition_position = GetTranistionStatePercentage();

	}
	else
	{
		cued_transition = false;
		transition_state = NoAnimationState;
		transition_position = 0.0f;
	}

	
	// if we have a new state 
	if (quedNewState)
	{
		// mark it as being qued and the position
		cued_new = true;
		new_position = GetNewStatePercentage();
	}
	else
	{
		cued_new = false;
		new_position = 0.0f;
	}

	Verify(current_state < GetClassData()->GetStateCount());
	Verify(transition_state < GetClassData()->GetStateCount());

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


void
	AnimationStateEngine::SetStates(
		int current_state, int transition_state, 
		bool cued_current, Scalar current_position, 
		bool cued_transition, Scalar transition_position, 
		bool cued_new, Scalar new_position,
		bool run_minimal)
{

	// Wow, this routine is a hell of a lot more complicated 
	// than I intended it to be!
	

#ifdef LAB_ONLY
	if(current_state >= GetClassData()->GetStateCount())
	{
		STOP(("CLIENT READING INVALID ANIMATION STATE"));
	}

	if(transition_state >= GetClassData()->GetStateCount())
	{
		STOP(("CLIENT READING INVALID ANIMATION STATE"));
	}
#endif
	
	transitionFlag = false;
	quedCurrentState = false;
	quedNewState = false;
	quedTransState = false;
	transitionTo = -1;



	//------------------------------------------------------------
	// See if our current animation matches the incomming state
	// if it doesn't match or doesn't exist at all
	// find and add the current state
	// this saves lookup and que time when the network 
	// is just echoing states we are already in.
	//------------------------------------------------------------
	
	AnimationState *new_anim_state = statePlaying.GetCurrent();
	if (new_anim_state != NULL)
	{
		if (new_anim_state->myState != current_state)
		{	
			// We have a state but it doesn't match

			statePlaying.Remove();
	
			new_anim_state = FindAnimationState(current_state);
			if (new_anim_state != NULL)
			{
				Check_Object(new_anim_state);

				Verify(statePlaying.GetCurrent() == NULL);
				statePlaying.Add(new_anim_state);
				NewState(current_state);
			}
			else
			{
				// we were givin a state we don't have
				// just set our state
				transitionFlag = false;
				statePlaying.Remove();
				NewState(current_state);
			}
			
		}
	}
	else
	{
		// we don't have any state currently qued
		new_anim_state = FindAnimationState(current_state);
		Check_Object(new_anim_state);

		Verify(statePlaying.GetCurrent() == NULL);
		statePlaying.Add(new_anim_state);
	}



	//------------------------------------------------------------
	//	If the current state is qued, set it's position
	//------------------------------------------------------------
	
	if (cued_current)
	{
		quedCurrentState = true;
	
		new_anim_state->Que(-1.0f, current_position, run_minimal);
		new_anim_state->CalculateStatePercentage();

		

		NewState(current_state);
		lastCurrentStatePosition = current_position;
	}

	
	//------------------------------------------------------------
	//	Que the transition if we have one
	//------------------------------------------------------------
	
		
	if (transition_state != AnimationStateEngine::NoAnimationState)
	{

		TransitionState *trans_new_anim_state = (TransitionState *)transitionPlaying.GetCurrent();
		if (trans_new_anim_state != NULL)
		{
			if ((trans_new_anim_state->myState != current_state) && (trans_new_anim_state->transitionToState != transition_state))
			{
				//------------------------------------------------------------
				//	We have a transition loaded but it doesn't match the request one
				//  so we remove the current one and load the requested one
				//------------------------------------------------------------
				

				transitionPlaying.Remove();
				trans_new_anim_state = FindTransitionState(current_state, transition_state);
				Check_Object(trans_new_anim_state);
				
				Verify(transitionPlaying.GetCurrent() == NULL);
				transitionPlaying.Add(trans_new_anim_state);
			}
		}
		else
		{
			//------------------------------------------------------------
			// We don't have a transition loaded so go ahead and load
			// the requested one
			//------------------------------------------------------------
			
			trans_new_anim_state = FindTransitionState(current_state, transition_state);
			Check_Object(trans_new_anim_state);
			
			Verify(transitionPlaying.GetCurrent() == NULL);
			transitionPlaying.Add(trans_new_anim_state);
		}


		transitionFlag = true;		
		transitionTo = transition_state;

		if (cued_transition)
		{
			//------------------------------------------------------------
			//  If the transition was qued go ahead and set the position 
			//------------------------------------------------------------
			
			quedTransState = true;
			trans_new_anim_state->Que(-1.0f, transition_position, run_minimal);
			trans_new_anim_state->CalculateStatePercentage();
			
		}
		

		AnimationState *new_anim_state = newStatePlaying.GetCurrent();
		if (new_anim_state != NULL)
		{
			if (new_anim_state->myState != transition_state)
			{
				//------------------------------------------------------------
				//	We have a new state loaded but it doesn't match the request one
				//  so we remove the current one and load the requested one
				//------------------------------------------------------------
				
				newStatePlaying.Remove();
				new_anim_state = FindAnimationState(transition_state);
				Check_Object(new_anim_state);

				Verify(newStatePlaying.GetCurrent() == NULL);
				newStatePlaying.Add(new_anim_state);

			}
		}
		else
		{
			//------------------------------------------------------------
			// We don't have a new state loaded so go ahead and load
			// the requested one
			//------------------------------------------------------------
			

			new_anim_state = FindAnimationState(transition_state);
			Check_Object(new_anim_state);

			Verify(newStatePlaying.GetCurrent() == NULL);
			newStatePlaying.Add(new_anim_state);

			
		}
		
		if (cued_new)
		{
			//------------------------------------------------------------
			//  If the new state was qued go ahead and set the position 
			//------------------------------------------------------------
			
			quedNewState = true;
			new_anim_state->Que(-1.0f,new_position, run_minimal);
			new_anim_state->CalculateStatePercentage();
			

		}
		
	}
	else if (transitionPlaying.GetCurrent() != NULL)
	{
		//------------------------------------------------------------
		// We have a transition and one isn't qued so we remove it
		//------------------------------------------------------------
	
		AnimationState *state = transitionPlaying.GetCurrent();
		
		transitionPlaying.Remove();

		state = newStatePlaying.GetCurrent();
		if (state != NULL)
		{
			newStatePlaying.Remove();
		}


	}


}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	AnimationStateEngine::RunStates(Stuff::Scalar time_slice, bool run_minimal)
{
	Check_Object(this);

	iteratorManager->PushLayer(1.0f);

	RUNSTATES_LOGIC("RunStates");
	Start_Timer(RunAnimStates);

	{
		RUNSTATES_LOGIC("RunStates::Iterate");
		Start_Timer(Iterate);

		AnimHierarchyNode *transition_node = NULL;
		AnimHierarchyNode *new_state_node = NULL;
		AnimHierarchyNode *cur_state_node = NULL;

		transBlendValue = 0.0f;
		newBlendValue = 0.0f;
		oldBlendValue = 0.0f;




		bool advance_new_state = true;
		bool advance_current_state = true;


		if (transitionFlag)
		{
			if (transitionPlaying.GetCurrent() == NULL)
			{
				// No transition - pure cut!

				//if there is no transition on the stack than just stop the
				//current state and move the new state over there...

				transitionFlag = false;
				quedCurrentState = true;

				AnimationState *state_playing = statePlaying.GetCurrent();
				Check_Object(state_playing);
				
				Stuff::Scalar old_position = state_playing->GetStatePercentage();
				
				statePlaying.Remove();
				//state_playing->UnloadIterators();
				
				AnimationState *new_state = newStatePlaying.GetCurrent();
				Check_Object(new_state);

				newStatePlaying.Remove();			
				new_state->Que(old_position, -1.0f, run_minimal);
				statePlaying.Add(new_state);

				NewState(transitionTo);

			}

		}


		if (quedTransState)
		{
			transition_node = iteratorManager->PushLayer(1.0f);

			Verify(transitionPlaying.GetCurrent() != NULL);

			//SPEW(("jerryeds", "T : - %f", time_slice));
		
			transitionPlaying.GetCurrent()->Advance(time_slice, 0, run_minimal);
			
			iteratorManager->PopLayer();
			
			transBlendValue = 1.0f;

			TransitionState *trans_state = (TransitionState*)transitionPlaying.GetCurrent();
			Check_Object(trans_state);


			// see if we need to stop the old state
			if(trans_state->GetStatePercentage() >= trans_state->playOldStateTill && quedCurrentState)
			{
				quedCurrentState = false;
			}

			// see if we need to load the new state.
			if(trans_state->GetStatePercentage() >= trans_state->startNewState && !quedNewState)
			{
				quedNewState = true;
				advance_new_state = false;
				
				AnimationState *new_state = newStatePlaying.GetCurrent();
				Check_Object(new_state);

				//SPEW(("jerryeds", "QUE NEW STATE: %d %f", trans_state->myState, trans_state->GetStatePercentage()));
				new_state->Que(trans_state->GetStatePercentage(), trans_state->overrideNewStatePosition, run_minimal);
			}

			// see if we can stop the transition
			if(trans_state->GetStatePercentage() >= 1.0f)
			{
				Verify(quedCurrentState == false);
				Verify(quedNewState == true);

				transitionFlag = false;
				quedCurrentState = true;
				quedTransState = false;
				quedNewState = false;
				advance_current_state = false;
				
				//trans_state->UnloadIterators();
				transitionPlaying.Remove();
				
				//current_state->UnloadIterators();
				statePlaying.Remove();

				AnimationState *new_state = newStatePlaying.GetCurrent();
				Check_Object(new_state);

				newStatePlaying.Remove();
				statePlaying.Add(new_state);
				NewState(transitionTo);
			}
		}







		if (quedCurrentState)
		{
			
			cur_state_node = iteratorManager->PushLayer(1.0f);

			Verify(statePlaying.GetCurrent() != NULL);
			lastCurrentStatePosition = statePlaying.GetCurrent()->GetStatePercentage();

			if (advance_current_state)
			{
				//SPEW(("jerryeds", "C : - %f", time_slice));
				statePlaying.GetCurrent()->Advance(time_slice, 0, run_minimal);
			}
			else
			{
				//SPEW(("jerryeds", "C : - %f", 0.0f));
				statePlaying.GetCurrent()->NoAdvance(0.0f, 0, run_minimal);
			}

			iteratorManager->PopLayer();

			oldBlendValue = 1.0f;

			if (transitionFlag)
			{
	#if defined (_ARMOR)
				AnimationState *new_state = newStatePlaying.GetCurrent();
				Check_Object(new_state);
	#endif
				if(!quedTransState)
				{

					TransitionState *trans_state = (TransitionState*)transitionPlaying.GetCurrent();
					Check_Object(trans_state);

					if (trans_state->transitionStart == TransitionState::StartAnyWhereToken)
					{
						AnimationState *current_state = statePlaying.GetCurrent();
						quedTransState = true;
						trans_state->Que(current_state->GetStatePercentage(), -1.0f, run_minimal);
					}
					else
					{
						AnimationState *current_state = statePlaying.GetCurrent();
						// we are waiting for the old state to get to a specific place
						// so that we can start the transition
						if (lastCurrentStatePosition != -1)
						{
							if(lastCurrentStatePosition <= trans_state->transitionStart 
								&& current_state->GetStatePercentage() >= trans_state->transitionStart)
							{
								// if it passed the trigger location

								//SPEW(("jerryeds", "1- %f:%f", lastCurrentStatePosition, current_state->GetStatePercentage()));

								quedTransState = true;
								trans_state->Que(current_state->GetStatePercentage(), -1.0f, run_minimal);
							}
							else if (lastCurrentStatePosition <= trans_state->transitionStart && current_state->LoopedThisFrame())
							{
								// if it was lower than the trigger spot and then looped
								quedTransState = true;
								trans_state->Que(current_state->GetStatePercentage(), -1.0f, run_minimal);
								
								//SPEW(("jerryeds", "2- %f:%f", lastCurrentStatePosition, current_state->GetStatePercentage()));
							}
							else if (current_state->GetStatePercentage() >= trans_state->transitionStart && current_state->LoopedThisFrame())
							{
								// if it is higher than the trigger location and it looped
								quedTransState = true;
								trans_state->Que(current_state->GetStatePercentage(), -1.0f, run_minimal);
								
								//SPEW(("jerryeds", "3- %f:%f", lastCurrentStatePosition, current_state->GetStatePercentage()));
							}

						}	
					}

					if (quedTransState)
					{

						transition_node = iteratorManager->PushLayer(1.0f);
						Verify(transitionPlaying.GetCurrent() != NULL);

						//SPEW(("jerryeds", "T2 : - %f", 0.0f));

						transitionPlaying.GetCurrent()->Advance(0.0f, 0, run_minimal);				
						iteratorManager->PopLayer();
						transBlendValue = 1.0f;
					}
				}
			}

		}

		if (quedNewState)
		{
			new_state_node = iteratorManager->PushLayer(1.0f);

			Verify(newStatePlaying.GetCurrent() != NULL);

			if (advance_new_state)
			{
				//SPEW(("jerryeds", "N : - %f", time_slice));
				newStatePlaying.GetCurrent()->Advance(time_slice, 0, run_minimal);
			}
			else
			{
				//SPEW(("jerryeds", "N : - %f", 0.0f));
				newStatePlaying.GetCurrent()->NoAdvance(0.0f, 0, run_minimal);
			}

			iteratorManager->PopLayer();

			newBlendValue = 1.0f;
		}

		iteratorManager->PopLayer();

		// set up the curves now
		if (quedTransState)
		{
			TransitionState *trans_state = (TransitionState *)transitionPlaying.GetCurrent();
			Check_Pointer(trans_state);

			if (quedCurrentState)
			{
				//where in the transition are we?
				
				Stuff::Scalar curve_percent;
				if (trans_state->playOldStateTill != 0.0f)
				{
					curve_percent = trans_state->GetStatePercentage() / trans_state->playOldStateTill;
					Clamp(curve_percent, 0.0f, 1.0f);
				}
				else
				{
					curve_percent = 0.0f;
				}

				Check_Pointer(cur_state_node);
				Check_Pointer(transition_node);

				Stuff::Scalar curve_position = animCurves[trans_state->startOverlapCurve].Play(curve_percent);

				cur_state_node->SetBlendValue(1.0f - curve_position);
				transition_node->SetBlendValue(curve_position);
				
				transBlendValue = curve_position;
				oldBlendValue = 1.0f - curve_position;
				newBlendValue = 0.0f;
				
			}
			else if(quedNewState)
			{
				Check_Pointer(new_state_node);
				Check_Pointer(transition_node);
				
				Stuff::Scalar curve_percent;
				if (trans_state->startNewState != 1.0f)
				{
					curve_percent =  (trans_state->GetStatePercentage() - trans_state->startNewState) / (1.0f - trans_state->startNewState);
					Clamp(curve_percent, 0.0f, 1.0f);
				}
				else
				{
					curve_percent = 0.0f;
				}
				
				Stuff::Scalar curve_position = animCurves[trans_state->endOverlapCurve].Play(curve_percent);

				new_state_node->SetBlendValue(1.0f - curve_position);
				transition_node->SetBlendValue(curve_position);


				transBlendValue = curve_position;
				newBlendValue = 1.0f - curve_position;
				oldBlendValue = 0.0f;

			}
		}

		Stop_Timer(Iterate);
	}

	{
	RUNSTATES_LOGIC("RunStates::BlendAndApply");
	iteratorManager->BlendAndApply(vehicleParent->animationArrayCount);
	}



	Stop_Timer(RunAnimStates);




}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::Advance(Stuff::Scalar time_slice, int depth_count, bool run_minimal)
{
	// play the internal state
	
	if (time_slice <= 0.0f)
	{
		return;
	}

	elapsedTime += time_slice;

	if (depth_count == 0)
	{
		justLooped = false;
	}
	else if (depth_count > 4)
	{
		CalculateStatePercentage();
		return;
	}


	bool any_playing = false;
	Scalar min_carryover = 99999999.0f;

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if not in a chain or the current animation in a chain
		if (anim_holder->currentStateFlag == AnimHolder::NowPlaying)
		{
			
			if (anim_holder->Advance(animStateEngine, time_slice, run_minimal))
			{
				// one of the anims just ended...
				Scalar local_carryover = anim_holder->GetCarryOver();

				// look for the closest one to the edge
				if (local_carryover < min_carryover)
				{
					min_carryover = local_carryover;
				}

				anim_holder->currentStateFlag = AnimHolder::DonePlaying;
			}
			else
			{
				any_playing = true;
			}
		}
		else if (anim_holder->currentStateFlag == AnimHolder::BeforePlaying)
		{
			if (anim_holder->waitForAnim != AnimHolder::NoStartAfterToken)
			{
				// check to see if this guy is ready to go...
				AnimHolder *wait_on_holder = animStateEngine->animHolderArray[anim_holder->waitForAnim + firstAnim];
				Check_Pointer(wait_on_holder);

				if (wait_on_holder->currentStateFlag == AnimHolder::DonePlaying)
				{
					anim_holder->currentStateFlag = AnimHolder::NowPlaying;
					anim_holder->Que(0.0f, run_minimal);
					if (anim_holder->Advance(animStateEngine, wait_on_holder->GetCarryOver(), run_minimal))
					{
						// one of the anims just ended...
						Scalar local_carryover = anim_holder->GetCarryOver();

						// look for the closest one to the edge
						if (local_carryover < min_carryover)
						{
							min_carryover = local_carryover;
						}

						anim_holder->currentStateFlag = AnimHolder::DonePlaying;
					}
					else
					{
						any_playing = true;
					}
				}				
			}
		}
	}


	if (!any_playing)
	{
		// reset we are done
		Que(0.0f, -1.0f, run_minimal);
		Verify(min_carryover != 99999999.0f);

		if (carryOver)
		{
			Advance(min_carryover, depth_count + 1, run_minimal);
		}

		justLooped = true;
	}

	CalculateStatePercentage();
}





//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::NoAdvance(Stuff::Scalar time_slice, int depth_count, bool run_minimal)
{
	// play the internal state
	
	
	if (depth_count == 0)
	{
		justLooped = false;
	}
	


	bool any_playing = false;
	Scalar min_carryover = 99999999.0f;

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if not in a chain or the current animation in a chain
		if (anim_holder->currentStateFlag == AnimHolder::NowPlaying)
		{
			
			if (anim_holder->Advance(animStateEngine, time_slice, run_minimal))
			{
				// one of the anims just ended...
				Scalar local_carryover = anim_holder->GetCarryOver();

				// look for the closest one to the edge
				if (local_carryover < min_carryover)
				{
					min_carryover = local_carryover;
				}

				anim_holder->currentStateFlag = AnimHolder::DonePlaying;
			}
			else
			{
				any_playing = true;
			}
		}
		else if (anim_holder->currentStateFlag == AnimHolder::BeforePlaying)
		{
			if (anim_holder->waitForAnim != AnimHolder::NoStartAfterToken)
			{
				// check to see if this guy is ready to go...
				AnimHolder *wait_on_holder = animStateEngine->animHolderArray[anim_holder->waitForAnim + firstAnim];
				Check_Pointer(wait_on_holder);

				if (wait_on_holder->currentStateFlag == AnimHolder::DonePlaying)
				{
					anim_holder->currentStateFlag = AnimHolder::NowPlaying;
					anim_holder->Que(0.0f, run_minimal);
					if (anim_holder->Advance(animStateEngine, wait_on_holder->GetCarryOver(), run_minimal))
					{
						// one of the anims just ended...
						Scalar local_carryover = anim_holder->GetCarryOver();

						// look for the closest one to the edge
						if (local_carryover < min_carryover)
						{
							min_carryover = local_carryover;
						}

						anim_holder->currentStateFlag = AnimHolder::DonePlaying;
					}
					else
					{
						any_playing = true;
					}
				}				
			}
		}
	}

	if (!any_playing)
	{
		// reset we are done
		Que(0.0f, -1.0f, run_minimal);
	}

	CalculateStatePercentage();
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void TransitionState::Advance(Stuff::Scalar time_slice, int depth_count, bool run_minimal)
{

	elapsedTime += time_slice;

	// play the internal state
	
	// we transition and that is IT
	Verify (depth_count == 0);

	Scalar min_carryover = 99999999.0f;

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if not in a chain or the current animation in a chain
		if (anim_holder->currentStateFlag == AnimHolder::NowPlaying)
		{
			
			if (anim_holder->Advance(animStateEngine, time_slice, run_minimal))
			{
				//SPEWALWAYS(("jerryeds","TRANS DONE - NO QUE!!!!"));
				// one of the anims just ended...
				Scalar local_carryover = anim_holder->GetCarryOver();

				// look for the closest one to the edge
				if (local_carryover < min_carryover)
				{
					min_carryover = local_carryover;
				}

				anim_holder->currentStateFlag = AnimHolder::DonePlaying;
			}
		}
		if (anim_holder->currentStateFlag == AnimHolder::BeforePlaying)
		{
			if (anim_holder->waitForAnim != AnimHolder::NoStartAfterToken)
			{
				// check to see if this guy is ready to go...
				AnimHolder *wait_on_holder = animStateEngine->animHolderArray[anim_holder->waitForAnim + firstAnim];
				Check_Pointer(wait_on_holder);

				if (wait_on_holder->currentStateFlag == AnimHolder::DonePlaying)
				{
					anim_holder->currentStateFlag = AnimHolder::NowPlaying;
					anim_holder->Que(0.0f, run_minimal);
					if (anim_holder->Advance(animStateEngine, wait_on_holder->GetCarryOver(), run_minimal))
					{
						// one of the anims just ended...
						Scalar local_carryover = anim_holder->GetCarryOver();

						// look for the closest one to the edge
						if (local_carryover < min_carryover)
						{
							min_carryover = local_carryover;
						}

						anim_holder->currentStateFlag = AnimHolder::DonePlaying;
					}
				}				
			}
		}
	}

	CalculateStatePercentage();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::CalculateStatePercentage(void)
{
	// complications - THIS IS NOT EASY PAY ATTENTION
	// 
	// First rule - Anim with the most time left right now sets the percentage
	//
	// Second rule - animation Delays are handled internaly to the animation 
	//				 so no consideration is made for that
	//
	// third rule - animations that are chained are treated as one animation
	//			    but they do so internaly, and all should return the 
	//				same percantage of completion
	//
	// forth rule - we project time to completion by a simple deadreckon
	//				time_left = percent_left_to_play * (percent_played / delta_time)

	Scalar max_time_left = 0.0f;
	Scalar max_timed_percentage = 0.0f;

	Scalar delta_time = static_cast<Scalar>(elapsedTime - startTime);

	if (Close_Enough(delta_time, 0.0f))
	{
		statePercentage = 0.0f;
		return;
	}

	Verify(delta_time != 0.0f);
	

	bool all_done = true;

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if not in a chain or the current animation in a chain
		if (anim_holder->currentStateFlag == AnimHolder::NowPlaying)
		{
			Scalar current_pos = anim_holder->GetCurrentPercentage();
			Verify(current_pos <= 1.0f);
			Verify(current_pos >= 0.0f);

			// don't realy have to do the subtraction
			// but for debuging it helps to see actual time
			// left
			
			// if not it is zero anyway and we are in the same boat!
			if (current_pos != 0.0f)
			{
				Scalar time_left = (delta_time/current_pos) - delta_time;
				if (time_left >= max_time_left)
				{
					max_timed_percentage = current_pos;
					max_time_left = time_left;
				}
			}
			all_done = false;
		}

	}

	if (all_done)
	{
		statePercentage = 1.0f;
		return;
	}


	statePercentage = max_timed_percentage;

}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::Que(Stuff::Scalar old_state_position, Stuff::Scalar over_ride_position, bool run_minimal)
{
	// this is 0.0f
	//startTime = gos_GetElapsedTime();

	#if defined(_ARMOR)
	bool verify_qued_animation = false;
	#endif


	justLooped = false;

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if we are not in a chain or are the first node in the chain
		// go ahead and start the animation

		Scalar set_position = -1;

		if (over_ride_position != -1)
		{
			set_position = over_ride_position;
		}

		//else if (old_state_position != -1)
		//{
			//set_position = old_state_position;
		//}
	


		if (set_position != -1)
		{
			if (set_position >= anim_holder->startPercentage &&  set_position <= (anim_holder->percentageOfChain + anim_holder->startPercentage))
			{
				// que this bad boy up
				anim_holder->currentStateFlag = AnimHolder::NowPlaying;

				#if defined(_ARMOR)
				verify_qued_animation = true;
				#endif


				// scale the position accordingly 
				set_position = (set_position - anim_holder->startPercentage)/anim_holder->percentageOfChain;

				anim_holder->Que(set_position, run_minimal);
				elapsedTime = anim_holder->currentTime;
				CalculateStatePercentage();
			}
			else
			{
				anim_holder->currentStateFlag = AnimHolder::BeforePlaying;
			}
		}
		else
		{
			if (anim_holder->waitForAnim == AnimHolder::NoStartAfterToken)
			{
				#if defined(_ARMOR)
				verify_qued_animation = true;
				#endif

				anim_holder->currentStateFlag = AnimHolder::NowPlaying;
				anim_holder->Que(set_position, run_minimal);
				elapsedTime = anim_holder->currentTime;
				CalculateStatePercentage();
			}
			else
			{
				anim_holder->currentStateFlag = AnimHolder::BeforePlaying;
			}
		}

	}

	Verify(verify_qued_animation);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::LoadIterators(bool run_minimal)
{

	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);

		// if we are not in a chain or are the first node in the chain
		// go ahead and start the animation

		anim_holder->LoadIterators(run_minimal);
	}

	statePercentage = 0.0f;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void AnimationState::UnloadIterators(void)
{
	// shut em down...
	
	for (int i = 0; i < animCount; ++i)
	{
		AnimHolder *anim_holder = animStateEngine->animHolderArray[i+firstAnim];
		Check_Pointer(anim_holder);
		//if (anim_holder->inAnimIteratorManager)
		//{
		//	anim_holder->Stop(animStateEngine);
		//}
		anim_holder->UnloadIterators();
	}

	statePercentage = -1.0f;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//



void HermiteSpline1D::Init(
			Stuff::Scalar start_point, 
			Stuff::Scalar out_tan, 
			Stuff::Scalar in_tan, 
			Stuff::Scalar stop_point
		)
{
	
	point1 = start_point;
	tangent1 = out_tan;
	tangent2 = in_tan;
	point2 = stop_point;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

Stuff::Scalar 
	HermiteSpline1D::Evaluate(Stuff::Scalar time_of_curve)
{
	Verify(time_of_curve <= 1.0f);
	Verify(time_of_curve >= 0.0f);

	Stuff::Scalar time_squared = time_of_curve * time_of_curve;
	Stuff::Scalar time_cubed = time_of_curve * time_of_curve * time_of_curve;
	

	Stuff::Scalar h1 = 2*time_cubed - 3*time_squared + 1;
	Stuff::Scalar h2 = -2*time_cubed + 3*time_squared;
	Stuff::Scalar h3 = time_cubed - 2 * time_squared + time_of_curve;
	Stuff::Scalar h4 = time_cubed - time_squared;

	return h1*point1 + h2*point2 + h3 * tangent1 + h4 * tangent2;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//



void AnimCurve::InitializeClass(void)
{
	BumpCurveMat.Init(			0.0f, 4.0f, -4.0f,  0.0f);
	EaseUpSplineCurveMat.Init(	0.0f, 0.0f,  0.0f,  1.0f);
	CurveUpCurveMat.Init(		0.0f, 0.0f,  2.0f,  1.0f);
	SpikeUpCurveMat.Init(		0.0f, 0.8f,  4.5f,  1.0f); 
	BellCurveMat.Init(			0.0f,-0.25f, 0.0f,  1.0f);
	SpikeCurveMat.Init(			0.0f, 0.0f,  3.0f,  1.0f);
	LongBumpCurveMat.Init(		0.0f, 3.2f,  0.0f,  1.0f);
	BumpSpikeCurveMat.Init(		0.0f, 2.0f,  1.0f,  1.0f);
	SpikeBellCurveMat.Init(		0.0f, 0.0f,  1.0f,  1.0f);
}


Stuff::Scalar AnimCurve::Play(Stuff::Scalar percent_of_curve)
{
	Verify(percent_of_curve >= 0.0f && percent_of_curve <= 1.0f);
	Verify(curveType >= 0 && curveType < CurveTypeCount);
	Verify(curveMin >= 0.0f && curveMin <= 1.0f);
	Verify(curveMax >= 0.0f && curveMax <= 1.0f);
	Verify(timeStart >= 0.0f && timeStart <= 1.0f);
	Verify(timeEnd >= 0.0f && timeEnd <= 1.0f);
	
	Stuff::Scalar curve_value = 0.0f;



	if (percent_of_curve < timeStart)
	{
		percent_of_curve = 0.0f;
	}
	else if (percent_of_curve > timeEnd)
	{
		percent_of_curve = 1.0f;
	}
	else
	{
		Verify(timeEnd - timeStart > 0.0f);
		Scalar position = percent_of_curve - timeStart;
		percent_of_curve = position / timeEnd - timeStart;
	}


	if (invertTime)
	{
		percent_of_curve = 1.0f - percent_of_curve;
	}

	switch(curveType)
	{
		case LinearUpCurveType:
			curve_value = percent_of_curve;
			break;

		case CubedCurveType:
			curve_value = percent_of_curve * percent_of_curve * percent_of_curve;
			break;

		case EaseUpCurveType:
			curve_value = 
				(-2.0f*percent_of_curve*percent_of_curve*percent_of_curve) + 
				(3.0f*percent_of_curve*percent_of_curve);
			break;

		case EdgeCurveType:
			curve_value =  1.0f-(Scalar)fabs((percent_of_curve-0.5f)*2.0f);
			break;

		case BumpCurveType:
			curve_value = BumpCurveMat.Evaluate(percent_of_curve);
			break;
		case EaseUpSplineCurveType:
			curve_value = EaseUpSplineCurveMat.Evaluate(percent_of_curve);
			break;
		case CurveUpCurveType:
			curve_value = CurveUpCurveMat.Evaluate(percent_of_curve);
			break;
		case SpikeUpCurveType:
			curve_value = SpikeUpCurveMat.Evaluate(percent_of_curve);
			break;

		case BellCurveType:
			{
				if(percent_of_curve >= 0.5f)
				{
					Stuff::Scalar reversed_double_spline;
					reversed_double_spline = 1.0f-((percent_of_curve - 0.5f)*2.0f);
					curve_value = BellCurveMat.Evaluate( reversed_double_spline);
				}
				else
				{
					Stuff::Scalar double_spline = percent_of_curve * 2.0f;
					curve_value = BellCurveMat.Evaluate(double_spline);
				}
			}
			break;
		case SpikeCurveType:
			{
				if(percent_of_curve >= 0.5f)
				{
					Stuff::Scalar reversed_double_spline;
					reversed_double_spline = 1.0f-((percent_of_curve - 0.5f)*2.0f);
					curve_value = SpikeCurveMat.Evaluate( reversed_double_spline);
				}
				else
				{
					Stuff::Scalar double_spline = percent_of_curve * 2.0f;
					curve_value = SpikeCurveMat.Evaluate(double_spline);
				}
			}
			break;
		case LongBumpCurveType:
			{
				if(percent_of_curve >= 0.5f)
				{
					Stuff::Scalar reversed_double_spline;
					reversed_double_spline = 1.0f-((percent_of_curve - 0.5f)*2.0f);
					curve_value = LongBumpCurveMat.Evaluate( reversed_double_spline);
				}
				else
				{
					Stuff::Scalar double_spline = percent_of_curve * 2.0f;
					curve_value = LongBumpCurveMat.Evaluate(double_spline);
				}
			}
			break;
		case BumpSpikeCurveType:
			{
				if(percent_of_curve >= 0.5f)
				{
					Stuff::Scalar reversed_double_spline;
					reversed_double_spline = 1.0f-((percent_of_curve - 0.5f)*2.0f);
					curve_value = BumpSpikeCurveMat.Evaluate( reversed_double_spline);
				}
				else
				{
					Stuff::Scalar double_spline = percent_of_curve * 2.0f;
					curve_value = BumpSpikeCurveMat.Evaluate(double_spline);
				}
			}
			break;
		case SpikeBellCurveType:
			{
				if(percent_of_curve >= 0.5f)
				{
					Stuff::Scalar reversed_double_spline;
					reversed_double_spline = 1.0f-((percent_of_curve - 0.5f)*2.0f);
					curve_value = SpikeBellCurveMat.Evaluate( reversed_double_spline);
				}
				else
				{
					Stuff::Scalar double_spline = percent_of_curve * 2.0f;
					curve_value = SpikeBellCurveMat.Evaluate(double_spline);
				}
			}
			break;

		default:
			STOP(("AnimCurve::Play : BAD CURVE TYPE!"));
			break;
		
	}

	
	Scalar spread = curveMax - curveMin;

	curve_value *= spread;
	curve_value += curveMin;


	if (invertScale)
	{
		curve_value = 1.0f - curve_value;
	}
	return curve_value;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	AnimationStateEngine::TestClass()
{
	Verify(IsDerivedFrom(DefaultData));
}

