Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1977 lines
49 KiB
C++

//===========================================================================//
// 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));
}