summaryrefslogtreecommitdiff
path: root/indra/llcharacter/llmotioncontroller.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llcharacter/llmotioncontroller.cpp
Print done when done.
Diffstat (limited to 'indra/llcharacter/llmotioncontroller.cpp')
-rw-r--r--indra/llcharacter/llmotioncontroller.cpp927
1 files changed, 927 insertions, 0 deletions
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
new file mode 100644
index 0000000000..7ec67b5fd4
--- /dev/null
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -0,0 +1,927 @@
+/**
+ * @file llmotioncontroller.cpp
+ * @brief Implementation of LLMotionController class.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+
+#include "llmotioncontroller.h"
+#include "llkeyframemotion.h"
+#include "llmath.h"
+#include "lltimer.h"
+#include "llanimationstates.h"
+#include "llstl.h"
+
+const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4;
+const U32 MAX_MOTION_INSTANCES = 32;
+
+//-----------------------------------------------------------------------------
+// Constants and statics
+//-----------------------------------------------------------------------------
+LLMotionRegistry LLMotionController::sRegistry;
+
+//-----------------------------------------------------------------------------
+// LLMotionTableEntry()
+//-----------------------------------------------------------------------------
+LLMotionTableEntry::LLMotionTableEntry()
+{
+ mConstructor = NULL;
+ mID.setNull();
+}
+
+LLMotionTableEntry::LLMotionTableEntry(LLMotionConstructor constructor, const LLUUID& id)
+ : mConstructor(constructor), mID(id)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// create()
+//-----------------------------------------------------------------------------
+LLMotion* LLMotionTableEntry::create(const LLUUID &id)
+{
+ LLMotion* motionp = mConstructor(id);
+
+ return motionp;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLMotionRegistry class
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// LLMotionRegistry()
+// Class Constructor
+//-----------------------------------------------------------------------------
+LLMotionRegistry::LLMotionRegistry() : mMotionTable(LLMotionTableEntry::uuidEq, LLMotionTableEntry())
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLMotionRegistry()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLMotionRegistry::~LLMotionRegistry()
+{
+ mMotionTable.removeAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// addMotion()
+//-----------------------------------------------------------------------------
+BOOL LLMotionRegistry::addMotion( const LLUUID& id, LLMotionConstructor constructor )
+{
+// llinfos << "Registering motion: " << name << llendl;
+ if (!mMotionTable.check(id))
+ {
+ mMotionTable.set(id, LLMotionTableEntry(constructor, id));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// markBad()
+//-----------------------------------------------------------------------------
+void LLMotionRegistry::markBad( const LLUUID& id )
+{
+ mMotionTable.set(id, LLMotionTableEntry());
+}
+
+//-----------------------------------------------------------------------------
+// createMotion()
+//-----------------------------------------------------------------------------
+LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
+{
+ LLMotionTableEntry motion_entry = mMotionTable.get(id);
+ LLMotion* motion = NULL;
+
+ if ( motion_entry.getID().isNull() )
+ {
+ //FIXME - RN: need to replace with a better default scheme
+ motion = LLKeyframeMotion::create(id);
+ }
+ else
+ {
+ motion = motion_entry.create(id);
+ }
+
+ return motion;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLMotionController class
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// LLMotionController()
+// Class Constructor
+//-----------------------------------------------------------------------------
+LLMotionController::LLMotionController( )
+{
+ mTime = 0.f;
+ mTimeOffset = 0.f;
+ mLastTime = 0.0f;
+ mHasRunOnce = FALSE;
+ mPaused = FALSE;
+ mPauseTime = 0.f;
+ mTimeStep = 0.f;
+ mTimeStepCount = 0;
+ mLastInterp = 0.f;
+ mTimeFactor = 1.f;
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLMotionController()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLMotionController::~LLMotionController()
+{
+ deleteAllMotions();
+}
+
+//-----------------------------------------------------------------------------
+// deleteAllMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::deleteAllMotions()
+{
+ mLoadingMotions.removeAllNodes();
+ mLoadedMotions.clear();
+ mActiveMotions.removeAllNodes();
+
+ for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
+ mAllMotions.clear();
+}
+
+//-----------------------------------------------------------------------------
+// addLoadedMotion()
+//-----------------------------------------------------------------------------
+void LLMotionController::addLoadedMotion(LLMotion* motionp)
+{
+ if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
+ {
+ // too many motions active this frame, kill all blenders
+ mPoseBlender.clearBlenders();
+
+ for (U32 i = 0; i < mLoadedMotions.size(); i++)
+ {
+ LLMotion* cur_motionp = mLoadedMotions.front();
+ mLoadedMotions.pop_front();
+
+ // motion isn't playing, delete it
+ if (!isMotionActive(cur_motionp))
+ {
+ mCharacter->requestStopMotion(cur_motionp);
+ mAllMotions.erase(cur_motionp->getID());
+ delete cur_motionp;
+ if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES)
+ {
+ break;
+ }
+ }
+ else
+ {
+ // put active motion on back
+ mLoadedMotions.push_back(cur_motionp);
+ }
+ }
+ }
+ mLoadedMotions.push_back(motionp);
+}
+
+//-----------------------------------------------------------------------------
+// setTimeStep()
+//-----------------------------------------------------------------------------
+void LLMotionController::setTimeStep(F32 step)
+{
+ mTimeStep = step;
+
+ if (step != 0.f)
+ {
+ // make sure timestamps conform to new quantum
+ for( LLMotion* motionp = mActiveMotions.getFirstData();
+ motionp != NULL;
+ motionp = mActiveMotions.getNextData() )
+ {
+ motionp->mActivationTimestamp = (F32)llfloor(motionp->mActivationTimestamp / step) * step;
+ BOOL stopped = motionp->isStopped();
+ motionp->setStopTime((F32)llfloor(motionp->getStopTime() / step) * step);
+ motionp->setStopped(stopped);
+ motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// setTimeFactor()
+//-----------------------------------------------------------------------------
+void LLMotionController::setTimeFactor(F32 time_factor)
+{
+ mTimeOffset += mTimer.getElapsedTimeAndResetF32() * mTimeFactor;
+ mTimeFactor = time_factor;
+}
+
+//-----------------------------------------------------------------------------
+// getFirstActiveMotion()
+//-----------------------------------------------------------------------------
+LLMotion* LLMotionController::getFirstActiveMotion()
+{
+ return mActiveMotions.getFirstData();
+}
+
+//-----------------------------------------------------------------------------
+// getNextActiveMotion()
+//-----------------------------------------------------------------------------
+LLMotion* LLMotionController::getNextActiveMotion()
+{
+ return mActiveMotions.getNextData();
+}
+
+
+//-----------------------------------------------------------------------------
+// setCharacter()
+//-----------------------------------------------------------------------------
+void LLMotionController::setCharacter(LLCharacter *character)
+{
+ mCharacter = character;
+}
+
+
+//-----------------------------------------------------------------------------
+// addMotion()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::addMotion( const LLUUID& id, LLMotionConstructor constructor )
+{
+ return sRegistry.addMotion(id, constructor);
+}
+
+//-----------------------------------------------------------------------------
+// removeMotion()
+//-----------------------------------------------------------------------------
+void LLMotionController::removeMotion( const LLUUID& id)
+{
+ LLMotion* motionp = findMotion(id);
+ if (motionp)
+ {
+ stopMotionLocally(id, TRUE);
+
+ mLoadingMotions.deleteData(motionp);
+ std::deque<LLMotion*>::iterator motion_it;
+ for (motion_it = mLoadedMotions.begin(); motion_it != mLoadedMotions.end(); ++motion_it)
+ {
+ if(*motion_it == motionp)
+ {
+ mLoadedMotions.erase(motion_it);
+ break;
+ }
+ }
+ mActiveMotions.deleteData(motionp);
+ mAllMotions.erase(id);
+ delete motionp;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// createMotion()
+//-----------------------------------------------------------------------------
+LLMotion* LLMotionController::createMotion( const LLUUID &id )
+{
+ // do we have an instance of this motion for this character?
+ LLMotion *motion = findMotion(id);
+
+ // if not, we need to create one
+ if (!motion)
+ {
+ // look up constructor and create it
+ motion = sRegistry.createMotion(id);
+ if (!motion)
+ {
+ return NULL;
+ }
+
+ // look up name for default motions
+ const char* motion_name = gAnimLibrary.animStateToString(id);
+ if (motion_name)
+ {
+ motion->setName(motion_name);
+ }
+
+ // initialize the new instance
+ LLMotion::LLMotionInitStatus stat = motion->onInitialize(mCharacter);
+ switch(stat)
+ {
+ case LLMotion::STATUS_FAILURE:
+ llinfos << "Motion " << id << " init failed." << llendl;
+ sRegistry.markBad(id);
+ delete motion;
+ return NULL;
+ case LLMotion::STATUS_HOLD:
+ mLoadingMotions.addData(motion);
+ break;
+ case LLMotion::STATUS_SUCCESS:
+ // add motion to our list
+ addLoadedMotion(motion);
+ break;
+ default:
+ llerrs << "Invalid initialization status" << llendl;
+ break;
+ }
+
+ mAllMotions[id] = motion;
+ }
+ return motion;
+}
+
+//-----------------------------------------------------------------------------
+// startMotion()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
+{
+ // look for motion in our list of created motions
+ LLMotion *motion = createMotion(id);
+
+ if (!motion)
+ {
+ return FALSE;
+ }
+ //if the motion is already active, then we're done
+ else if (isMotionActive(motion)) // motion is playing and...
+ {
+ if (motion->isStopped()) // motion has been stopped
+ {
+ deactivateMotion(motion);
+ }
+ else if (mTime < motion->mSendStopTimestamp) // motion is still active
+ {
+ return TRUE;
+ }
+ }
+
+// llinfos << "Starting motion " << name << llendl;
+ return activateMotion(motion, mTime - start_offset);
+}
+
+
+//-----------------------------------------------------------------------------
+// stopMotionLocally()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate)
+{
+ // if already inactive, return false
+ LLMotion *motion = findMotion(id);
+ if (!motion)
+ {
+ return FALSE;
+ }
+
+ // If on active list, stop it
+ if (isMotionActive(motion) && !motion->isStopped())
+ {
+ // when using timesteps, set stop time to last frame's time, otherwise grab current timer value
+ // FIXME: should investigate this inconsistency...hints of obscure bugs
+
+ F32 stop_time = (mTimeStep != 0.f || mPaused) ? (mTime) : mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor);
+ motion->setStopTime(stop_time);
+
+ if (stop_immediate)
+ {
+ deactivateMotion(motion);
+ }
+ return TRUE;
+ }
+ else if (isMotionLoading(motion))
+ {
+ motion->setStopped(TRUE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+//-----------------------------------------------------------------------------
+// updateRegularMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::updateRegularMotions()
+{
+ updateMotionsByType(LLMotion::NORMAL_BLEND);
+}
+
+//-----------------------------------------------------------------------------
+// updateAdditiveMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::updateAdditiveMotions()
+{
+ updateMotionsByType(LLMotion::ADDITIVE_BLEND);
+}
+
+//-----------------------------------------------------------------------------
+// resetJointSignatures()
+//-----------------------------------------------------------------------------
+void LLMotionController::resetJointSignatures()
+{
+ memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+}
+
+//-----------------------------------------------------------------------------
+// updateMotionsByType()
+//-----------------------------------------------------------------------------
+void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
+{
+ BOOL update_result = TRUE;
+ U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS];
+
+ memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+
+ // iterate through active motions in chronological order
+ for(LLMotion* motionp = mActiveMotions.getFirstData();
+ motionp != NULL;
+ motionp = mActiveMotions.getNextData())
+ {
+ if (motionp->getBlendType() != anim_type)
+ {
+ continue;
+ }
+
+ BOOL update_motion = FALSE;
+
+ if (motionp->getPose()->getWeight() < 1.f)
+ {
+ update_motion = TRUE;
+ }
+ else
+ {
+ S32 i;
+ // NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4
+ for (i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++)
+ {
+ U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]);
+ U32 test_signature = *(U32*)&(motionp->mJointSignature[0][i * 4]);
+
+ if ((*current_signature | test_signature) > (*current_signature))
+ {
+ *current_signature |= test_signature;
+ update_motion = TRUE;
+ }
+
+ *((U32*)&last_joint_signature[i * 4]) = *(U32*)&(mJointSignature[1][i * 4]);
+ current_signature = (U32*)&(mJointSignature[1][i * 4]);
+ test_signature = *(U32*)&(motionp->mJointSignature[1][i * 4]);
+
+ if ((*current_signature | test_signature) > (*current_signature))
+ {
+ *current_signature |= test_signature;
+ update_motion = TRUE;
+ }
+ }
+ }
+
+ if (!update_motion)
+ {
+ if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
+ {
+ deactivateMotion(motionp);
+ }
+ else if (motionp->isStopped() && mTime > motionp->getStopTime())
+ {
+ // is this the first iteration in the ease out phase?
+ if (mLastTime <= motionp->getStopTime())
+ {
+ // store residual weight for this motion
+ motionp->mResidualWeight = motionp->getPose()->getWeight();
+ }
+ }
+ else if (mTime > motionp->mSendStopTimestamp)
+ {
+ // notify character of timed stop event on first iteration past sendstoptimestamp
+ // this will only be called when an animation stops itself (runs out of time)
+ if (mLastTime <= motionp->mSendStopTimestamp)
+ {
+ mCharacter->requestStopMotion( motionp );
+ stopMotionLocally(motionp->getID(), FALSE);
+ }
+ }
+ else if (mTime >= motionp->mActivationTimestamp)
+ {
+ if (mLastTime < motionp->mActivationTimestamp)
+ {
+ motionp->mResidualWeight = motionp->getPose()->getWeight();
+ }
+ }
+ continue;
+ }
+
+ LLPose *posep = motionp->getPose();
+
+ // only filter by LOD after running every animation at least once (to prime the avatar state)
+ if (mHasRunOnce && motionp->getMinPixelArea() > mCharacter->getPixelArea())
+ {
+ motionp->fadeOut();
+
+ //should we notify the simulator that this motion should be stopped (check even if skipped by LOD logic)
+ if (mTime > motionp->mSendStopTimestamp)
+ {
+ // notify character of timed stop event on first iteration past sendstoptimestamp
+ // this will only be called when an animation stops itself (runs out of time)
+ if (mLastTime <= motionp->mSendStopTimestamp)
+ {
+ mCharacter->requestStopMotion( motionp );
+ stopMotionLocally(motionp->getID(), FALSE);
+ }
+ }
+
+ if (motionp->getFadeWeight() < 0.01f)
+ {
+ if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
+ {
+ posep->setWeight(0.f);
+ deactivateMotion(motionp);
+ }
+ continue;
+ }
+ }
+ else
+ {
+ motionp->fadeIn();
+ }
+
+ //**********************
+ // MOTION INACTIVE
+ //**********************
+ if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
+ {
+ // this motion has gone on too long, deactivate it
+ // did we have a chance to stop it?
+ if (mLastTime <= motionp->getStopTime())
+ {
+ // if not, let's stop it this time through and deactivate it the next
+
+ posep->setWeight(motionp->getFadeWeight());
+ motionp->onUpdate(motionp->getStopTime() - motionp->mActivationTimestamp, last_joint_signature);
+ }
+ else
+ {
+ posep->setWeight(0.f);
+ deactivateMotion(motionp);
+ continue;
+ }
+ }
+
+ //**********************
+ // MOTION EASE OUT
+ //**********************
+ else if (motionp->isStopped() && mTime > motionp->getStopTime())
+ {
+ // is this the first iteration in the ease out phase?
+ if (mLastTime <= motionp->getStopTime())
+ {
+ // store residual weight for this motion
+ motionp->mResidualWeight = motionp->getPose()->getWeight();
+ }
+
+ if (motionp->getEaseOutDuration() == 0.f)
+ {
+ posep->setWeight(0.f);
+ }
+ else
+ {
+ posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight * cubic_step(1.f - ((mTime - motionp->getStopTime()) / motionp->getEaseOutDuration())));
+ }
+
+ // perform motion update
+ update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
+ }
+
+ //**********************
+ // MOTION ACTIVE
+ //**********************
+ else if (mTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
+ {
+ posep->setWeight(motionp->getFadeWeight());
+
+ //should we notify the simulator that this motion should be stopped?
+ if (mTime > motionp->mSendStopTimestamp)
+ {
+ // notify character of timed stop event on first iteration past sendstoptimestamp
+ // this will only be called when an animation stops itself (runs out of time)
+ if (mLastTime <= motionp->mSendStopTimestamp)
+ {
+ mCharacter->requestStopMotion( motionp );
+ stopMotionLocally(motionp->getID(), FALSE);
+ }
+ }
+
+ // perform motion update
+ update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
+ }
+
+ //**********************
+ // MOTION EASE IN
+ //**********************
+ else if (mTime >= motionp->mActivationTimestamp)
+ {
+ if (mLastTime < motionp->mActivationTimestamp)
+ {
+ motionp->mResidualWeight = motionp->getPose()->getWeight();
+ }
+ if (motionp->getEaseInDuration() == 0.f)
+ {
+ posep->setWeight(motionp->getFadeWeight());
+ }
+ else
+ {
+ // perform motion update
+ posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight + (1.f - motionp->mResidualWeight) * cubic_step((mTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration()));
+ }
+ // perform motion update
+ update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
+ }
+ else
+ {
+ posep->setWeight(0.f);
+ update_result = motionp->onUpdate(0.f, last_joint_signature);
+ }
+
+ // allow motions to deactivate themselves
+ if (!update_result)
+ {
+ if (!motionp->isStopped() || motionp->getStopTime() > mTime)
+ {
+ // animation has stopped itself due to internal logic
+ // propagate this to the network
+ // as not all viewers are guaranteed to have access to the same logic
+ mCharacter->requestStopMotion( motionp );
+ stopMotionLocally(motionp->getID(), FALSE);
+ }
+
+ }
+
+ // even if onupdate returns FALSE, add this motion in to the blend one last time
+ mPoseBlender.addMotion(motionp);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// updateMotion()
+//-----------------------------------------------------------------------------
+void LLMotionController::updateMotion()
+{
+ BOOL use_quantum = (mTimeStep != 0.f);
+
+ // Update timing info for this time step.
+ if (!mPaused)
+ {
+ F32 update_time = mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor);
+ if (use_quantum)
+ {
+ F32 time_interval = fmodf(update_time, mTimeStep);
+
+ // always animate *ahead* of actual time
+ S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
+ if (quantum_count == mTimeStepCount)
+ {
+ // we're still in same time quantum as before, so just interpolate and exit
+ if (!mPaused)
+ {
+ F32 interp = time_interval / mTimeStep;
+ mPoseBlender.interpolate(interp - mLastInterp);
+ mLastInterp = interp;
+ }
+
+ return;
+ }
+
+ // is calculating a new keyframe pose, make sure the last one gets applied
+ mPoseBlender.interpolate(1.f);
+ mPoseBlender.clearBlenders();
+
+ mTimeStepCount = quantum_count;
+ mLastTime = mTime;
+ mTime = (F32)quantum_count * mTimeStep;
+ mLastInterp = 0.f;
+ }
+ else
+ {
+ mLastTime = mTime;
+ mTime = update_time;
+ }
+ }
+
+ // query pending motions for completion
+ LLMotion* motionp;
+
+ for ( motionp = mLoadingMotions.getFirstData();
+ motionp != NULL;
+ motionp = mLoadingMotions.getNextData() )
+ {
+ LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter);
+ if (status == LLMotion::STATUS_SUCCESS)
+ {
+ mLoadingMotions.removeCurrentData();
+ // add motion to our loaded motion list
+ addLoadedMotion(motionp);
+ // this motion should be playing
+ if (!motionp->isStopped())
+ {
+ activateMotion(motionp, mTime);
+ }
+ }
+ else if (status == LLMotion::STATUS_FAILURE)
+ {
+ llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
+ sRegistry.markBad(motionp->getID());
+ mLoadingMotions.removeCurrentData();
+ mAllMotions.erase(motionp->getID());
+ delete motionp;
+ }
+ }
+
+ resetJointSignatures();
+
+ if (!mPaused)
+ {
+ // update additive motions
+ updateAdditiveMotions();
+ resetJointSignatures();
+
+ // update all regular motions
+ updateRegularMotions();
+
+ if (use_quantum)
+ {
+ mPoseBlender.blendAndCache(TRUE);
+ }
+ else
+ {
+ mPoseBlender.blendAndApply();
+ }
+ }
+
+ mHasRunOnce = TRUE;
+// llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl;
+}
+
+
+//-----------------------------------------------------------------------------
+// activateMotion()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::activateMotion(LLMotion *motion, F32 time)
+{
+ if (mLoadingMotions.checkData(motion))
+ {
+ // we want to start this motion, but we can't yet, so flag it as started
+ motion->setStopped(FALSE);
+ // report pending animations as activated
+ return TRUE;
+ }
+
+ motion->mResidualWeight = motion->getPose()->getWeight();
+ motion->mActivationTimestamp = time;
+
+ // set stop time based on given duration and ease out time
+ if (motion->getDuration() != 0.f && !motion->getLoop())
+ {
+ F32 ease_out_time;
+ F32 motion_duration;
+
+ // should we stop at the end of motion duration, or a bit earlier
+ // to allow it to ease out while moving?
+ ease_out_time = motion->getEaseOutDuration();
+
+ // is the clock running when the motion is easing in?
+ // if not (POSTURE_EASE) then we need to wait that much longer before triggering the stop
+ motion_duration = llmax(motion->getDuration() - ease_out_time, 0.f);
+ motion->mSendStopTimestamp = time + motion_duration;
+ }
+ else
+ {
+ motion->mSendStopTimestamp = F32_MAX;
+ }
+
+ mActiveMotions.addData(motion);
+
+ motion->activate();
+ motion->onUpdate(0.f, mJointSignature[1]);
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// deactivateMotion()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::deactivateMotion(LLMotion *motion)
+{
+ motion->deactivate();
+ mActiveMotions.removeData(motion);
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// isMotionActive()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::isMotionActive(LLMotion *motion)
+{
+ if (motion && motion->isActive())
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// isMotionLoading()
+//-----------------------------------------------------------------------------
+BOOL LLMotionController::isMotionLoading(LLMotion* motion)
+{
+ return mLoadingMotions.checkData(motion);
+}
+
+
+//-----------------------------------------------------------------------------
+// findMotion()
+//-----------------------------------------------------------------------------
+LLMotion *LLMotionController::findMotion(const LLUUID& id)
+{
+ return mAllMotions[id];
+}
+
+
+//-----------------------------------------------------------------------------
+// flushAllMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::flushAllMotions()
+{
+ LLDynamicArray<LLUUID> active_motions;
+ LLDynamicArray<F32> active_motion_times;
+
+ for (LLMotion* motionp = mActiveMotions.getFirstData();
+ motionp;
+ motionp = mActiveMotions.getNextData())
+ {
+ active_motions.put(motionp->getID());
+ active_motion_times.put(mTime - motionp->mActivationTimestamp);
+ motionp->deactivate();
+ }
+
+ // delete all motion instances
+ deleteAllMotions();
+
+ // kill current hand pose that was previously called out by
+ // keyframe motion
+ mCharacter->removeAnimationData("Hand Pose");
+
+ // restart motions
+ for (S32 i = 0; i < active_motions.count(); i++)
+ {
+ startMotion(active_motions[i], active_motion_times[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// pause()
+//-----------------------------------------------------------------------------
+void LLMotionController::pause()
+{
+ if (!mPaused)
+ {
+ //llinfos << "Pausing animations..." << llendl;
+ mPauseTime = mTimer.getElapsedTimeF32();
+ mPaused = TRUE;
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// unpause()
+//-----------------------------------------------------------------------------
+void LLMotionController::unpause()
+{
+ if (mPaused)
+ {
+ //llinfos << "Unpausing animations..." << llendl;
+ mTimer.reset();
+ mTimer.setAge(mPauseTime);
+ mPaused = FALSE;
+ }
+}
+// End