//----------------------------------------------------------------------------- // stopMotionLocally() //----------------------------------------------------------------------------- BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate) { // if already inactive, return false LLMotion *motion = findMotion(id); if (!motion) { return FALSE; } // If on active list, stop it if (isMotionActive(motion) && !motion->isStopped()) { // when using timesteps, set stop time to last frame's time, otherwise grab current timer value // *FIX: should investigate this inconsistency...hints of obscure bugs F32 stop_time = (mTimeStep != 0.f || mPaused) ? (mTime) : mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor); motion->setStopTime(stop_time); if (stop_immediate) { deactivateMotion(motion, false); } return TRUE; } else if (isMotionLoading(motion)) { motion->setStopped(TRUE); return TRUE; } return FALSE; }
//----------------------------------------------------------------------------- // startMotion() //----------------------------------------------------------------------------- BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) { // look for motion in our list of created motions LLMotion *motion = createMotion(id); if (!motion) { return FALSE; } //if the motion is already active, then we're done else if (isMotionActive(motion)) // motion is playing and... { if (motion->isStopped()) // motion has been stopped { deactivateMotion(motion, false); } else if (mTime < motion->mSendStopTimestamp) // motion is still active { return TRUE; } } // llinfos << "Starting motion " << name << llendl; return activateMotion(motion, mTime - start_offset); }
// static void LLPreviewAnim::auditionAnim( void *userdata ) { LLPreviewAnim* self = (LLPreviewAnim*) userdata; const LLInventoryItem *item = self->getItem(); if(item) { LLUUID itemID=item->getAssetUUID(); LLButton* btn = self->getChild<LLButton>("Anim audition btn"); if (btn) { btn->toggleState(); } if (self->childGetValue("Anim audition btn").asBoolean() ) { self->mPauseRequest = NULL; gAgent.getAvatarObject()->startMotion(item->getAssetUUID()); LLVOAvatar* avatar = gAgent.getAvatarObject(); LLMotion* motion = avatar->findMotion(itemID); if (motion) { motion->setDeactivateCallback(&endAnimCallback, (void *)(new LLHandle<LLFloater>(self->getHandle()))); } } else { gAgent.getAvatarObject()->stopMotion(itemID); gAgent.sendAnimationRequest(itemID, ANIM_REQUEST_STOP); } } }
//----------------------------------------------------------------------------- // onSliderMove() //----------------------------------------------------------------------------- void LLFloaterAnimPreview::onSliderMove(LLUICtrl* ctrl, void*user_data) { LLFloaterAnimPreview* previewp = (LLFloaterAnimPreview*)user_data; if (!previewp->getEnabled()) return; LLVOAvatar* avatarp; if (previewp->mInWorld) { if (!gAgent.getAvatarObject()) { return; } avatarp = gAgent.getAvatarObject(); } else { if (!previewp->mAnimPreview) { return; } avatarp = previewp->mAnimPreview->getDummyAvatar(); } F32 slider_value = (F32)previewp->childGetValue("playback_slider").asReal(); LLUUID base_id = previewp->mIDList[previewp->childGetValue("preview_base_anim").asString()]; LLMotion* motionp = avatarp->findMotion(previewp->mMotionID); F32 duration = motionp->getDuration();// + motionp->getEaseOutDuration(); F32 delta_time = duration * slider_value; avatarp->deactivateAllMotions(); avatarp->startMotion(base_id, delta_time + BASE_ANIM_TIME_OFFSET); avatarp->startMotion(previewp->mMotionID, delta_time); previewp->mPauseRequest = avatarp->requestPause(); previewp->refresh(); }
//----------------------------------------------------------------------------- // 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); } }
void LLMotionController::pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles) { // Run over all motions. for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) { LLMotion* motionp = *iter; AISyncServer* server = motionp->server(); if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. { // Run over all clients of the found servers. AISyncServer::client_list_t const& clients = server->getClients(); for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) { LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr); if (!motion) { continue; } LLMotionController* controller = motion->getController(); if (controller == this) { continue; } controller->requestPause(avatar_pause_handles); } } } }
//----------------------------------------------------------------------------- // deactivateAllMotions() //----------------------------------------------------------------------------- void LLMotionController::deactivateAllMotions() { //They must all die, precious. for (std::map<LLUUID, LLMotion*>::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); iter++) { LLMotion* motionp = iter->second; if (motionp) motionp->deactivate(); } // delete all motion instances deleteAllMotions(); }
//<singu> //----------------------------------------------------------------------------- // toggle_hidden() //----------------------------------------------------------------------------- void LLMotionController::toggle_hidden(void) { mHaveVisibleSyncedMotions = mHidden; // Default is false if we just became invisible (otherwise this value isn't used). mHidden = !mHidden; synceventset_t const visible = mHidden ? 0 : 4; // Run over all motions. for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) { LLMotion* motionp = *iter; AISyncServer* server = motionp->server(); if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. { bool visible_before = server->events_with_at_least_one_client_ready() & 4; server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible. bool visible_after = server->events_with_at_least_one_client_ready() & 4; if (visible_after) // Are there any synchronized motions (left) that ARE visible? { mHaveVisibleSyncedMotions = true; } if (visible_before != visible_after) { // The group as a whole now might need to change whether or not it is animated. AISyncServer::client_list_t const& clients = server->getClients(); for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) { LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr); if (!motion) { continue; } LLMotionController* controller = motion->getController(); if (controller == this) { continue; } if (visible_after) { // Us becoming visible means that all synchronized avatars need to be animated again too. controller->setHaveVisibleSyncedMotions(); } else { // Us becoming hidden means that all synchronized avatars might stop animating. controller->refresh_hidden(); // It is extremely unlikely, but harmless, to call this twice on the same controller. } } } } } }
//----------------------------------------------------------------------------- // 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); } } }
//----------------------------------------------------------------------------- // 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()) { //<singu> F32 start_time = mAnimTime; if (!mDisableSyncing) { motionp->aisync_loaded(); start_time = motionp->syncActivationTime(start_time); } ++mDisableSyncing; //</singu> activateMotionInstance(motionp, start_time); //<singu> --mDisableSyncing; //</singu> } } else if (status == LLMotion::STATUS_FAILURE) { llinfos << "Motion " << motionp->getID() << " init failed." << llendl; sRegistry.markBad(motionp->getID()); mLoadingMotions.erase(curiter); // Singu note: a motion in mLoadingMotions will not be in mActiveMotions // and therefore not be in mDeprecatedMotions. So, we don't have to // check for it's existence there. llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end()); mAllMotions.erase(motionp->getID()); //<singu> // Make sure we're not registered anymore. motionp->unregister_client(); //</singu> 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; }
//----------------------------------------------------------------------------- // LLKeyframeMotionParam::addKeyframeMotion() //----------------------------------------------------------------------------- BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value) { LLMotion *newMotion = mCharacter->createMotion( id ); if (!newMotion) { return FALSE; } newMotion->setName(name); // now add motion to this list mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value)); return TRUE; }
void LLPreviewAnim::onClose(bool app_quitting) { const LLInventoryItem *item = getItem(); if(item) { gAgentAvatarp->stopMotion(item->getAssetUUID()); gAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); LLMotion* motion = gAgentAvatarp->findMotion(item->getAssetUUID()); if (motion) { // *TODO: minor memory leak here, user data is never deleted (Use real callbacks) motion->setDeactivateCallback(NULL, (void *)NULL); } } destroy(); }
void LLMotionController::refresh_hidden(void) { mHaveVisibleSyncedMotions = !mHidden; // Run over all motions. for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) { LLMotion* motionp = *iter; AISyncServer* server = motionp->server(); if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. { bool visible_after = server->events_with_at_least_one_client_ready() & 4; if (visible_after) // Are there any synchronized motions (left) that ARE visible? { mHaveVisibleSyncedMotions = true; } } } }
//----------------------------------------------------------------------------- // 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; motionp->mActivationTimestamp = (F32)llfloor(motionp->mActivationTimestamp / step) * step; BOOL stopped = motionp->isStopped(); motionp->setStopTime((F32)llfloor(motionp->getStopTime() / step) * step); motionp->setStopped(stopped); motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step; } } }
//----------------------------------------------------------------------------- // onSliderMove() //----------------------------------------------------------------------------- void LLFloaterAnimPreview::onSliderMove() { if (!getEnabled()) return; if (mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getPreviewAvatar(); F32 slider_value = (F32)getChild<LLUICtrl>("playback_slider")->getValue().asReal(); LLUUID base_id = mIDList[getChild<LLUICtrl>("preview_base_anim")->getValue().asString()]; LLMotion* motionp = avatarp->findMotion(mMotionID); F32 duration = motionp->getDuration();// + motionp->getEaseOutDuration(); F32 delta_time = duration * slider_value; avatarp->deactivateAllMotions(); avatarp->startMotion(base_id, delta_time + BASE_ANIM_TIME_OFFSET); avatarp->startMotion(mMotionID, delta_time); mPauseRequest = avatarp->requestPause(); refresh(); } }
//----------------------------------------------------------------------------- // 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->isActive() // singu: do not deprecate motions that are not active. && 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; //<singu> F32 start_time = mAnimTime - start_offset; if (!mDisableSyncing) { start_time = motion->syncActivationTime(start_time); } ++mDisableSyncing; //</singu> BOOL res = activateMotionInstance(motion, start_time); //<singu> --mDisableSyncing; //</singu> return res; }
//----------------------------------------------------------------------------- // 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"); llassert(mDeprecatedMotions.find(motion) == mDeprecatedMotions.end()); // singu: it's impossible that a motion is in mAllMotions and mDeprecatedMotions at the same time. llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl; } //<singu> // Also dump the deprecated motions. for (motion_set_t::iterator iter = mDeprecatedMotions.begin(); iter != mDeprecatedMotions.end(); ++iter) { std::string state_string; LLMotion* motion = *iter; LLUUID id = motion->getID(); llassert(mLoadingMotions.find(motion) == mLoadingMotions.end()); 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"); state_string += "D"; llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl; } //</singu> }
//----------------------------------------------------------------------------- // 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; } } }
//----------------------------------------------------------------------------- // updateMotion() //----------------------------------------------------------------------------- void LLMotionController::updateMotion() { BOOL use_quantum = (mTimeStep != 0.f); // Update timing info for this time step. if (!mPaused) { F32 update_time = mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor); if (use_quantum) { F32 time_interval = fmodf(update_time, mTimeStep); // always animate *ahead* of actual time S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1; if (quantum_count == mTimeStepCount) { // we're still in same time quantum as before, so just interpolate and exit if (!mPaused) { F32 interp = time_interval / mTimeStep; mPoseBlender.interpolate(interp - mLastInterp); mLastInterp = interp; } return; } // is calculating a new keyframe pose, make sure the last one gets applied mPoseBlender.interpolate(1.f); mPoseBlender.clearBlenders(); mTimeStepCount = quantum_count; mLastTime = mTime; mTime = (F32)quantum_count * mTimeStep; mLastInterp = 0.f; } else { mLastTime = mTime; mTime = update_time; } } // query pending motions for completion 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 addLoadedMotion(motionp); // this motion should be playing if (!motionp->isStopped()) { activateMotion(motionp, mTime); } } else if (status == LLMotion::STATUS_FAILURE) { llinfos << "Motion " << motionp->getID() << " init failed." << llendl; sRegistry.markBad(motionp->getID()); mLoadingMotions.erase(curiter); mAllMotions.erase(motionp->getID()); delete motionp; } } resetJointSignatures(); if (!mPaused) { // update additive motions updateAdditiveMotions(); resetJointSignatures(); // update all regular motions updateRegularMotions(); if (use_quantum) { mPoseBlender.blendAndCache(TRUE); } else { mPoseBlender.blendAndApply(); } } mHasRunOnce = TRUE; // llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl; }
// Run all steps until you're either done or hit a wait. void LLGestureMgr::stepGesture(LLMultiGesture* gesture) { if (!gesture) { return; } if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return; // Of the ones that started playing, have any stopped? std::set<LLUUID>::iterator gest_it; for (gest_it = gesture->mPlayingAnimIDs.begin(); gest_it != gesture->mPlayingAnimIDs.end(); ) { if (gesture->mLocal) { // Local, erase if no longer playing (or gone) LLMotion* motion = gAgentAvatarp->findMotion(*gest_it); if (!motion || motion->isStopped()) gesture->mPlayingAnimIDs.erase(gest_it); ++gest_it; } // look in signaled animations (simulator's view of what is // currently playing. else if (gAgentAvatarp->mSignaledAnimations.find(*gest_it) != gAgentAvatarp->mSignaledAnimations.end()) { ++gest_it; } else { // not found, so not currently playing or scheduled to play // delete from the triggered set gesture->mPlayingAnimIDs.erase(gest_it++); } } // Of all the animations that we asked the sim to start for us, // pick up the ones that have actually started. for (gest_it = gesture->mRequestedAnimIDs.begin(); gest_it != gesture->mRequestedAnimIDs.end(); ) { LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); if (play_it != gAgentAvatarp->mSignaledAnimations.end()) { // Hooray, this animation has started playing! // Copy into playing. gesture->mPlayingAnimIDs.insert(*gest_it); gesture->mRequestedAnimIDs.erase(gest_it++); } else { // nope, not playing yet ++gest_it; } } // Run the current steps BOOL waiting = FALSE; while (!waiting && gesture->mPlaying) { // Get the current step, if there is one. // Otherwise enter the waiting at end state. LLGestureStep* step = NULL; if (gesture->mCurrentStep < (S32)gesture->mSteps.size()) { step = gesture->mSteps[gesture->mCurrentStep]; llassert(step != NULL); } else { // step stays null, we're off the end gesture->mWaitingAtEnd = TRUE; } // If we're waiting at the end, wait for all gestures to stop // playing. // TODO: Wait for all sounds to complete as well. if (gesture->mWaitingAtEnd) { // Neither do we have any pending requests, nor are they // still playing. if ((gesture->mRequestedAnimIDs.empty() && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing gesture->mWaitingAtEnd = FALSE; gesture->mPlaying = FALSE; } else { waiting = TRUE; } continue; } // If we're waiting on our animations to stop, poll for // completion. if (gesture->mWaitingAnimations) { // Neither do we have any pending requests, nor are they // still playing. if ((gesture->mRequestedAnimIDs.empty() && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing gesture->mWaitingAnimations = FALSE; gesture->mCurrentStep++; } else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS) { // we've waited too long for an animation LL_INFOS() << "Waited too long for animations to stop, continuing gesture." << LL_ENDL; gesture->mWaitingAnimations = FALSE; gesture->mCurrentStep++; } else { waiting = TRUE; } continue; } // If we're waiting a fixed amount of time, check for timer // expiration. if (gesture->mWaitingTimer) { // We're waiting for a certain amount of time to pass LLGestureStepWait* wait_step = (LLGestureStepWait*)step; F32 elapsed = gesture->mWaitTimer.getElapsedTimeF32(); if (elapsed > wait_step->mWaitSeconds) { // wait is done, continue execution gesture->mWaitingTimer = FALSE; gesture->mCurrentStep++; } else { // we're waiting, so execution is done for now waiting = TRUE; } continue; } // Not waiting, do normal execution runStep(gesture, step); } }
//----------------------------------------------------------------------------- // LLKeyframeMotionParam::onInitialize(LLCharacter *character) //----------------------------------------------------------------------------- LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) { mCharacter = character; if (!loadMotions()) { return STATUS_FAILURE; } for (motion_map_t::iterator iter = mParameterizedMotions.begin(); iter != mParameterizedMotions.end(); ++iter) { motion_list_t& motionList = iter->second; for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) { const ParameterizedMotion& paramMotion = *iter2; LLMotion* motion = paramMotion.mMotion; motion->onInitialize(character); if (motion->getDuration() > mEaseInDuration) { mEaseInDuration = motion->getEaseInDuration(); } if (motion->getEaseOutDuration() > mEaseOutDuration) { mEaseOutDuration = motion->getEaseOutDuration(); } if (motion->getDuration() > mDuration) { mDuration = motion->getDuration(); } if (motion->getPriority() > mPriority) { mPriority = motion->getPriority(); } LLPose *pose = motion->getPose(); mPoseBlender.addMotion(motion); for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) { LLPose *blendedPose = mPoseBlender.getBlendedPose(); blendedPose->addJointState(jsp); } } } return STATUS_SUCCESS; }
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 { LLFastTimer t(FTM_MOTION_ON_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); } }