You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
796 lines
22 KiB
796 lines
22 KiB
/*==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==*/ |
|
#include "plAvCallbackAction.h" // must be first: references havok new |
|
|
|
// singular |
|
#include "plAnimStage.h" |
|
|
|
// local |
|
#include "plAvatarMgr.h" |
|
#include "plAGAnim.h" |
|
#include "plArmatureMod.h" |
|
#include "plAGAnimInstance.h" |
|
#include "plMatrixChannel.h" |
|
#include "plAvBrainGeneric.h" |
|
#include "plMultiStageBehMod.h" |
|
|
|
// global |
|
#include "hsUtils.h" |
|
#include "hsStlUtils.h" |
|
#include "hsResMgr.h" |
|
#include "hsTimer.h" |
|
|
|
#include <cstdio> |
|
|
|
// other |
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "plMessage/plSimStateMsg.h" |
|
#include "plStatusLog/plStatusLog.h" |
|
#include "pnMessage/plNotifyMsg.h" |
|
#include "plPipeline/plDebugText.h" |
|
|
|
#ifdef DEBUG_MULTISTAGE |
|
#include "plAvatarMgr.h" |
|
#include "plStatusLog/plStatusLog.h" |
|
#endif |
|
|
|
|
|
class plAGAnim; |
|
|
|
// PLANIMSTAGE default ctor |
|
plAnimStage::plAnimStage() |
|
: fAnimName(nil), |
|
fNotify(0), |
|
fArmature(nil), |
|
fBrain(nil), |
|
fForwardType(kForwardNone), |
|
fBackType(kBackNone), |
|
fAdvanceType(kAdvanceNone), |
|
fRegressType(kRegressNone), |
|
fLoops(0), |
|
fAnimInstance(nil), |
|
fLocalTime(0.0f), |
|
fLength(0.0f), |
|
fCurLoop(0), |
|
fAttached(false), |
|
fDoAdvanceTo(false), |
|
fAdvanceTo(0), |
|
fDoRegressTo(false), |
|
fRegressTo(0), |
|
fMod(nil), |
|
fSentNotifies(0), |
|
fReverseOnIdle(false), |
|
fDone(false) |
|
{ |
|
} |
|
|
|
plAnimStage::plAnimStage(const char *animName, UInt8 notify) |
|
: fNotify(notify), |
|
fArmature(nil), |
|
fBrain(nil), |
|
fForwardType(kForwardAuto), // different from default |
|
fBackType(kBackNone), |
|
fAdvanceType(kAdvanceAuto), // different from default |
|
fRegressType(kRegressNone), |
|
fLoops(0), |
|
fAnimInstance(nil), |
|
fLocalTime(0.0f), |
|
fLength(0.0f), |
|
fCurLoop(0), |
|
fAttached(false), |
|
fDoAdvanceTo(false), |
|
fAdvanceTo(0), |
|
fDoRegressTo(false), |
|
fRegressTo(0), |
|
fMod(nil), |
|
fSentNotifies(0), |
|
fReverseOnIdle(false), |
|
fDone(false) |
|
{ |
|
fAnimName = hsStrcpy(animName); |
|
} |
|
|
|
|
|
// PLANIMSTAGE canonical ctor |
|
plAnimStage::plAnimStage(const char *animName, |
|
UInt8 notify, |
|
ForwardType forward, |
|
BackType back, |
|
AdvanceType advance, |
|
RegressType regress, |
|
int loops) |
|
: fArmature(nil), |
|
fBrain(nil), |
|
fNotify(notify), |
|
fForwardType(forward), |
|
fBackType(back), |
|
fAdvanceType(advance), |
|
fRegressType(regress), |
|
fLoops(loops), |
|
fAnimInstance(nil), |
|
fLocalTime(0.0f), |
|
fLength(0.0f), |
|
fCurLoop(0), |
|
fAttached(false), |
|
fDoAdvanceTo(false), |
|
fAdvanceTo(0), |
|
fDoRegressTo(false), |
|
fRegressTo(0), |
|
fMod(nil), |
|
fSentNotifies(0), |
|
fReverseOnIdle(false), |
|
fDone(false) |
|
{ |
|
fAnimName = hsStrcpy(animName); |
|
} |
|
|
|
plAnimStage::plAnimStage(const char *animName, |
|
UInt8 notify, |
|
ForwardType forward, |
|
BackType back, |
|
AdvanceType advance, |
|
RegressType regress, |
|
int loops, |
|
bool doAdvanceTo, |
|
int advanceTo, |
|
bool doRegressTo, |
|
int regressTo) |
|
: fArmature(nil), |
|
fBrain(nil), |
|
fNotify(notify), |
|
fForwardType(forward), |
|
fBackType(back), |
|
fAdvanceType(advance), |
|
fRegressType(regress), |
|
fLoops(loops), |
|
fAnimInstance(nil), |
|
fLocalTime(0.0f), |
|
fLength(0.0f), |
|
fCurLoop(0), |
|
fAttached(false), |
|
fDoAdvanceTo(doAdvanceTo), |
|
fAdvanceTo(advanceTo), |
|
fDoRegressTo(doRegressTo), |
|
fRegressTo(regressTo), |
|
fMod(nil), |
|
fSentNotifies(0), |
|
fReverseOnIdle(false), |
|
fDone(false) |
|
{ |
|
fAnimName = hsStrcpy(animName); |
|
} |
|
|
|
// PLANIMSTAGE dtor |
|
plAnimStage::~plAnimStage() |
|
{ |
|
if(fAnimName) |
|
delete[] fAnimName; |
|
|
|
hsAssert(fAnimInstance == nil, "plAnimStage still has anim instance during destruction. (that's bad.)"); |
|
// we could delete the animation instance here, but it should have been deleted already... |
|
// *** check back in a while.... |
|
} |
|
|
|
// operator= ---------------------------------------------------- |
|
// ---------- |
|
const plAnimStage& plAnimStage::operator=(const plAnimStage& src) |
|
{ |
|
fAnimName = hsStrcpy(src.fAnimName); |
|
fNotify = src.fNotify; |
|
fForwardType = src.fForwardType; |
|
fBackType = src.fBackType; |
|
fAdvanceType = src.fAdvanceType; |
|
fRegressType = src.fRegressType; |
|
fLoops = src.fLoops; |
|
fDoAdvanceTo = src.fDoAdvanceTo; |
|
fAdvanceTo = src.fAdvanceTo; |
|
fDoRegressTo = src.fDoRegressTo; |
|
fRegressTo = src.fRegressTo; |
|
fMod = src.fMod; |
|
|
|
fAnimInstance = nil; |
|
fLocalTime = 0.0f; |
|
fLength = 0.0f; |
|
fCurLoop = 0; |
|
fAttached = false; |
|
|
|
fReverseOnIdle = src.fReverseOnIdle; |
|
|
|
return *this; |
|
} |
|
|
|
// attach -------------------------------------------------------------------------------------------------------- |
|
// ------- |
|
plAGAnimInstance * plAnimStage::Attach(plArmatureMod *armature, plArmatureBrain *brain, float initialBlend, double time) |
|
{ |
|
// NOTE: you need to be able to detach an animstage and then re-attach it and have |
|
// it wind up in exactly the same state it was in before - for loading and saving. |
|
fBrain = brain; |
|
fSentNotifies = 0; |
|
fArmature = armature; |
|
|
|
if(fAnimInstance) |
|
{ |
|
fAnimInstance->SetBlend(initialBlend); |
|
} else { |
|
plAGAnim *anim = armature->FindCustomAnim(fAnimName); |
|
|
|
if(anim) |
|
{ |
|
fLength = anim->GetEnd(); |
|
fAnimInstance = armature->AttachAnimationBlended(anim, initialBlend); |
|
fAnimInstance->SetCurrentTime(fLocalTime); |
|
#ifdef DEBUG_MULTISTAGE |
|
char sbuf[256]; |
|
sprintf(sbuf,"AnimStage::Attach - attaching stage %s",fAnimName); |
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf); |
|
#endif |
|
} else { |
|
char buf[256]; |
|
sprintf(buf, "Can't find animation <%s> for animation stage. Anything could happen.", fAnimName); |
|
hsAssert(false, buf); |
|
#ifdef DEBUG_MULTISTAGE |
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(buf); |
|
#endif |
|
} |
|
} |
|
|
|
if(fAnimInstance) |
|
{ |
|
fAnimInstance->Stop(); // we'll be setting the time directly. |
|
fAnimatedHandle = (fAnimInstance->GetAnimation()->GetChannel("Handle") != nil); |
|
fAttached = true; |
|
// this is too early to send the enter notify. we're attached, but we may not |
|
// have faded in yet. |
|
// XXX ISendNotify(kNotifyEnter, proEventData::kEnterStage, armature, brain); |
|
} |
|
|
|
return fAnimInstance; |
|
} |
|
|
|
// SENDNOTIFY |
|
hsBool plAnimStage::ISendNotify(UInt32 notifyMask, UInt32 notifyType, plArmatureMod *armature, plArmatureBrain *brain) |
|
{ |
|
// make sure the user has requested this type of notify |
|
if(fNotify & notifyMask) |
|
{ |
|
plKey avKey = armature->GetTarget(0)->GetKey(); |
|
if (fMod) |
|
avKey = fMod->GetKey(); |
|
plNotifyMsg *msg = TRACKED_NEW plNotifyMsg(); |
|
msg->SetSender(avKey); |
|
|
|
if (fMod) |
|
{ |
|
msg->SetBCastFlag(plMessage::kNetPropagate, fMod->NetProp()); |
|
msg->SetBCastFlag(plMessage::kNetForce, fMod->NetForce()); |
|
} |
|
else |
|
{ |
|
msg->SetBCastFlag(plMessage::kNetPropagate, false); |
|
msg->SetBCastFlag(plMessage::kNetForce, false); |
|
} |
|
|
|
plAvBrainGeneric *genBrain = plAvBrainGeneric::ConvertNoRef(brain); |
|
int stageNum = genBrain ? genBrain->GetStageNum(this) : -1; |
|
msg->AddMultiStageEvent(stageNum, notifyType, armature->GetTarget(0)->GetKey()); |
|
|
|
if (! genBrain->RelayNotifyMsg(msg) ) |
|
{ |
|
msg->UnRef(); // couldn't send; destroy... |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// DETACH |
|
hsBool plAnimStage::Detach(plArmatureMod *armature) |
|
{ |
|
|
|
hsBool result = false; |
|
|
|
#ifdef DEBUG_MULTISTAGE |
|
char sbuf[256]; |
|
sprintf(sbuf,"AnimStage::Detach - detaching stage %s",fAnimName); |
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf); |
|
#endif |
|
// hsStatusMessageF("Detaching plAnimStage <%s>", fAnimName); |
|
if(fArmature) { |
|
fArmature = nil; |
|
|
|
if(fAnimInstance) { |
|
armature->DetachAnimation(fAnimInstance); // detach instantly |
|
fAnimInstance = nil; |
|
result = true; |
|
} |
|
#ifdef DEBUG_MULTISTAGE |
|
} else { |
|
char sbuf[256]; |
|
sprintf(sbuf,"AnimStage::Detach: stage already detached"); |
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf); |
|
#endif |
|
// hsStatusMessageF("Detach: stage already detached."); |
|
} |
|
|
|
fBrain = nil; |
|
fAttached = false; |
|
return result; |
|
} |
|
|
|
void plAnimStage::Reset(double time, plArmatureMod *avMod, bool atStart) |
|
{ |
|
if(atStart) |
|
SetLocalTime(0.0f, true); |
|
else |
|
SetLocalTime(fLength, true); |
|
avMod->GetRootAnimator()->Reset(time); |
|
} |
|
|
|
void plAnimStage::ResetAtTime(double globalTime, float localTime, plArmatureMod *avMod) |
|
{ |
|
SetLocalTime(localTime, true); |
|
avMod->GetRootAnimator()->Reset(globalTime); |
|
} |
|
|
|
|
|
// MoveRelative ------------------------------ |
|
// ------------- |
|
// A true result means that the stage is done. |
|
bool plAnimStage::MoveRelative(double time, float delta, float &overage, plArmatureMod *avMod) |
|
{ |
|
bool result; // true means the stage is done |
|
|
|
if(fLocalTime == 0.0f && delta >= 0.0f && !hsCheckBits(fSentNotifies, kNotifyEnter)) |
|
{ |
|
// we send the "enter" notify if we're at the start and either moving forward |
|
// or standing still. |
|
ISendNotify(kNotifyEnter, proEventData::kEnterStage, avMod, fBrain); |
|
hsSetBits(fSentNotifies, kNotifyEnter); |
|
} |
|
|
|
// aborting... |
|
if( fAdvanceType == kAdvanceOnMove && (avMod->HasMovementFlag() || avMod->ExitModeKeyDown())) |
|
{ // special case: advance when any key is pressed, regardless of position in stage. |
|
ISendNotify(kNotifyAdvance, proEventData::kAdvanceNextStage, avMod, fBrain); |
|
result = true; |
|
} else { |
|
if(delta == 0.0f) |
|
{ |
|
return false; |
|
} |
|
else |
|
if(delta < 0.0f) |
|
result = IMoveBackward(time, delta, overage, avMod); |
|
else |
|
result = IMoveForward(time, delta, overage, avMod); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
// IMoveBackward ------------------------------------------------------------------------------ |
|
// -------------- |
|
bool plAnimStage::IMoveBackward(double time, float delta, float &overrun, plArmatureMod *avMod) |
|
{ |
|
if (fLocalTime <= 0 && fRegressType == kRegressNone) |
|
{ |
|
// If we're at the beginning, but not allowed to regress, we don't want to keep processing |
|
// (and firing triggers). |
|
return false; |
|
} |
|
|
|
float target = fLocalTime + delta; |
|
bool infiniteLoop = fLoops == -1; |
|
bool loopsRemain = fCurLoop > 0 || infiniteLoop; |
|
|
|
// This must be here before we set the local time. |
|
if (fAnimInstance->GetTimeConvert()) |
|
fAnimInstance->GetTimeConvert()->Backwards(); |
|
|
|
if(target < 0) |
|
{ |
|
SetLocalTime(0); // animation to beginning |
|
avMod->GetRootAGMod()->Apply(time); // move avatar to beginning |
|
if(loopsRemain) |
|
{ |
|
// If a callback is on the last frame, it'll get triggered twice. Once for setting |
|
// the anim at the end, and once when we play again. So we don't fire callbacks here. |
|
SetLocalTime(fLength, true); // animation wraps to end |
|
|
|
avMod->GetRootAnimator()->Reset(time); // reset the root animator at the end |
|
fCurLoop = infiniteLoop ? 0 : fCurLoop - 1; |
|
target = fLength - (fmodf(-target, fLength)); // modularize negative number to discard |
|
// extra loops (only one allowed) |
|
} else { |
|
// overrun = target + fLength; |
|
// now we want to make sure that overrun goes negative when appropriate, rather than modularizing |
|
overrun = target; |
|
fDone = true; |
|
return ITryRegress(avMod); |
|
} |
|
} |
|
|
|
overrun = 0.0f; |
|
fLocalTime = target; |
|
|
|
fAnimInstance->SetCurrentTime(fLocalTime); |
|
return false; // not done |
|
} |
|
|
|
|
|
// IMoveForward ------------------------------------------------------------------------------ |
|
// ------------- |
|
// It's currently not supported to advance the animation by more than its length in one frame. |
|
// It wouldn't be too hard to add, but it clutters things up and it hasn't been shown to |
|
// be necessary. |
|
bool plAnimStage::IMoveForward(double time, float delta, float &overrun, plArmatureMod *avMod) |
|
{ |
|
if (fLocalTime >= fLength && fAdvanceType == kAdvanceNone) |
|
{ |
|
// If we're at the end, but not allowed to advance, we don't want to keep processing |
|
// (and firing triggers). |
|
return false; |
|
} |
|
|
|
// first get the target time in local time, ignoring overruns |
|
float target = fLocalTime + delta; |
|
|
|
if (fAnimInstance->GetTimeConvert()) |
|
fAnimInstance->GetTimeConvert()->Forewards(); |
|
|
|
|
|
if (target > fLength) |
|
{ |
|
// we're going to the end for sure, so do that first |
|
SetLocalTime(fLength); |
|
// we're going to swap in a new animation before the next eval, so force |
|
// an apply of this one to make sure the avatar gets the necessary movement. |
|
// we only apply on the root node to get the movement -- no need to animate |
|
// the fingers as they'll be overwritten when the next animation is swapped in. |
|
avMod->GetRootAGMod()->Apply(time); |
|
|
|
// are there *any* loops to be had? |
|
bool loopsRemain = fCurLoop < fLoops || fLoops == -1; |
|
if(loopsRemain) |
|
{ |
|
SetLocalTime(0.0f, true); // animation back to beginning |
|
avMod->GetRootAnimator()->Reset(time); // reset the root animator's frame cache |
|
fCurLoop++; |
|
target = fmodf(target, fLength); // discard extra loops (only one at a time allowed) |
|
// target -= fLength; |
|
} else { |
|
overrun = target - fLength; |
|
fDone = true; |
|
return ITryAdvance(avMod); |
|
} |
|
} |
|
|
|
overrun = 0.0f; |
|
fLocalTime = target; |
|
|
|
avMod->GetRootAGMod()->Apply(time); |
|
fAnimInstance->SetCurrentTime(fLocalTime); |
|
return false; // not done |
|
} |
|
|
|
bool plAnimStage::ITryAdvance(plArmatureMod *avMod) |
|
{ |
|
bool stageDone = false; |
|
|
|
|
|
// hsStatusMessageF("Sending advance message for stage <%s>\n", fAnimName); |
|
if(fAdvanceType == kAdvanceAuto || fAdvanceType == kAdvanceOnMove) { |
|
stageDone = true; |
|
} |
|
|
|
if(!hsCheckBits(fSentNotifies, kNotifyAdvance)) |
|
{ |
|
// we send the advance message at the point where we *would* advance, whether |
|
// or not we actually do. this is misleading but better suited to actual current usage. |
|
// we may want to rename this to "ReachedStageEnd" |
|
ISendNotify(kNotifyAdvance, proEventData::kAdvanceNextStage, avMod, fBrain); |
|
hsSetBits(fSentNotifies, kNotifyAdvance); |
|
} |
|
|
|
return stageDone; |
|
} |
|
|
|
|
|
bool plAnimStage::ITryRegress(plArmatureMod *avMod) |
|
{ |
|
bool stageDone = false; |
|
|
|
// we send the advance message at the point where we *would* advance, whether |
|
// or not we actually do. this is misleading but better suited to actual current usage. |
|
// we may want to rename this to "ReachedStageEnd" |
|
ISendNotify(kNotifyRegress, proEventData::kRegressPrevStage, avMod, fBrain); |
|
|
|
// hsStatusMessageF("Sending regress message for stage <%s>\n", fAnimName); |
|
if(fRegressType == kRegressAuto) { |
|
stageDone = true; |
|
} |
|
return stageDone; |
|
} |
|
|
|
|
|
// GETANIMNAME |
|
const char * plAnimStage::GetAnimName() |
|
{ |
|
return fAnimName; |
|
} |
|
|
|
// GETFORWARDTYPE |
|
plAnimStage::ForwardType plAnimStage::GetForwardType() |
|
{ |
|
return fForwardType; |
|
} |
|
|
|
// SETFORWARDTYPE |
|
void plAnimStage::SetForwardType(ForwardType t) |
|
{ |
|
fForwardType = t; |
|
} |
|
|
|
// GETBACKTYPE |
|
plAnimStage::BackType plAnimStage::GetBackType() |
|
{ |
|
return fBackType; |
|
} |
|
|
|
// SETBACKTYPE |
|
void plAnimStage::SetBackType(BackType t) |
|
{ |
|
fBackType = t; |
|
} |
|
|
|
// GETADVANCETYPE |
|
plAnimStage::AdvanceType plAnimStage::GetAdvanceType() |
|
{ |
|
return fAdvanceType; |
|
} |
|
|
|
// SETADVANCETYPE |
|
void plAnimStage::SetAdvanceType(AdvanceType t) |
|
{ |
|
fAdvanceType = t; |
|
} |
|
|
|
// GETREGRESSTYPE |
|
plAnimStage::RegressType plAnimStage::GetRegressType() |
|
{ |
|
return fRegressType; |
|
} |
|
|
|
// SETREGRESSTYPE |
|
void plAnimStage::SetRegresstype(RegressType t) |
|
{ |
|
fRegressType = t; |
|
} |
|
|
|
// GETNOTIFYFLAGS |
|
UInt32 plAnimStage::GetNotifyFlags() |
|
{ |
|
return fNotify; |
|
} |
|
|
|
// SETNOTIFYFLAGS |
|
void plAnimStage::SetNotifyFlags(UInt32 newFlags) |
|
{ |
|
fNotify = (UInt8)newFlags; |
|
} |
|
|
|
// GETNUMLOOPS |
|
int plAnimStage::GetNumLoops() |
|
{ |
|
return fLoops; |
|
} |
|
|
|
// SETNUMLOOPS |
|
void plAnimStage::SetNumLoops(int loops) |
|
{ |
|
// I'm very suspicious of this if statement... |
|
// 1. It's preceded by an assert whose condition is the opposite the error message |
|
// (which I've now commented out) |
|
// 2. It only matters if the avatar is currently in the stage. |
|
// 3. It doesn't seem intuitive that if I'm currently on loop 3 and you |
|
// change the number of loops to 6, that I should jump to the end. |
|
// BUT... |
|
// It's been like this for ages, so I'm not touching it until a break shows a problem. |
|
// |
|
//hsAssert(loops < fCurLoop, "Setting loopcount below current loop"); |
|
if(loops >= fCurLoop) { |
|
fCurLoop = loops; |
|
} |
|
fLoops = loops; |
|
} |
|
|
|
// GETLOOPVALUE |
|
int plAnimStage::GetLoopValue() |
|
{ |
|
return fCurLoop; |
|
} |
|
|
|
// SETLOOPVALUE |
|
void plAnimStage::SetLoopValue(int value) |
|
{ |
|
fCurLoop = value; |
|
} |
|
|
|
// GETLOCALTIME |
|
float plAnimStage::GetLocalTime() |
|
{ |
|
return fLocalTime; |
|
} |
|
|
|
// SETLOCALTIME |
|
void plAnimStage::SetLocalTime(float time, hsBool noCallbacks /* = false */) |
|
{ |
|
fLocalTime = time; |
|
if(fAnimInstance) |
|
fAnimInstance->SetCurrentTime(time, noCallbacks); |
|
} |
|
|
|
// GETLENGTH |
|
float plAnimStage::GetLength() |
|
{ |
|
return fLength; |
|
} |
|
|
|
// GETISATTACHED |
|
bool plAnimStage::GetIsAttached() |
|
{ |
|
return fAttached; |
|
} |
|
|
|
// SETISATTACHED |
|
void plAnimStage::SetIsAttached(bool status) |
|
{ |
|
fAttached = status; |
|
} |
|
|
|
// GETNEXTSTAGE |
|
int plAnimStage::GetNextStage(int curStage) |
|
{ |
|
if(fDoAdvanceTo) |
|
{ |
|
return fAdvanceTo; |
|
} else { |
|
return curStage + 1; |
|
} |
|
} |
|
|
|
// GETPREVSTAGE |
|
int plAnimStage::GetPrevStage(int curStage) |
|
{ |
|
if(fDoRegressTo) |
|
{ |
|
return fRegressTo; |
|
} else { |
|
return curStage - 1; |
|
} |
|
} |
|
|
|
// DUMPDEBUG |
|
void plAnimStage::DumpDebug(bool active, int &x, int &y, int lineHeight, char *strBuf, plDebugText &debugTxt) |
|
{ |
|
std::string str; |
|
|
|
str += fAnimName; |
|
str += " "; |
|
|
|
if(fLoops) { |
|
sprintf(strBuf, "loop(%d/%d)", fCurLoop, fLoops); |
|
str += strBuf; |
|
} |
|
|
|
sprintf(strBuf, "time: (%f/%f)", fLocalTime, fLength); |
|
str += strBuf; |
|
|
|
if(active) |
|
debugTxt.DrawString(x, y, str.c_str(), 0, 255, 0); |
|
else if(fAnimInstance) |
|
debugTxt.DrawString(x, y, str.c_str()); |
|
else |
|
debugTxt.DrawString(x, y, str.c_str(), 255, 255, 0); |
|
|
|
y += lineHeight; |
|
} |
|
|
|
// READ |
|
void plAnimStage::Read(hsStream *stream, hsResMgr *mgr) |
|
{ |
|
delete [] fAnimName; |
|
fAnimName = stream->ReadSafeString(); |
|
fNotify = stream->ReadByte(); |
|
fForwardType = (ForwardType)stream->ReadLE32(); |
|
fBackType = (BackType)stream->ReadLE32(); |
|
fAdvanceType = (AdvanceType)stream->ReadLE32(); |
|
fRegressType = (RegressType)stream->ReadLE32(); |
|
fLoops = stream->ReadLE32(); |
|
|
|
fDoAdvanceTo = stream->Readbool(); |
|
fAdvanceTo = stream->ReadLE32(); |
|
fDoRegressTo = stream->Readbool(); |
|
fRegressTo = stream->ReadLE32(); |
|
} |
|
|
|
void plAnimStage::Write(hsStream *stream, hsResMgr *mgr) |
|
{ |
|
stream->WriteSafeString(fAnimName); |
|
stream->WriteByte(fNotify); |
|
stream->WriteLE32(fForwardType); |
|
stream->WriteLE32(fBackType); |
|
stream->WriteLE32(fAdvanceType); |
|
stream->WriteLE32(fRegressType); |
|
stream->WriteLE32(fLoops); |
|
|
|
stream->Writebool(fDoAdvanceTo); |
|
stream->WriteLE32(fAdvanceTo); |
|
stream->Writebool(fDoRegressTo); |
|
stream->WriteLE32(fRegressTo); |
|
} |
|
|
|
|
|
// SAVEAUX |
|
void plAnimStage::SaveAux(hsStream *stream, hsResMgr *mgr) |
|
{ |
|
stream->WriteLEScalar(fLocalTime); |
|
stream->WriteLEScalar(fLength); |
|
stream->WriteLE32(fCurLoop); |
|
stream->Writebool(fAttached); |
|
// no ephemeral stage at the moment |
|
} |
|
|
|
// LOADAUX |
|
void plAnimStage::LoadAux(hsStream *stream, hsResMgr *mgr, double time) |
|
{ |
|
fLocalTime = stream->ReadLEScalar(); |
|
fLength = stream->ReadLEScalar(); |
|
fCurLoop = stream->ReadLE32(); |
|
// This should actually be Readbool (lowercase), but I won't fix it since that |
|
// would require a version change |
|
fAttached = (stream->Readbool() != 0); |
|
} |
|
|
|
|