|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// INCLUDES
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// singular
|
|
|
|
#include "plAGAnimInstance.h"
|
|
|
|
|
|
|
|
// local
|
|
|
|
#include "plAGAnim.h"
|
|
|
|
#include "plAGModifier.h"
|
|
|
|
#include "plAGMasterMod.h"
|
|
|
|
|
|
|
|
// global
|
|
|
|
#include "hsTimer.h" // just when debugging for GetSysSeconds
|
|
|
|
|
|
|
|
// other
|
|
|
|
#include "pnNetCommon/plSDLTypes.h"
|
|
|
|
#include "plMessage/plAnimCmdMsg.h"
|
|
|
|
#include "plMessage/plOneShotCallbacks.h"
|
|
|
|
#include "plModifier/plSDLModifier.h"
|
|
|
|
#include "plSDL/plSDL.h"
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// FLAGS
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// enable this to show blend trees before and after attaches and detaches
|
|
|
|
// #define SHOW_AG_CHANGES
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// STATIC
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef TRACK_AG_ALLOCS
|
|
|
|
extern const char *gGlobalAnimName = nil;
|
|
|
|
extern const char *gGlobalChannelName = nil;
|
|
|
|
#endif // TRACK_AG_ALLOCS
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// plAGAnimInstance
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// ctor -------------------------------------------------------------------
|
|
|
|
// -----
|
|
|
|
plAGAnimInstance::plAGAnimInstance(plAGAnim * anim, plAGMasterMod * master,
|
|
|
|
hsScalar blend, UInt16 blendPriority, hsBool cache,
|
|
|
|
bool useAmplitude)
|
|
|
|
: fAnimation(anim),
|
|
|
|
fMaster(master),
|
|
|
|
fBlend(blend),
|
|
|
|
fAmplitude(useAmplitude ? 1.0f : -1.0f)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
fTimeConvert = nil;
|
|
|
|
plScalarChannel *timeChan = nil;
|
|
|
|
#ifdef TRACK_AG_ALLOCS
|
|
|
|
gGlobalAnimName = anim->GetName(); // for debug tracking...
|
|
|
|
#endif // TRACK_AG_ALLOCS
|
|
|
|
|
|
|
|
plATCAnim *atcAnim = plATCAnim::ConvertNoRef(anim);
|
|
|
|
if (atcAnim)
|
|
|
|
{
|
|
|
|
fTimeConvert = TRACKED_NEW plAnimTimeConvert();
|
|
|
|
fTimeConvert->Init(atcAnim, this, master);
|
|
|
|
timeChan = TRACKED_NEW plATCChannel(fTimeConvert);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
timeChan = TRACKED_NEW plScalarSDLChannel(anim->GetLength());
|
|
|
|
fSDLChannels.push_back((plScalarSDLChannel *)timeChan);
|
|
|
|
}
|
|
|
|
|
|
|
|
int nInChannels = anim->GetChannelCount();
|
|
|
|
|
|
|
|
fCleanupChannels.push_back(timeChan);
|
|
|
|
|
|
|
|
#ifdef SHOW_AG_CHANGES
|
|
|
|
hsStatusMessageF("\nAbout to Attach anim <%s>", GetName());
|
|
|
|
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (i = 0; i < nInChannels; i++)
|
|
|
|
{
|
|
|
|
plAGApplicator * app = fAnimation->GetApplicator(i);
|
|
|
|
plAGChannel * inChannel = app->GetChannel();
|
|
|
|
const char * channelName = app->GetChannelName();
|
|
|
|
plAGModifier * channelMod = master->GetChannelMod(channelName);
|
|
|
|
|
|
|
|
if(channelMod) {
|
|
|
|
#ifdef TRACK_AG_ALLOCS
|
|
|
|
gGlobalChannelName = channelName;
|
|
|
|
#endif // TRACK_AG_ALLOCS
|
|
|
|
|
|
|
|
// we're going to be accumulating a chain of channels.
|
|
|
|
// curChannel will always point to the top one...
|
|
|
|
plAGChannel *topNode = inChannel;
|
|
|
|
|
|
|
|
if(cache)
|
|
|
|
{
|
|
|
|
topNode = topNode->MakeCacheChannel(fTimeConvert);
|
|
|
|
IRegisterDetach(channelName, topNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(useAmplitude)
|
|
|
|
{
|
|
|
|
// amplitude is rarely used and expensive, so only alloc if asked
|
|
|
|
// first build a static copy of the incoming channel...
|
|
|
|
plAGChannel *zeroState = inChannel->MakeZeroState();
|
|
|
|
IRegisterDetach(channelName, zeroState);
|
|
|
|
|
|
|
|
// now make a blend node to blend the anim with its static copy
|
|
|
|
topNode = zeroState->MakeBlend(topNode, &fAmplitude, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a time scaler to localize time for this instance
|
|
|
|
topNode = topNode->MakeTimeScale(timeChan);
|
|
|
|
IRegisterDetach(channelName, topNode);
|
|
|
|
|
|
|
|
channelMod->MergeChannel(app, topNode, &fBlend, this, blendPriority);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hsAssert(false, "Adding an animation with an invalid channel.");
|
|
|
|
}
|
|
|
|
fFadeBlend = fFadeAmp = false;
|
|
|
|
|
|
|
|
#ifdef TRACK_AG_ALLOCS
|
|
|
|
gGlobalAnimName = nil;
|
|
|
|
#endif // TRACK_AG_ALLOCS
|
|
|
|
}
|
|
|
|
|
|
|
|
// dtor -----------------------------
|
|
|
|
// -----
|
|
|
|
plAGAnimInstance::~plAGAnimInstance()
|
|
|
|
{
|
|
|
|
delete fTimeConvert;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SearchForGlobals ---------------------
|
|
|
|
// -----------------
|
|
|
|
void plAGAnimInstance::SearchForGlobals()
|
|
|
|
{
|
|
|
|
const plAgeGlobalAnim *ageAnim = plAgeGlobalAnim::ConvertNoRef(fAnimation);
|
|
|
|
if (ageAnim != nil && fSDLChannels.size() > 0)
|
|
|
|
{
|
|
|
|
extern const plSDLModifier *ExternFindAgeSDL();
|
|
|
|
const plSDLModifier *sdlMod = ExternFindAgeSDL();
|
|
|
|
if (!sdlMod)
|
|
|
|
return;
|
|
|
|
|
|
|
|
plSimpleStateVariable *var = sdlMod->GetStateCache()->FindVar(ageAnim->GetGlobalVarName());
|
|
|
|
if (!var)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sdlMod->AddNotifyForVar(fMaster->GetKey(), ageAnim->GetGlobalVarName(), 0);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < fSDLChannels.size(); i++)
|
|
|
|
fSDLChannels[i]->SetVar(var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plAGAnimInstance::IRegisterDetach(const char *channelName, plAGChannel *channel)
|
|
|
|
{
|
|
|
|
plDetachMap::value_type newPair(channelName, channel);
|
|
|
|
fManualDetachChannels.insert(newPair);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetCurrentTime ---------------------------------------------------------------
|
|
|
|
// ---------------
|
|
|
|
void plAGAnimInstance::SetCurrentTime(hsScalar localT, hsBool jump /* = false */)
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
fTimeConvert->SetCurrentAnimTime(localT, jump);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SeekRelative ------------------------------------
|
|
|
|
// -------------
|
|
|
|
void plAGAnimInstance::SeekRelative (hsScalar delta, hsBool jump)
|
|
|
|
{
|
|
|
|
if(fTimeConvert)
|
|
|
|
{
|
|
|
|
hsScalar now = fTimeConvert->CurrentAnimTime();
|
|
|
|
fTimeConvert->SetCurrentAnimTime (now + delta, jump);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detach ---------------------
|
|
|
|
// -------
|
|
|
|
void plAGAnimInstance::Detach()
|
|
|
|
{
|
|
|
|
fMaster->DetachAnimation(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// DetachChannels ---------------------
|
|
|
|
// ---------------
|
|
|
|
void plAGAnimInstance::DetachChannels()
|
|
|
|
{
|
|
|
|
#ifdef SHOW_AG_CHANGES
|
|
|
|
hsStatusMessageF("\nAbout to DETACH anim <%s>", GetName());
|
|
|
|
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
|
|
|
#endif
|
|
|
|
plDetachMap::iterator i = fManualDetachChannels.begin();
|
|
|
|
|
|
|
|
while(i != fManualDetachChannels.end())
|
|
|
|
{
|
|
|
|
const char *channelName = (*i).first;
|
|
|
|
plAGModifier *channelMod = fMaster->GetChannelMod(channelName, true);
|
|
|
|
|
|
|
|
if(channelMod)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
plAGChannel *channel = (*i).second;
|
|
|
|
channelMod->DetachChannel(channel);
|
|
|
|
} while (++i != fManualDetachChannels.end() && i->first == channelName);
|
|
|
|
} else {
|
|
|
|
do {
|
|
|
|
} while (++i != fManualDetachChannels.end() && i->first == channelName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int cleanCount = fCleanupChannels.size();
|
|
|
|
hsAssert(cleanCount, "No time controls when deleting animation");
|
|
|
|
for (int j = 0; j < cleanCount; j++)
|
|
|
|
{
|
|
|
|
delete fCleanupChannels[j];
|
|
|
|
}
|
|
|
|
fCleanupChannels.clear();
|
|
|
|
|
|
|
|
#ifdef SHOW_AG_CHANGES
|
|
|
|
hsStatusMessageF("\nFinished DETACHING anim <%s>", GetName());
|
|
|
|
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBlend ---------------------------------------
|
|
|
|
// ---------
|
|
|
|
hsScalar plAGAnimInstance::SetBlend(hsScalar blend)
|
|
|
|
{
|
|
|
|
float oldBlend = fBlend.Value(0.0, true);
|
|
|
|
if(oldBlend != blend &&
|
|
|
|
(oldBlend == 0.0f ||
|
|
|
|
blend == 0.0f ||
|
|
|
|
oldBlend == 1.0f ||
|
|
|
|
blend == 1.0f))
|
|
|
|
{
|
|
|
|
fMaster->SetNeedCompile(true);
|
|
|
|
}
|
|
|
|
fBlend.Set(blend);
|
|
|
|
return blend;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlend -------------------------
|
|
|
|
// ---------
|
|
|
|
hsScalar plAGAnimInstance::GetBlend()
|
|
|
|
{
|
|
|
|
return fBlend.Value(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetAmplitude -------------------------------------
|
|
|
|
// -------------
|
|
|
|
hsScalar plAGAnimInstance::SetAmplitude(hsScalar amp)
|
|
|
|
{
|
|
|
|
if(fAmplitude.Get() != -1.0f)
|
|
|
|
{
|
|
|
|
fAmplitude.Set(amp);
|
|
|
|
}
|
|
|
|
return amp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAmplitude -------------------------
|
|
|
|
// -------------
|
|
|
|
hsScalar plAGAnimInstance::GetAmplitude()
|
|
|
|
{
|
|
|
|
return fAmplitude.Value(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetName -----------------------------
|
|
|
|
// --------
|
|
|
|
const char * plAGAnimInstance::GetName()
|
|
|
|
{
|
|
|
|
if(fAnimation)
|
|
|
|
return fAnimation->GetName();
|
|
|
|
else
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLoop ----------------------------------
|
|
|
|
// --------
|
|
|
|
void plAGAnimInstance::SetLoop(hsBool status)
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
fTimeConvert->Loop(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandleCmd ----------------------------------------
|
|
|
|
// ----------
|
|
|
|
hsBool plAGAnimInstance::HandleCmd(plAnimCmdMsg *msg)
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
return fTimeConvert->HandleCmd(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsFinished -----------------------
|
|
|
|
// -----------
|
|
|
|
hsBool plAGAnimInstance::IsFinished()
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
return fTimeConvert->IsStopped();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsAtEnd -----------------------
|
|
|
|
// --------
|
|
|
|
hsBool plAGAnimInstance::IsAtEnd()
|
|
|
|
{
|
|
|
|
if(fTimeConvert)
|
|
|
|
{
|
|
|
|
return fTimeConvert->CurrentAnimTime() == fTimeConvert->GetEnd();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start -----------------------------------
|
|
|
|
// ------
|
|
|
|
void plAGAnimInstance::Start(double timeNow)
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
{
|
|
|
|
if (timeNow < 0)
|
|
|
|
fTimeConvert->Start();
|
|
|
|
else
|
|
|
|
fTimeConvert->Start(timeNow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop ---------------------
|
|
|
|
// -----
|
|
|
|
void plAGAnimInstance::Stop()
|
|
|
|
{
|
|
|
|
if (fTimeConvert)
|
|
|
|
fTimeConvert->Stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// AttachCallbacks --------------------------------------------------
|
|
|
|
// ----------------
|
|
|
|
void plAGAnimInstance::AttachCallbacks(plOneShotCallbacks *callbacks)
|
|
|
|
{
|
|
|
|
const plATCAnim *anim = plATCAnim::ConvertNoRef(fAnimation);
|
|
|
|
if (callbacks && anim)
|
|
|
|
{
|
|
|
|
plAnimCmdMsg animMsg;
|
|
|
|
animMsg.SetCmd(plAnimCmdMsg::kAddCallbacks);
|
|
|
|
|
|
|
|
for (int i = 0; i < callbacks->GetNumCallbacks(); i++)
|
|
|
|
{
|
|
|
|
plOneShotCallbacks::plOneShotCallback& cb = callbacks->GetCallback(i);
|
|
|
|
|
|
|
|
plEventCallbackMsg *eventMsg = TRACKED_NEW plEventCallbackMsg;
|
|
|
|
eventMsg->AddReceiver(cb.fReceiver);
|
|
|
|
eventMsg->fRepeats = 0;
|
|
|
|
eventMsg->fUser = cb.fUser;
|
|
|
|
|
|
|
|
if (cb.fMarker)
|
|
|
|
{
|
|
|
|
float marker = anim->GetMarker(cb.fMarker);
|
|
|
|
hsAssert(marker != -1, "Bad marker name");
|
|
|
|
eventMsg->fEventTime = marker;
|
|
|
|
eventMsg->fEvent = kTime;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eventMsg->fEvent = kStop;
|
|
|
|
}
|
|
|
|
|
|
|
|
animMsg.AddCallback(eventMsg);
|
|
|
|
hsRefCnt_SafeUnRef(eventMsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
fTimeConvert->HandleCmd(&animMsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessFade -------------------------------------
|
|
|
|
// ------------
|
|
|
|
void plAGAnimInstance::ProcessFade(hsScalar elapsed)
|
|
|
|
{
|
|
|
|
if (fFadeBlend) {
|
|
|
|
hsScalar newBlend = ICalcFade(fFadeBlend, GetBlend(), fFadeBlendGoal, fFadeBlendRate, elapsed);
|
|
|
|
SetBlend(newBlend);
|
|
|
|
if(fFadeDetach && (newBlend == fFadeBlendGoal) && (fFadeBlendGoal == 0.0f) )
|
|
|
|
{
|
|
|
|
fMaster->DetachAnimation(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fFadeAmp && fAmplitude.Get() != -1.0f) {
|
|
|
|
hsScalar curAmp = GetAmplitude();
|
|
|
|
hsScalar newAmp = ICalcFade(fFadeAmp, curAmp, fFadeAmpGoal, fFadeAmpRate, elapsed);
|
|
|
|
SetAmplitude(newAmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ICalcFade ---------------------------------------------------------------------
|
|
|
|
// ----------
|
|
|
|
hsScalar plAGAnimInstance::ICalcFade(hsBool &fade, hsScalar curVal, hsScalar goal,
|
|
|
|
hsScalar rate, hsScalar elapsed)
|
|
|
|
{
|
|
|
|
hsScalar newVal;
|
|
|
|
hsScalar curStep = rate * elapsed;
|
|
|
|
if(rate > 0) {
|
|
|
|
newVal = __min(goal, curVal + curStep);
|
|
|
|
} else {
|
|
|
|
newVal = __max(goal, curVal + curStep);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(newVal == goal)
|
|
|
|
{
|
|
|
|
fade = false;
|
|
|
|
fMaster->DirtySynchState(kSDLAGMaster, 0); // send SDL state update to server
|
|
|
|
}
|
|
|
|
return newVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FadeAndDetach -------------------------------------------------
|
|
|
|
// --------------
|
|
|
|
void plAGAnimInstance::FadeAndDetach(hsScalar goal, hsScalar rate)
|
|
|
|
{
|
|
|
|
ISetupFade(goal, rate, true, kFadeBlend);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fade --------------------------------------------------------------------------------
|
|
|
|
// -----
|
|
|
|
void plAGAnimInstance::Fade(hsScalar goal, hsScalar rate, UInt8 type /* = kFadeBlend */)
|
|
|
|
{
|
|
|
|
ISetupFade(goal, rate, false, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ISetupFade --------------------------------------------------------------------------
|
|
|
|
// -----------
|
|
|
|
void plAGAnimInstance::ISetupFade(hsScalar goal, hsScalar rate, bool detach, UInt8 type)
|
|
|
|
{
|
|
|
|
if (rate == 0)
|
|
|
|
{
|
|
|
|
if (type == kFadeBlend)
|
|
|
|
{
|
|
|
|
SetBlend(goal);
|
|
|
|
fFadeBlend = false;
|
|
|
|
if(detach) {
|
|
|
|
fMaster->DetachAnimation(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == kFadeAmp)
|
|
|
|
{
|
|
|
|
SetAmplitude(goal);
|
|
|
|
fFadeAmp = false;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = (rate > 0 ? rate : -rate); // For old code that sends negative values
|
|
|
|
|
|
|
|
hsScalar curVal = 0;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case kFadeBlend:
|
|
|
|
curVal = GetBlend();
|
|
|
|
break;
|
|
|
|
case kFadeAmp:
|
|
|
|
curVal = GetAmplitude();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (curVal > goal)
|
|
|
|
rate = -rate;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case kFadeBlend:
|
|
|
|
fFadeBlend = true;
|
|
|
|
fFadeBlendGoal = goal;
|
|
|
|
fFadeBlendRate = rate;
|
|
|
|
fFadeDetach = detach;
|
|
|
|
break;
|
|
|
|
case kFadeAmp:
|
|
|
|
fFadeAmp = true;
|
|
|
|
fFadeAmpGoal = goal;
|
|
|
|
fFadeAmpRate = rate;
|
|
|
|
fFadeDetach = false; // only detach on blend fades, for the moment.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class agAlloc
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
agAlloc(plAGChannel *object, const char *chanName, const char *animName, UInt16 classIndex)
|
|
|
|
: fObject(object),
|
|
|
|
fClassIndex(classIndex)
|
|
|
|
{
|
|
|
|
fChannelName = hsStrcpy(chanName);
|
|
|
|
fAnimName = hsStrcpy(animName);
|
|
|
|
}
|
|
|
|
|
|
|
|
~agAlloc()
|
|
|
|
{
|
|
|
|
delete[] fChannelName;
|
|
|
|
delete[] fAnimName;
|
|
|
|
}
|
|
|
|
|
|
|
|
plAGChannel *fObject;
|
|
|
|
char *fChannelName;
|
|
|
|
char *fAnimName;
|
|
|
|
UInt16 fClassIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::map<plAGChannel *, agAlloc *> agAllocMap;
|
|
|
|
static agAllocMap gAGAllocs;
|
|
|
|
|
|
|
|
void RegisterAGAlloc(plAGChannel *object, const char *chanName, const char *animName, UInt16 classIndex)
|
|
|
|
{
|
|
|
|
gAGAllocs[object] = TRACKED_NEW agAlloc(object, chanName, animName, classIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DumpAGAllocs()
|
|
|
|
{
|
|
|
|
agAllocMap::iterator i = gAGAllocs.begin();
|
|
|
|
agAllocMap::iterator theEnd = gAGAllocs.end();
|
|
|
|
|
|
|
|
hsStatusMessage("DUMPING AG ALLOCATIONS ================================================");
|
|
|
|
|
|
|
|
for ( ; i != theEnd; i++)
|
|
|
|
{
|
|
|
|
agAlloc * al = (*i).second;
|
|
|
|
|
|
|
|
UInt16 realClassIndex = al->fObject->ClassIndex();
|
|
|
|
|
|
|
|
hsStatusMessageF("agAlloc: an: %s ch: %s, cl: %s", al->fAnimName, al->fChannelName, plFactory::GetNameOfClass(realClassIndex));
|
|
|
|
|
|
|
|
}
|
|
|
|
// it's not fast but it's safe and simple..
|
|
|
|
i = gAGAllocs.begin();
|
|
|
|
while(i != gAGAllocs.end())
|
|
|
|
{
|
|
|
|
agAlloc * al = (*i).second;
|
|
|
|
delete al;
|
|
|
|
|
|
|
|
i = gAGAllocs.erase(i);
|
|
|
|
}
|
|
|
|
hsStatusMessage("FINISHED DUMPING AG ALLOCATIONS *********************************************");
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnRegisterAGAlloc(plAGChannel *object)
|
|
|
|
{
|
|
|
|
agAllocMap::iterator i = gAGAllocs.find(object);
|
|
|
|
if(i != gAGAllocs.end())
|
|
|
|
{
|
|
|
|
agAlloc * al = (*i).second;
|
|
|
|
|
|
|
|
gAGAllocs.erase(i);
|
|
|
|
delete al;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|