Files
SingularityViewer/indra/llcharacter/llmotioncontroller.cpp
Lirusaito 61beedd3d9 Changed style of comments with asterisks to avoid highlighting errors on //* with weak highlighters, change is to all files that could potentially break highlights
Most were needed, though some were just for possible problems with highlighting, should not affect performance whatsoever.
2012-01-09 05:40:03 -05:00

1133 lines
34 KiB
C++

/**
* @file llmotioncontroller.cpp
* @brief Implementation of LLMotionController class.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"
#include "llmemtype.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;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLMotionRegistry class
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLMotionRegistry()
// Class Constructor
//-----------------------------------------------------------------------------
LLMotionRegistry::LLMotionRegistry()
{
}
//-----------------------------------------------------------------------------
// ~LLMotionRegistry()
// Class Destructor
//-----------------------------------------------------------------------------
LLMotionRegistry::~LLMotionRegistry()
{
mMotionTable.clear();
}
//-----------------------------------------------------------------------------
// addMotion()
//-----------------------------------------------------------------------------
BOOL LLMotionRegistry::registerMotion( const LLUUID& id, LLMotionConstructor constructor )
{
// llinfos << "Registering motion: " << name << llendl;
if (!is_in_map(mMotionTable, id))
{
mMotionTable[id] = constructor;
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// markBad()
//-----------------------------------------------------------------------------
void LLMotionRegistry::markBad( const LLUUID& id )
{
mMotionTable[id] = LLMotionConstructor(NULL);
}
//-----------------------------------------------------------------------------
// createMotion()
//-----------------------------------------------------------------------------
LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
{
LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL));
LLMotion* motion = NULL;
if ( constructor == NULL )
{
// *FIX: need to replace with a better default scheme. RN
motion = LLKeyframeMotion::create(id);
}
else
{
motion = constructor(id);
}
return motion;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLMotionController class
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLMotionController()
// Class Constructor
//-----------------------------------------------------------------------------
LLMotionController::LLMotionController()
: mTimeFactor(1.f),
mCharacter(NULL),
mAnimTime(0.f),
mPrevTimerElapsed(0.f),
mLastTime(0.0f),
mHasRunOnce(FALSE),
mPaused(FALSE),
mPauseTime(0.f),
mTimeStep(0.f),
mTimeStepCount(0),
mLastInterp(0.f),
mIsSelf(FALSE)
{
}
//-----------------------------------------------------------------------------
// ~LLMotionController()
// Class Destructor
//-----------------------------------------------------------------------------
LLMotionController::~LLMotionController()
{
deleteAllMotions();
}
void LLMotionController::incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions)
{
num_motions += mAllMotions.size();
num_loading_motions += mLoadingMotions.size();
num_loaded_motions += mLoadedMotions.size();
num_active_motions += mActiveMotions.size();
num_deprecated_motions += mDeprecatedMotions.size();
}
//-----------------------------------------------------------------------------
// deleteAllMotions()
//-----------------------------------------------------------------------------
void LLMotionController::deleteAllMotions()
{
mLoadingMotions.clear();
mLoadedMotions.clear();
mActiveMotions.clear();
for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
mAllMotions.clear();
}
//-----------------------------------------------------------------------------
// purgeExcessMotion()
//-----------------------------------------------------------------------------
void LLMotionController::purgeExcessMotions()
{
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
{
// clean up deprecated motions
for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin();
deprecated_motion_it != mDeprecatedMotions.end(); )
{
motion_set_t::iterator cur_iter = deprecated_motion_it++;
LLMotion* cur_motionp = *cur_iter;
if (!isMotionActive(cur_motionp))
{
// Motion is deprecated so we know it's not cannonical,
// we can safely remove the instance
removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions
mDeprecatedMotions.erase(cur_iter);
}
}
}
std::set<LLUUID> motions_to_kill;
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
{
// too many motions active this frame, kill all blenders
mPoseBlender.clearBlenders();
for (motion_set_t::iterator loaded_motion_it = mLoadedMotions.begin();
loaded_motion_it != mLoadedMotions.end();
++loaded_motion_it)
{
LLMotion* cur_motionp = *loaded_motion_it;
// motion isn't playing, delete it
if (!isMotionActive(cur_motionp))
{
motions_to_kill.insert(cur_motionp->getID());
}
}
}
// clean up all inactive, loaded motions
for (std::set<LLUUID>::iterator motion_it = motions_to_kill.begin();
motion_it != motions_to_kill.end();
++motion_it)
{
// look up the motion again by ID to get canonical instance
// and kill it only if that one is inactive
LLUUID motion_id = *motion_it;
LLMotion* motionp = findMotion(motion_id);
if (motionp && !isMotionActive(motionp))
{
removeMotion(motion_id);
}
}
if (mLoadedMotions.size() > 2*MAX_MOTION_INSTANCES)
{
LL_WARNS_ONCE("Animation") << "> " << 2*MAX_MOTION_INSTANCES << " Loaded Motions" << llendl;
}
}
//-----------------------------------------------------------------------------
// deactivateStoppedMotions()
//-----------------------------------------------------------------------------
void LLMotionController::deactivateStoppedMotions()
{
// Since we're hidden, deactivate any stopped motions.
for (motion_list_t::iterator iter = mActiveMotions.begin();
iter != mActiveMotions.end(); )
{
motion_list_t::iterator curiter = iter++;
LLMotion* motionp = *curiter;
if (motionp->isStopped())
{
deactivateMotionInstance(motionp);
}
}
}
//-----------------------------------------------------------------------------
// setTimeStep()
//-----------------------------------------------------------------------------
void LLMotionController::setTimeStep(F32 step)
{
mTimeStep = step;
if (step != 0.f)
{
// make sure timestamps conform to new quantum
for (motion_list_t::iterator iter = mActiveMotions.begin();
iter != mActiveMotions.end(); ++iter)
{
LLMotion* motionp = *iter;
F32 activation_time = motionp->mActivationTimestamp;
motionp->mActivationTimestamp = (F32)(llfloor(activation_time / 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)
{
mTimeFactor = time_factor;
}
//-----------------------------------------------------------------------------
// setCharacter()
//-----------------------------------------------------------------------------
void LLMotionController::setCharacter(LLCharacter *character)
{
mCharacter = character;
}
//-----------------------------------------------------------------------------
// registerMotion()
//-----------------------------------------------------------------------------
BOOL LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor constructor )
{
return sRegistry.registerMotion(id, constructor);
}
//-----------------------------------------------------------------------------
// removeMotion()
//-----------------------------------------------------------------------------
void LLMotionController::removeMotion( const LLUUID& id)
{
LLMotion* motionp = findMotion(id);
mAllMotions.erase(id);
removeMotionInstance(motionp);
}
// removes instance of a motion from all runtime structures, but does
// not erase entry by ID, as this could be a duplicate instance
// use removeMotion(id) to remove all references to a given motion by id.
void LLMotionController::removeMotionInstance(LLMotion* motionp)
{
if (motionp)
{
llassert(findMotion(motionp->getID()) != motionp);
if (motionp->isActive())
motionp->deactivate();
mLoadingMotions.erase(motionp);
mLoadedMotions.erase(motionp);
mActiveMotions.remove(motionp);
delete motionp;
}
}
//-----------------------------------------------------------------------------
// createMotion()
//-----------------------------------------------------------------------------
LLMotion* LLMotionController::createMotion( const LLUUID &id )
{
LLMemType mt(LLMemType::MTYPE_ANIMATION);
// 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.insert(motion);
break;
case LLMotion::STATUS_SUCCESS:
// add motion to our list
mLoadedMotions.insert(motion);
break;
default:
llerrs << "Invalid initialization status" << llendl;
break;
}
mAllMotions[id] = motion;
}
return motion;
}
//-----------------------------------------------------------------------------
// startMotion()
//-----------------------------------------------------------------------------
BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
{
// do we have an instance of this motion for this character?
LLMotion *motion = findMotion(id);
// motion that is stopping will be allowed to stop but
// replaced by a new instance of that motion
if (motion
&& !mPaused
&& motion->canDeprecate()
&& motion->getFadeWeight() > 0.01f // not LOD-ed out
&& (motion->isBlending() || motion->getStopTime() != 0.f))
{
deprecateMotionInstance(motion);
// force creation of new instance
motion = NULL;
}
// create new motion instance
if (!motion)
{
motion = createMotion(id);
}
if (!motion)
{
return FALSE;
}
//if the motion is already active and allows deprecation, then let it keep playing
else if (motion->canDeprecate() && isMotionActive(motion))
{
return TRUE;
}
// llinfos << "Starting motion " << name << llendl;
return activateMotionInstance(motion, mAnimTime - start_offset);
}
//-----------------------------------------------------------------------------
// stopMotionLocally()
//-----------------------------------------------------------------------------
BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate)
{
// if already inactive, return false
LLMotion *motion = findMotion(id);
return stopMotionInstance(motion, stop_immediate);
}
BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate)
{
if (!motion)
{
return FALSE;
}
// If on active list, stop it
if (isMotionActive(motion) && !motion->isStopped())
{
motion->setStopTime(mAnimTime);
if (stop_immediate)
{
deactivateMotionInstance(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);
}
//-----------------------------------------------------------------------------
// updateIdleMotion()
// minimal updates for active motions
//-----------------------------------------------------------------------------
void LLMotionController::updateIdleMotion(LLMotion* motionp)
{
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
{
deactivateMotionInstance(motionp);
}
else if (motionp->isStopped() && mAnimTime > 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 (mAnimTime > 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 );
stopMotionInstance(motionp, FALSE);
}
}
else if (mAnimTime >= motionp->mActivationTimestamp)
{
if (mLastTime < motionp->mActivationTimestamp)
{
motionp->mResidualWeight = motionp->getPose()->getWeight();
}
}
}
//-----------------------------------------------------------------------------
// updateIdleActiveMotions()
// Call this instead of updateMotionsByType for hidden avatars
//-----------------------------------------------------------------------------
void LLMotionController::updateIdleActiveMotions()
{
for (motion_list_t::iterator iter = mActiveMotions.begin();
iter != mActiveMotions.end(); )
{
motion_list_t::iterator curiter = iter++;
LLMotion* motionp = *curiter;
updateIdleMotion(motionp);
}
}
//-----------------------------------------------------------------------------
// 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 (motion_list_t::iterator iter = mActiveMotions.begin();
iter != mActiveMotions.end(); )
{
motion_list_t::iterator curiter = iter++;
LLMotion* motionp = *curiter;
if (motionp->getBlendType() != anim_type)
{
continue;
}
BOOL update_motion = FALSE;
if (motionp->getPose()->getWeight() < 1.f)
{
update_motion = TRUE;
}
else
{
// NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4
for (S32 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)
{
updateIdleMotion(motionp);
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 (mAnimTime > 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 );
stopMotionInstance(motionp, FALSE);
}
}
if (motionp->getFadeWeight() < 0.01f)
{
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
{
posep->setWeight(0.f);
deactivateMotionInstance(motionp);
}
continue;
}
}
else
{
motionp->fadeIn();
}
// **********************
// MOTION INACTIVE
// **********************
if (motionp->isStopped() && mAnimTime > 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);
deactivateMotionInstance(motionp);
continue;
}
}
// **********************
// MOTION EASE OUT
// **********************
else if (motionp->isStopped() && mAnimTime > 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 - ((mAnimTime - motionp->getStopTime()) / motionp->getEaseOutDuration())));
}
// perform motion update
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
}
// **********************
// MOTION ACTIVE
// **********************
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
{
posep->setWeight(motionp->getFadeWeight());
//should we notify the simulator that this motion should be stopped?
if (mAnimTime > 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 );
stopMotionInstance(motionp, FALSE);
}
}
// perform motion update
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
}
// **********************
// MOTION EASE IN
// **********************
else if (mAnimTime >= 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((mAnimTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration()));
}
// perform motion update
update_result = motionp->onUpdate(mAnimTime - 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() > mAnimTime)
{
// 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 );
stopMotionInstance(motionp, FALSE);
}
}
// even if onupdate returns FALSE, add this motion in to the blend one last time
mPoseBlender.addMotion(motionp);
}
}
//-----------------------------------------------------------------------------
// updateLoadingMotions()
//-----------------------------------------------------------------------------
void LLMotionController::updateLoadingMotions()
{
// query pending motions for completion
for (motion_set_t::iterator iter = mLoadingMotions.begin();
iter != mLoadingMotions.end(); )
{
motion_set_t::iterator curiter = iter++;
LLMotion* motionp = *curiter;
if( !motionp)
{
continue; // maybe shouldn't happen but i've seen it -MG
}
LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter);
if (status == LLMotion::STATUS_SUCCESS)
{
mLoadingMotions.erase(curiter);
// add motion to our loaded motion list
mLoadedMotions.insert(motionp);
// this motion should be playing
if (!motionp->isStopped())
{
activateMotionInstance(motionp, mAnimTime);
}
}
else if (status == LLMotion::STATUS_FAILURE)
{
llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
sRegistry.markBad(motionp->getID());
mLoadingMotions.erase(curiter);
motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
if (found_it != mDeprecatedMotions.end())
{
mDeprecatedMotions.erase(found_it);
}
mAllMotions.erase(motionp->getID());
delete motionp;
}
}
}
//-----------------------------------------------------------------------------
// call updateMotion() or updateMotionsMinimal() every frame
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// updateMotion()
//-----------------------------------------------------------------------------
void LLMotionController::updateMotions(bool force_update)
{
BOOL use_quantum = (mTimeStep != 0.f);
// Always update mPrevTimerElapsed
F32 cur_time = mTimer.getElapsedTimeF32();
F32 delta_time = cur_time - mPrevTimerElapsed;
mPrevTimerElapsed = cur_time;
mLastTime = mAnimTime;
// Always cap the number of loaded motions
purgeExcessMotions();
// Update timing info for this time step.
if (!mPaused)
{
F32 update_time = mAnimTime + delta_time * 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;
}
updateLoadingMotions();
return;
}
// is calculating a new keyframe pose, make sure the last one gets applied
mPoseBlender.interpolate(1.f);
clearBlenders();
mTimeStepCount = quantum_count;
mAnimTime = (F32)quantum_count * mTimeStep;
mLastInterp = 0.f;
}
else
{
mAnimTime = update_time;
}
}
updateLoadingMotions();
resetJointSignatures();
if (mPaused && !force_update)
{
updateIdleActiveMotions();
}
else
{
// 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;
}
//-----------------------------------------------------------------------------
// updateMotionsMinimal()
// minimal update (e.g. while hidden)
//-----------------------------------------------------------------------------
void LLMotionController::updateMotionsMinimal()
{
// Always update mPrevTimerElapsed
mPrevTimerElapsed = mTimer.getElapsedTimeF32();
purgeExcessMotions();
updateLoadingMotions();
resetJointSignatures();
deactivateStoppedMotions();
mHasRunOnce = TRUE;
}
//-----------------------------------------------------------------------------
// activateMotionInstance()
//-----------------------------------------------------------------------------
BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
{
// It's not clear why the getWeight() line seems to be crashing this, but
// hopefully this fixes it.
if (motion == NULL || motion->getPose() == NULL)
{
return FALSE;
}
if (mLoadingMotions.find(motion) != mLoadingMotions.end())
{
// 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();
// 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;
}
if (motion->isActive())
{
mActiveMotions.remove(motion);
}
mActiveMotions.push_front(motion);
motion->activate(time);
motion->onUpdate(0.f, mJointSignature[1]);
if (mAnimTime >= motion->mSendStopTimestamp)
{
motion->setStopTime(motion->mSendStopTimestamp);
if (motion->mResidualWeight == 0.0f)
{
// bit of a hack; if newly activating a motion while easing out, weight should = 1
motion->mResidualWeight = 1.f;
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// deactivateMotionInstance()
//-----------------------------------------------------------------------------
BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion)
{
motion->deactivate();
motion_set_t::iterator found_it = mDeprecatedMotions.find(motion);
if (found_it != mDeprecatedMotions.end())
{
// deprecated motions need to be completely excised
removeMotionInstance(motion);
mDeprecatedMotions.erase(found_it);
}
else
{
// for motions that we are keeping, simply remove from active queue
mActiveMotions.remove(motion);
}
return TRUE;
}
void LLMotionController::deprecateMotionInstance(LLMotion* motion)
{
mDeprecatedMotions.insert(motion);
//fade out deprecated motion
stopMotionInstance(motion, FALSE);
//no longer canonical
mAllMotions.erase(motion->getID());
}
//-----------------------------------------------------------------------------
// isMotionActive()
//-----------------------------------------------------------------------------
bool LLMotionController::isMotionActive(LLMotion *motion)
{
return (motion && motion->isActive());
}
//-----------------------------------------------------------------------------
// isMotionLoading()
//-----------------------------------------------------------------------------
bool LLMotionController::isMotionLoading(LLMotion* motion)
{
return (mLoadingMotions.find(motion) != mLoadingMotions.end());
}
//-----------------------------------------------------------------------------
// findMotion()
//-----------------------------------------------------------------------------
LLMotion* LLMotionController::findMotion(const LLUUID& id) const
{
motion_map_t::const_iterator iter = mAllMotions.find(id);
if(iter == mAllMotions.end())
{
return NULL;
}
else
{
return iter->second;
}
}
//-----------------------------------------------------------------------------
// dumpMotions()
//-----------------------------------------------------------------------------
void LLMotionController::dumpMotions()
{
llinfos << "=====================================" << llendl;
for (motion_map_t::iterator iter = mAllMotions.begin();
iter != mAllMotions.end(); iter++)
{
LLUUID id = iter->first;
std::string state_string;
LLMotion *motion = iter->second;
if (mLoadingMotions.find(motion) != mLoadingMotions.end())
state_string += std::string("l");
if (mLoadedMotions.find(motion) != mLoadedMotions.end())
state_string += std::string("L");
if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
state_string += std::string("A");
if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end())
state_string += std::string("D");
llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
}
}
//-----------------------------------------------------------------------------
// deactivateAllMotions()
//-----------------------------------------------------------------------------
void LLMotionController::deactivateAllMotions()
{
for (motion_map_t::iterator iter = mAllMotions.begin();
iter != mAllMotions.end(); iter++)
{
LLMotion* motionp = iter->second;
deactivateMotionInstance(motionp);
}
}
//-----------------------------------------------------------------------------
// flushAllMotions()
//-----------------------------------------------------------------------------
void LLMotionController::flushAllMotions()
{
std::vector<std::pair<LLUUID,F32> > active_motions;
active_motions.reserve(mActiveMotions.size());
for (motion_list_t::iterator iter = mActiveMotions.begin();
iter != mActiveMotions.end(); )
{
motion_list_t::iterator curiter = iter++;
LLMotion* motionp = *curiter;
F32 dtime = mAnimTime - motionp->mActivationTimestamp;
active_motions.push_back(std::make_pair(motionp->getID(),dtime));
motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it
}
mActiveMotions.clear();
// delete all motion instances
deleteAllMotions();
// kill current hand pose that was previously called out by
// keyframe motion
mCharacter->removeAnimationData("Hand Pose");
// restart motions
for (std::vector<std::pair<LLUUID,F32> >::iterator iter = active_motions.begin();
iter != active_motions.end(); ++iter)
{
startMotion(iter->first, iter->second);
}
}
//-----------------------------------------------------------------------------
// pause()
//-----------------------------------------------------------------------------
void LLMotionController::pauseAllMotions()
{
if (!mPaused)
{
//llinfos << "Pausing animations..." << llendl;
mPaused = TRUE;
}
}
//-----------------------------------------------------------------------------
// unpause()
//-----------------------------------------------------------------------------
void LLMotionController::unpauseAllMotions()
{
if (mPaused)
{
//llinfos << "Unpausing animations..." << llendl;
mPaused = FALSE;
}
}
// End