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.
1977 lines
49 KiB
C++
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 ¤t_state, int &transition_state,
|
|
bool &cued_current, Scalar ¤t_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));
|
|
}
|
|
|