diff options
Diffstat (limited to 'indra/llcharacter/llmotioncontroller.cpp')
-rw-r--r-- | indra/llcharacter/llmotioncontroller.cpp | 2288 |
1 files changed, 1144 insertions, 1144 deletions
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 115606d863..e4dc066d58 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -1,1144 +1,1144 @@ -/** - * @file llmotioncontroller.cpp - * @brief Implementation of LLMotionController class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -//----------------------------------------------------------------------------- -// Header Files -//----------------------------------------------------------------------------- -#include "linden_common.h" - -#include "llmotioncontroller.h" -#include "llfasttimer.h" -#include "llkeyframemotion.h" -#include "llmath.h" -#include "lltimer.h" -#include "llanimationstates.h" -#include "llstl.h" - -// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4. -const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4; -const U32 MAX_MOTION_INSTANCES = 32; - -//----------------------------------------------------------------------------- -// Constants and statics -//----------------------------------------------------------------------------- -F32 LLMotionController::sCurrentTimeFactor = 1.f; -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 ) -{ - // LL_INFOS() << "Registering motion: " << name << LL_ENDL; - 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(sCurrentTimeFactor), - mCharacter(NULL), - mAnimTime(0.f), - mPrevTimerElapsed(0.f), - mLastTime(0.0f), - mHasRunOnce(false), - mPaused(false), - mPausedFrame(0), - mTimeStep(0.f), - mTimeStepCount(0), - mLastInterp(0.f), - mIsSelf(false), - mLastCountAfterPurge(0) -{ -} - - -//----------------------------------------------------------------------------- -// ~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(); - - // stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from - // mAllMotions to mDeprecatedMotions in method - // LLMotionController::deprecateMotionInstance(). Thus, we should also clean - // up the mDeprecatedMotions list as well. - for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); - mDeprecatedMotions.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 (LLMotion* cur_motionp : mLoadedMotions) - { - // motion isn't playing, delete it - if (!isMotionActive(cur_motionp)) - { - motions_to_kill.insert(cur_motionp->getID()); - } - } - } - - // clean up all inactive, loaded motions - for (LLUUID motion_id : motions_to_kill) - { - // look up the motion again by ID to get canonical instance - // and kill it only if that one is inactive - LLMotion* motionp = findMotion(motion_id); - if (motionp && !isMotionActive(motionp)) - { - removeMotion(motion_id); - } - } - - U32 loaded_count = mLoadedMotions.size(); - if (loaded_count > (2 * MAX_MOTION_INSTANCES) && loaded_count > mLastCountAfterPurge) - { - LL_WARNS_ONCE("Animation") << loaded_count << " Loaded Motions. Amount of motions is over limit." << LL_ENDL; - } - mLastCountAfterPurge = loaded_count; -} - -//----------------------------------------------------------------------------- -// 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 ) -{ - // 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: - LL_INFOS() << "Motion " << id << " init failed." << LL_ENDL; - 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: - LL_ERRS() << "Invalid initialization status" << LL_ENDL; - 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; - } - -// LL_INFOS() << "Starting motion " << name << LL_ENDL; - 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); - // SL-1290: always stop immediate if paused - return stopMotionInstance(motion, stop_immediate||mPaused); -} - -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_ANIMATED_JOINTS); - memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); -} - -//----------------------------------------------------------------------------- -// updateIdleMotion() -// minimal updates for active motions -//----------------------------------------------------------------------------- -void LLMotionController::updateIdleMotion(LLMotion* motionp) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - 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() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - 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) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - bool update_result = true; - U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS]; - - memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_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 - { - 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() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - // 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) - { - LL_INFOS() << "Motion " << motionp->getID() << " init failed." << LL_ENDL; - 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) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - // SL-763: "Distant animated objects run at super fast speed" - // The use_quantum optimization or possibly the associated code in setTimeStamp() - // does not work as implemented. - // Currently setting mTimeStep to nonzero is disabled elsewhere. - 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; -// LL_INFOS() << "Motion controller time " << motionTimer.getElapsedTimeF32() << LL_ENDL; -} - -//----------------------------------------------------------------------------- -// updateMotionsMinimal() -// minimal update (e.g. while hidden) -//----------------------------------------------------------------------------- -void LLMotionController::updateMotionsMinimal() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - // Always update mPrevTimerElapsed - mPrevTimerElapsed = mTimer.getElapsedTimeF32(); - - purgeExcessMotions(); - updateLoadingMotions(); - resetJointSignatures(); - - deactivateStoppedMotions(); - - mHasRunOnce = true; -} - -//----------------------------------------------------------------------------- -// activateMotionInstance() -//----------------------------------------------------------------------------- -bool LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - // 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() -{ - LL_INFOS() << "=====================================" << LL_ENDL; - for (motion_map_t::value_type& motion_pair : mAllMotions) - { - LLUUID id = motion_pair.first; - std::string state_string; - LLMotion *motion = motion_pair.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"); - LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL; - - } -} - -//----------------------------------------------------------------------------- -// deactivateAllMotions() -//----------------------------------------------------------------------------- -void LLMotionController::deactivateAllMotions() -{ - for (motion_map_t::value_type& motion_pair : mAllMotions) - { - LLMotion* motionp = motion_pair.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> >::value_type& motion_pair : active_motions) - { - startMotion(motion_pair.first, motion_pair.second); - } -} - -//----------------------------------------------------------------------------- -// pause() -//----------------------------------------------------------------------------- -void LLMotionController::pauseAllMotions() -{ - if (!mPaused) - { - //LL_INFOS() << "Pausing animations..." << LL_ENDL; - mPaused = true; - mPausedFrame = LLFrameTimer::getFrameCount(); - } - -} - -//----------------------------------------------------------------------------- -// unpause() -//----------------------------------------------------------------------------- -void LLMotionController::unpauseAllMotions() -{ - if (mPaused) - { - //LL_INFOS() << "Unpausing animations..." << LL_ENDL; - mPaused = false; - } -} -// End +/**
+ * @file llmotioncontroller.cpp
+ * @brief Implementation of LLMotionController class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+
+#include "llmotioncontroller.h"
+#include "llfasttimer.h"
+#include "llkeyframemotion.h"
+#include "llmath.h"
+#include "lltimer.h"
+#include "llanimationstates.h"
+#include "llstl.h"
+
+// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4.
+const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4;
+const U32 MAX_MOTION_INSTANCES = 32;
+
+//-----------------------------------------------------------------------------
+// Constants and statics
+//-----------------------------------------------------------------------------
+F32 LLMotionController::sCurrentTimeFactor = 1.f;
+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 )
+{
+ // LL_INFOS() << "Registering motion: " << name << LL_ENDL;
+ 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(sCurrentTimeFactor),
+ mCharacter(NULL),
+ mAnimTime(0.f),
+ mPrevTimerElapsed(0.f),
+ mLastTime(0.0f),
+ mHasRunOnce(false),
+ mPaused(false),
+ mPausedFrame(0),
+ mTimeStep(0.f),
+ mTimeStepCount(0),
+ mLastInterp(0.f),
+ mIsSelf(false),
+ mLastCountAfterPurge(0)
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// ~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();
+
+ // stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from
+ // mAllMotions to mDeprecatedMotions in method
+ // LLMotionController::deprecateMotionInstance(). Thus, we should also clean
+ // up the mDeprecatedMotions list as well.
+ for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer());
+ mDeprecatedMotions.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 (LLMotion* cur_motionp : mLoadedMotions)
+ {
+ // motion isn't playing, delete it
+ if (!isMotionActive(cur_motionp))
+ {
+ motions_to_kill.insert(cur_motionp->getID());
+ }
+ }
+ }
+
+ // clean up all inactive, loaded motions
+ for (LLUUID motion_id : motions_to_kill)
+ {
+ // look up the motion again by ID to get canonical instance
+ // and kill it only if that one is inactive
+ LLMotion* motionp = findMotion(motion_id);
+ if (motionp && !isMotionActive(motionp))
+ {
+ removeMotion(motion_id);
+ }
+ }
+
+ U32 loaded_count = mLoadedMotions.size();
+ if (loaded_count > (2 * MAX_MOTION_INSTANCES) && loaded_count > mLastCountAfterPurge)
+ {
+ LL_WARNS_ONCE("Animation") << loaded_count << " Loaded Motions. Amount of motions is over limit." << LL_ENDL;
+ }
+ mLastCountAfterPurge = loaded_count;
+}
+
+//-----------------------------------------------------------------------------
+// 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 )
+{
+ // 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:
+ LL_INFOS() << "Motion " << id << " init failed." << LL_ENDL;
+ 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:
+ LL_ERRS() << "Invalid initialization status" << LL_ENDL;
+ 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;
+ }
+
+// LL_INFOS() << "Starting motion " << name << LL_ENDL;
+ 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);
+ // SL-1290: always stop immediate if paused
+ return stopMotionInstance(motion, stop_immediate||mPaused);
+}
+
+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_ANIMATED_JOINTS);
+ memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
+}
+
+//-----------------------------------------------------------------------------
+// updateIdleMotion()
+// minimal updates for active motions
+//-----------------------------------------------------------------------------
+void LLMotionController::updateIdleMotion(LLMotion* motionp)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ 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()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ 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)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ bool update_result = true;
+ U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
+
+ memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_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
+ {
+ 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()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ // 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)
+ {
+ LL_INFOS() << "Motion " << motionp->getID() << " init failed." << LL_ENDL;
+ 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)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ // SL-763: "Distant animated objects run at super fast speed"
+ // The use_quantum optimization or possibly the associated code in setTimeStamp()
+ // does not work as implemented.
+ // Currently setting mTimeStep to nonzero is disabled elsewhere.
+ 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;
+// LL_INFOS() << "Motion controller time " << motionTimer.getElapsedTimeF32() << LL_ENDL;
+}
+
+//-----------------------------------------------------------------------------
+// updateMotionsMinimal()
+// minimal update (e.g. while hidden)
+//-----------------------------------------------------------------------------
+void LLMotionController::updateMotionsMinimal()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ // Always update mPrevTimerElapsed
+ mPrevTimerElapsed = mTimer.getElapsedTimeF32();
+
+ purgeExcessMotions();
+ updateLoadingMotions();
+ resetJointSignatures();
+
+ deactivateStoppedMotions();
+
+ mHasRunOnce = true;
+}
+
+//-----------------------------------------------------------------------------
+// activateMotionInstance()
+//-----------------------------------------------------------------------------
+bool LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+ // 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()
+{
+ LL_INFOS() << "=====================================" << LL_ENDL;
+ for (motion_map_t::value_type& motion_pair : mAllMotions)
+ {
+ LLUUID id = motion_pair.first;
+ std::string state_string;
+ LLMotion *motion = motion_pair.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");
+ LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL;
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// deactivateAllMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::deactivateAllMotions()
+{
+ for (motion_map_t::value_type& motion_pair : mAllMotions)
+ {
+ LLMotion* motionp = motion_pair.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> >::value_type& motion_pair : active_motions)
+ {
+ startMotion(motion_pair.first, motion_pair.second);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// pause()
+//-----------------------------------------------------------------------------
+void LLMotionController::pauseAllMotions()
+{
+ if (!mPaused)
+ {
+ //LL_INFOS() << "Pausing animations..." << LL_ENDL;
+ mPaused = true;
+ mPausedFrame = LLFrameTimer::getFrameCount();
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// unpause()
+//-----------------------------------------------------------------------------
+void LLMotionController::unpauseAllMotions()
+{
+ if (mPaused)
+ {
+ //LL_INFOS() << "Unpausing animations..." << LL_ENDL;
+ mPaused = false;
+ }
+}
+// End
|