mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
anim-clip -- sequence selection by afx effects
This commit is contained in:
parent
8c65467697
commit
ab88b8f489
|
|
@ -20,6 +20,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||
// Copyright (C) 2015 Faust Logic, Inc.
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "T3D/aiPlayer.h"
|
||||
|
||||
|
|
@ -97,6 +102,9 @@ AIPlayer::AIPlayer()
|
|||
mMoveSlowdown = true;
|
||||
mMoveState = ModeStop;
|
||||
|
||||
// This new member saves the movement state of the AI so that
|
||||
// it can be restored after a substituted animation is finished.
|
||||
mMoveState_saved = -1;
|
||||
mAimObject = 0;
|
||||
mAimLocationSet = false;
|
||||
mTargetInLOS = false;
|
||||
|
|
@ -547,23 +555,27 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
|||
mMoveState = ModeMove;
|
||||
}
|
||||
|
||||
if (mMoveStuckTestCountdown > 0)
|
||||
--mMoveStuckTestCountdown;
|
||||
else
|
||||
{
|
||||
// We should check to see if we are stuck...
|
||||
F32 locationDelta = (location - mLastLocation).len();
|
||||
// Don't check for ai stuckness if animation during
|
||||
// an anim-clip effect override.
|
||||
if (mDamageState == Enabled && !(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked()) {
|
||||
if (mMoveStuckTestCountdown > 0)
|
||||
--mMoveStuckTestCountdown;
|
||||
else
|
||||
{
|
||||
// We should check to see if we are stuck...
|
||||
F32 locationDelta = (location - mLastLocation).len();
|
||||
if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled)
|
||||
{
|
||||
// If we are slowing down, then it's likely that our location delta will be less than
|
||||
// our move stuck tolerance. Because we can be both slowing and stuck
|
||||
// we should TRY to check if we've moved. This could use better detection.
|
||||
if ( mMoveState != ModeSlowing || locationDelta == 0 )
|
||||
{
|
||||
mMoveState = ModeStuck;
|
||||
onStuck();
|
||||
}
|
||||
}
|
||||
{
|
||||
mMoveState = ModeStuck;
|
||||
onStuck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -626,6 +638,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
|||
}
|
||||
#endif // TORQUE_NAVIGATION_ENABLED
|
||||
|
||||
if (!(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked())
|
||||
mLastLocation = location;
|
||||
|
||||
return true;
|
||||
|
|
@ -1415,6 +1428,47 @@ DefineEngineMethod( AIPlayer, clearMoveTriggers, void, ( ),,
|
|||
object->clearMoveTriggers();
|
||||
}
|
||||
|
||||
// These changes coordinate with anim-clip mods to parent class, Player.
|
||||
|
||||
// New method, restartMove(), restores the AIPlayer to its normal move-state
|
||||
// following animation overrides from AFX. The tag argument is used to match
|
||||
// the latest override and prevents interruption of overlapping animation
|
||||
// overrides. See related anim-clip changes in Player.[h,cc].
|
||||
void AIPlayer::restartMove(U32 tag)
|
||||
{
|
||||
if (tag != 0 && tag == last_anim_tag)
|
||||
{
|
||||
if (mMoveState_saved != -1)
|
||||
{
|
||||
mMoveState = (MoveState) mMoveState_saved;
|
||||
mMoveState_saved = -1;
|
||||
}
|
||||
|
||||
bool is_death_anim = ((anim_clip_flags & IS_DEATH_ANIM) != 0);
|
||||
|
||||
last_anim_tag = 0;
|
||||
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||
|
||||
if (mDamageState != Enabled)
|
||||
{
|
||||
if (!is_death_anim)
|
||||
{
|
||||
// this is a bit hardwired and desperate,
|
||||
// but if he's dead he needs to look like it.
|
||||
setActionThread("death10", false, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New method, saveMoveState(), stores the current movement state
|
||||
// so that it can be restored when restartMove() is called.
|
||||
void AIPlayer::saveMoveState()
|
||||
{
|
||||
if (mMoveState_saved == -1)
|
||||
mMoveState_saved = (S32) mMoveState;
|
||||
}
|
||||
|
||||
F32 AIPlayer::getTargetDistance(GameBase* target, bool _checkEnabled)
|
||||
{
|
||||
if (!isServerObject()) return false;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||
// Copyright (C) 2015 Faust Logic, Inc.
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
#ifndef _AIPLAYER_H_
|
||||
#define _AIPLAYER_H_
|
||||
|
||||
|
|
@ -225,6 +230,18 @@ public:
|
|||
|
||||
/// @}
|
||||
#endif // TORQUE_NAVIGATION_ENABLED
|
||||
// New method, restartMove(), restores the AIPlayer to its normal move-state
|
||||
// following animation overrides from AFX. The tag argument is used to match
|
||||
// the latest override and prevents interruption of overlapping animation
|
||||
// overrides.
|
||||
// New method, saveMoveState(), stores the current movement state
|
||||
// so that it can be restored when restartMove() is called.
|
||||
// See related anim-clip changes in Player.[h,cc].
|
||||
private:
|
||||
S32 mMoveState_saved;
|
||||
public:
|
||||
void restartMove(U32 tag);
|
||||
void saveMoveState();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2746,7 +2746,12 @@ void Player::updateMove(const Move* move)
|
|||
// Desired move direction & speed
|
||||
VectorF moveVec;
|
||||
F32 moveSpeed;
|
||||
if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled)
|
||||
// If BLOCK_USER_CONTROL is set in anim_clip_flags, the user won't be able to
|
||||
// resume control over the player character. This generally happens for
|
||||
// short periods of time synchronized with script driven animation at places
|
||||
// where it makes sense that user motion is prohibited, such as when the
|
||||
// player is lifted off the ground or knocked down.
|
||||
if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled && !isAnimationLocked())
|
||||
{
|
||||
zRot.getColumn(0,&moveVec);
|
||||
moveVec *= (move->x * (mPose == SprintPose ? mDataBlock->sprintStrafeScale : 1.0f));
|
||||
|
|
@ -3031,7 +3036,9 @@ void Player::updateMove(const Move* move)
|
|||
mContactTimer++;
|
||||
|
||||
// Acceleration from Jumping
|
||||
if (move->trigger[sJumpTrigger] && canJump())// !isMounted() &&
|
||||
// While BLOCK_USER_CONTROL is set in anim_clip_flags, the user won't be able to
|
||||
// make the player character jump.
|
||||
if (move->trigger[sJumpTrigger] && canJump() && !isAnimationLocked())
|
||||
{
|
||||
// Scale the jump impulse base on maxJumpSpeed
|
||||
F32 zSpeedScale = mVelocity.z;
|
||||
|
|
@ -3539,6 +3546,8 @@ void Player::updateLookAnimation(F32 dt)
|
|||
|
||||
bool Player::inDeathAnim()
|
||||
{
|
||||
if ((anim_clip_flags & ANIM_OVERRIDDEN) != 0 && (anim_clip_flags & IS_DEATH_ANIM) == 0)
|
||||
return false;
|
||||
if (mActionAnimation.thread && mActionAnimation.action >= 0)
|
||||
if (mActionAnimation.action < mDataBlock->actionCount)
|
||||
return mDataBlock->actionList[mActionAnimation.action].death;
|
||||
|
|
@ -3748,6 +3757,8 @@ bool Player::setArmThread(U32 action)
|
|||
|
||||
bool Player::setActionThread(const char* sequence,bool hold,bool wait,bool fsp)
|
||||
{
|
||||
if (anim_clip_flags & ANIM_OVERRIDDEN)
|
||||
return false;
|
||||
for (U32 i = 1; i < mDataBlock->actionCount; i++)
|
||||
{
|
||||
PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
|
||||
|
|
@ -3947,8 +3958,10 @@ void Player::updateActionThread()
|
|||
pickActionAnimation();
|
||||
}
|
||||
|
||||
// prevent scaling of AFX picked actions
|
||||
if ( (mActionAnimation.action != PlayerData::LandAnim) &&
|
||||
(mActionAnimation.action != PlayerData::NullAnimation) )
|
||||
(mActionAnimation.action != PlayerData::NullAnimation) &&
|
||||
!(anim_clip_flags & ANIM_OVERRIDDEN))
|
||||
{
|
||||
// Update action animation time scale to match ground velocity
|
||||
PlayerData::ActionAnimation &anim =
|
||||
|
|
@ -4566,6 +4579,10 @@ void Player::updateAnimation(F32 dt)
|
|||
if (mImageStateThread)
|
||||
mShapeInstance->advanceTime(dt,mImageStateThread);
|
||||
|
||||
// update any active blend clips
|
||||
if (isGhost())
|
||||
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||
mShapeInstance->advanceTime(dt, blend_clips[i].thread);
|
||||
// If we are the client's player on this machine, then we need
|
||||
// to make sure the transforms are up to date as they are used
|
||||
// to setup the camera.
|
||||
|
|
@ -4579,6 +4596,11 @@ void Player::updateAnimation(F32 dt)
|
|||
else
|
||||
{
|
||||
updateAnimationTree(false);
|
||||
// This addition forces recently visible players to animate their
|
||||
// skeleton now rather than in pre-render so that constrained effects
|
||||
// get up-to-date node transforms.
|
||||
if (didRenderLastRender())
|
||||
mShapeInstance->animate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7249,6 +7271,165 @@ void Player::afx_unpackUpdate(NetConnection* con, BitStream* stream)
|
|||
mark_fx_c_triggers = mask;
|
||||
}
|
||||
}
|
||||
|
||||
// Code for overriding player's animation with sequences selected by the
|
||||
// anim-clip component effect.
|
||||
|
||||
void Player::restoreAnimation(U32 tag)
|
||||
{
|
||||
// check if this is a blended clip
|
||||
if ((tag & BLENDED_CLIP) != 0)
|
||||
{
|
||||
restoreBlendAnimation(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag != 0 && tag == last_anim_tag)
|
||||
{
|
||||
bool is_death_anim = ((anim_clip_flags & IS_DEATH_ANIM) != 0);
|
||||
|
||||
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||
|
||||
if (isClientObject())
|
||||
{
|
||||
if (mDamageState != Enabled)
|
||||
{
|
||||
if (!is_death_anim)
|
||||
{
|
||||
// this is a bit hardwired and desperate,
|
||||
// but if he's dead he needs to look like it.
|
||||
setActionThread("death10", false, false, false);
|
||||
}
|
||||
}
|
||||
else if (mState != MoveState)
|
||||
{
|
||||
// not sure what happens here
|
||||
}
|
||||
else
|
||||
{
|
||||
pickActionAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
last_anim_tag = 0;
|
||||
last_anim_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
U32 Player::getAnimationID(const char* name)
|
||||
{
|
||||
for (U32 i = 0; i < mDataBlock->actionCount; i++)
|
||||
{
|
||||
PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
|
||||
if (dStricmp(anim.name, name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
Con::errorf("Player::getAnimationID() -- Player does not contain a sequence that matches the name, %s.", name);
|
||||
return BAD_ANIM_ID;
|
||||
}
|
||||
|
||||
U32 Player::playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||
{
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return 0;
|
||||
|
||||
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||
if (seq_id == -1)
|
||||
{
|
||||
Con::errorf("Player::playAnimation() problem. BAD_SEQ_ID");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mShapeInstance->getShape()->sequences[seq_id].isBlend())
|
||||
return playBlendAnimation(seq_id, pos, rate);
|
||||
|
||||
if (isClientObject())
|
||||
{
|
||||
PlayerData::ActionAnimation &anim = mDataBlock->actionList[anim_id];
|
||||
if (anim.sequence != -1)
|
||||
{
|
||||
mActionAnimation.action = anim_id;
|
||||
mActionAnimation.forward = (rate >= 0);
|
||||
mActionAnimation.firstPerson = false;
|
||||
mActionAnimation.holdAtEnd = hold;
|
||||
mActionAnimation.waitForEnd = hold? true: wait;
|
||||
mActionAnimation.animateOnServer = false;
|
||||
mActionAnimation.atEnd = false;
|
||||
mActionAnimation.delayTicks = (S32)sNewAnimationTickTime;
|
||||
|
||||
F32 transTime = (trans < 0) ? sAnimationTransitionTime : trans;
|
||||
|
||||
mShapeInstance->setTimeScale(mActionAnimation.thread, rate);
|
||||
mShapeInstance->transitionToSequence(mActionAnimation.thread,anim.sequence,
|
||||
pos, transTime, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_death_anim)
|
||||
anim_clip_flags |= IS_DEATH_ANIM;
|
||||
else
|
||||
anim_clip_flags &= ~IS_DEATH_ANIM;
|
||||
|
||||
anim_clip_flags |= ANIM_OVERRIDDEN;
|
||||
last_anim_tag = unique_anim_tag_counter++;
|
||||
last_anim_id = anim_id;
|
||||
|
||||
return last_anim_tag;
|
||||
}
|
||||
|
||||
F32 Player::getAnimationDurationByID(U32 anim_id)
|
||||
{
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return 0.0f;
|
||||
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||
return mDataBlock->mShape->sequences[seq_id].duration;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool Player::isBlendAnimation(const char* name)
|
||||
{
|
||||
U32 anim_id = getAnimationID(name);
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return false;
|
||||
|
||||
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||
return mDataBlock->mShape->sequences[seq_id].isBlend();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* Player::getLastClipName(U32 clip_tag)
|
||||
{
|
||||
if (clip_tag != last_anim_tag || last_anim_id >= PlayerData::NumActionAnims)
|
||||
return "";
|
||||
|
||||
return mDataBlock->actionList[last_anim_id].name;
|
||||
}
|
||||
|
||||
void Player::unlockAnimation(U32 tag, bool force)
|
||||
{
|
||||
if ((tag != 0 && tag == last_anim_lock_tag) || force)
|
||||
anim_clip_flags &= ~BLOCK_USER_CONTROL;
|
||||
}
|
||||
|
||||
U32 Player::lockAnimation()
|
||||
{
|
||||
anim_clip_flags |= BLOCK_USER_CONTROL;
|
||||
last_anim_lock_tag = unique_anim_tag_counter++;
|
||||
|
||||
return last_anim_lock_tag;
|
||||
}
|
||||
|
||||
ConsoleMethod(Player, isAnimationLocked, bool, 2, 2, "isAnimationLocked()")
|
||||
{
|
||||
return object->isAnimationLocked();
|
||||
}
|
||||
|
||||
|
||||
#ifdef TORQUE_OPENVR
|
||||
void Player::setControllers(Vector<OpenVRTrackedObject*> controllerList)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -793,6 +793,17 @@ private:
|
|||
private:
|
||||
static bool sCorpsesHiddenFromRayCast;
|
||||
|
||||
public:
|
||||
virtual void restoreAnimation(U32 tag);
|
||||
virtual U32 getAnimationID(const char* name);
|
||||
virtual U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||
virtual F32 getAnimationDurationByID(U32 anim_id);
|
||||
virtual bool isBlendAnimation(const char* name);
|
||||
virtual const char* getLastClipName(U32 clip_tag);
|
||||
virtual void unlockAnimation(U32 tag, bool force=false);
|
||||
virtual U32 lockAnimation();
|
||||
virtual bool isAnimationLocked() const { return ((anim_clip_flags & BLOCK_USER_CONTROL) != 0); }
|
||||
|
||||
};
|
||||
|
||||
typedef Player::Pose PlayerPose;
|
||||
|
|
|
|||
|
|
@ -1045,6 +1045,13 @@ ShapeBase::ShapeBase()
|
|||
|
||||
for (i = 0; i < MaxTriggerKeys; i++)
|
||||
mTrigger[i] = false;
|
||||
anim_clip_flags = 0;
|
||||
last_anim_id = -1;
|
||||
last_anim_tag = 0;
|
||||
last_anim_lock_tag = 0;
|
||||
saved_seq_id = -1;
|
||||
saved_pos = 0.0f;
|
||||
saved_rate = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1183,6 +1190,16 @@ void ShapeBase::onSceneRemove()
|
|||
|
||||
bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
// need to destroy blend-clips or we crash
|
||||
if (isGhost())
|
||||
{
|
||||
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||
{
|
||||
if (blend_clips[i].thread)
|
||||
mShapeInstance->destroyThread(blend_clips[i].thread);
|
||||
blend_clips.erase_fast(i);
|
||||
}
|
||||
}
|
||||
ShapeBaseData *prevDB = dynamic_cast<ShapeBaseData*>( mDataBlock );
|
||||
|
||||
bool isInitialDataBlock = ( mDataBlock == 0 );
|
||||
|
|
@ -5101,6 +5118,186 @@ DefineEngineMethod( ShapeBase, getModelFile, const char *, (),,
|
|||
return datablock->getDataField( fieldName, NULL );
|
||||
}
|
||||
|
||||
|
||||
U32 ShapeBase::unique_anim_tag_counter = 1;
|
||||
|
||||
U32 ShapeBase::playBlendAnimation(S32 seq_id, F32 pos, F32 rate)
|
||||
{
|
||||
BlendThread blend_clip;
|
||||
blend_clip.tag = ((unique_anim_tag_counter++) | BLENDED_CLIP);
|
||||
blend_clip.thread = 0;
|
||||
|
||||
if (isClientObject())
|
||||
{
|
||||
blend_clip.thread = mShapeInstance->addThread();
|
||||
mShapeInstance->setSequence(blend_clip.thread, seq_id, pos);
|
||||
mShapeInstance->setTimeScale(blend_clip.thread, rate);
|
||||
}
|
||||
|
||||
blend_clips.push_back(blend_clip);
|
||||
|
||||
return blend_clip.tag;
|
||||
}
|
||||
|
||||
void ShapeBase::restoreBlendAnimation(U32 tag)
|
||||
{
|
||||
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||
{
|
||||
if (blend_clips[i].tag == tag)
|
||||
{
|
||||
if (blend_clips[i].thread)
|
||||
{
|
||||
mShapeInstance->destroyThread(blend_clips[i].thread);
|
||||
}
|
||||
blend_clips.erase_fast(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void ShapeBase::restoreAnimation(U32 tag)
|
||||
{
|
||||
if (!isClientObject())
|
||||
return;
|
||||
|
||||
// check if this is a blended clip
|
||||
if ((tag & BLENDED_CLIP) != 0)
|
||||
{
|
||||
restoreBlendAnimation(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag != 0 && tag == last_anim_tag)
|
||||
{
|
||||
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||
|
||||
stopThread(0);
|
||||
|
||||
if (saved_seq_id != -1)
|
||||
{
|
||||
setThreadSequence(0, saved_seq_id);
|
||||
setThreadPosition(0, saved_pos);
|
||||
setThreadTimeScale(0, saved_rate);
|
||||
setThreadDir(0, (saved_rate >= 0));
|
||||
playThread(0);
|
||||
|
||||
saved_seq_id = -1;
|
||||
saved_pos = 0.0f;
|
||||
saved_rate = 1.0f;
|
||||
}
|
||||
|
||||
last_anim_tag = 0;
|
||||
last_anim_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
U32 ShapeBase::getAnimationID(const char* name)
|
||||
{
|
||||
const TSShape* ts_shape = getShape();
|
||||
S32 seq_id = (ts_shape) ? ts_shape->findSequence(name) : -1;
|
||||
return (seq_id >= 0) ? (U32) seq_id : BAD_ANIM_ID;
|
||||
}
|
||||
|
||||
U32 ShapeBase::playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||
{
|
||||
if (!isClientObject())
|
||||
return 0;
|
||||
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return 0;
|
||||
|
||||
const TSShape* ts_shape = getShape();
|
||||
if (!ts_shape)
|
||||
return 0;
|
||||
|
||||
S32 seq_id = (S32) anim_id;
|
||||
if (mShapeInstance->getShape()->sequences[seq_id].isBlend())
|
||||
return playBlendAnimation(seq_id, pos, rate);
|
||||
|
||||
if (last_anim_tag == 0)
|
||||
{
|
||||
// try to save state of playing animation
|
||||
Thread& st = mScriptThread[0];
|
||||
if (st.sequence != -1)
|
||||
{
|
||||
saved_seq_id = st.sequence;
|
||||
saved_pos = st.position;
|
||||
saved_rate = st.timescale;
|
||||
}
|
||||
}
|
||||
|
||||
// START OR TRANSITION TO SEQUENCE HERE
|
||||
setThreadSequence(0, seq_id);
|
||||
setThreadPosition(0, pos);
|
||||
setThreadTimeScale(0, rate);
|
||||
setThreadDir(0, (rate >= 0));
|
||||
playThread(0);
|
||||
|
||||
if (is_death_anim)
|
||||
anim_clip_flags |= IS_DEATH_ANIM;
|
||||
else
|
||||
anim_clip_flags &= ~IS_DEATH_ANIM;
|
||||
|
||||
anim_clip_flags |= ANIM_OVERRIDDEN;
|
||||
last_anim_tag = unique_anim_tag_counter++;
|
||||
last_anim_id = anim_id;
|
||||
|
||||
return last_anim_tag;
|
||||
}
|
||||
|
||||
F32 ShapeBase::getAnimationDurationByID(U32 anim_id)
|
||||
{
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return 0.0f;
|
||||
|
||||
S32 seq_id = (S32) anim_id;
|
||||
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||
return mDataBlock->mShape->sequences[seq_id].duration;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool ShapeBase::isBlendAnimation(const char* name)
|
||||
{
|
||||
U32 anim_id = getAnimationID(name);
|
||||
if (anim_id == BAD_ANIM_ID)
|
||||
return false;
|
||||
|
||||
S32 seq_id = (S32) anim_id;
|
||||
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||
return mDataBlock->mShape->sequences[seq_id].isBlend();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ShapeBase::getLastClipName(U32 clip_tag)
|
||||
{
|
||||
if (clip_tag != last_anim_tag)
|
||||
return "";
|
||||
|
||||
S32 seq_id = (S32) last_anim_id;
|
||||
|
||||
S32 idx = mDataBlock->mShape->sequences[seq_id].nameIndex;
|
||||
if (idx < 0 || idx >= mDataBlock->mShape->names.size())
|
||||
return 0;
|
||||
|
||||
return mDataBlock->mShape->names[idx];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
U32 ShapeBase::playAnimation(const char* name, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||
{
|
||||
return playAnimationByID(getAnimationID(name), pos, rate, trans, hold, wait, is_death_anim);
|
||||
}
|
||||
|
||||
F32 ShapeBase::getAnimationDuration(const char* name)
|
||||
{
|
||||
return getAnimationDurationByID(getAnimationID(name));
|
||||
}
|
||||
|
||||
void ShapeBase::setSelectionFlags(U8 flags)
|
||||
{
|
||||
Parent::setSelectionFlags(flags);
|
||||
|
|
|
|||
|
|
@ -1861,6 +1861,43 @@ public:
|
|||
protected:
|
||||
DECLARE_CALLBACK( F32, validateCameraFov, (F32 fov) );
|
||||
|
||||
protected:
|
||||
enum {
|
||||
ANIM_OVERRIDDEN = BIT(0),
|
||||
BLOCK_USER_CONTROL = BIT(1),
|
||||
IS_DEATH_ANIM = BIT(2),
|
||||
BAD_ANIM_ID = 999999999,
|
||||
BLENDED_CLIP = 0x80000000,
|
||||
};
|
||||
struct BlendThread
|
||||
{
|
||||
TSThread* thread;
|
||||
U32 tag;
|
||||
};
|
||||
Vector<BlendThread> blend_clips;
|
||||
static U32 unique_anim_tag_counter;
|
||||
U8 anim_clip_flags;
|
||||
S32 last_anim_id;
|
||||
U32 last_anim_tag;
|
||||
U32 last_anim_lock_tag;
|
||||
S32 saved_seq_id;
|
||||
F32 saved_pos;
|
||||
F32 saved_rate;
|
||||
U32 playBlendAnimation(S32 seq_id, F32 pos, F32 rate);
|
||||
void restoreBlendAnimation(U32 tag);
|
||||
public:
|
||||
U32 playAnimation(const char* name, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||
F32 getAnimationDuration(const char* name);
|
||||
|
||||
virtual void restoreAnimation(U32 tag);
|
||||
virtual U32 getAnimationID(const char* name);
|
||||
virtual U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||
virtual F32 getAnimationDurationByID(U32 anim_id);
|
||||
virtual bool isBlendAnimation(const char* name);
|
||||
virtual const char* getLastClipName(U32 clip_tag);
|
||||
virtual void unlockAnimation(U32 tag, bool force=false) { }
|
||||
virtual U32 lockAnimation() { return 0; }
|
||||
virtual bool isAnimationLocked() const { return false; }
|
||||
|
||||
virtual void setSelectionFlags(U8 flags);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue