예제 #1
0
//-----------------------------------------------------------------------------
// deactivateMotion()
//-----------------------------------------------------------------------------
BOOL LLMotionController::deactivateMotion(LLMotion *motion, bool remove_weight)
{
	if( remove_weight )
	{
		// immediately remove pose weighting instead of letting it time out
		LLPose *posep = motion->getPose();
		posep->setWeight(0.f);
	}
	
	motion->deactivate();
	mActiveMotions.remove(motion);

	return TRUE;
}
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);
	}
}
//-----------------------------------------------------------------------------
// LLKeyframeMotionParam::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
{
	F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();

	// zero out all pose weights
	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;
//			llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl;
			paramMotion.mMotion->getPose()->setWeight(0.f);
		}
	}


	for (motion_map_t::iterator iter = mParameterizedMotions.begin();
		 iter != mParameterizedMotions.end(); ++iter)
	{
		const std::string& paramName = iter->first;
		F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName);
		if (NULL == paramValue) // unexpected, but...
		{
			llwarns << "paramValue == NULL" << llendl;
			continue;
		}

		// DANGER! Do not modify mParameterizedMotions while using these pointers!
		const ParameterizedMotion* firstMotion = NULL;
		const ParameterizedMotion* secondMotion = NULL;

		motion_list_t& motionList = iter->second;
		for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
		{
			const ParameterizedMotion& paramMotion = *iter2;
			paramMotion.mMotion->onUpdate(time, joint_mask);
			
			F32 distToParam = paramMotion.mParam - *paramValue;
			
			if ( distToParam <= 0.f)
			{
				// keep track of the motion closest to the parameter value
				firstMotion = &paramMotion;
			}
			else
			{
				// we've passed the parameter value
				// so store the first motion we find as the second one we want to blend...
				if (firstMotion && !secondMotion )
				{
					secondMotion = &paramMotion;
				}
				//...or, if we've seen no other motion so far, make sure we blend to this only
				else if (!firstMotion)
				{
					firstMotion = &paramMotion;
					secondMotion = &paramMotion;
				}
			}
		}

		LLPose *firstPose;
		LLPose *secondPose;

		if (firstMotion)
			firstPose = firstMotion->mMotion->getPose();
		else
			firstPose = NULL;

		if (secondMotion)
			secondPose = secondMotion->mMotion->getPose();
		else
			secondPose = NULL;
		
		// now modify weight of the subanim (only if we are blending between two motions)
		if (firstMotion && secondMotion)
		{
			if (firstMotion == secondMotion)
			{
				firstPose->setWeight(weightFactor);
			}
			else if (firstMotion->mParam == secondMotion->mParam)
			{
				firstPose->setWeight(0.5f * weightFactor);
				secondPose->setWeight(0.5f * weightFactor);
			}
			else
			{
				F32 first_weight = 1.f - 
					((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / 
						(secondMotion->mParam - firstMotion->mParam));
				first_weight = llclamp(first_weight, 0.f, 1.f);
				
				F32 second_weight = 1.f - first_weight;
				
				firstPose->setWeight(first_weight * weightFactor);
				secondPose->setWeight(second_weight * weightFactor);

//				llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl;
//				llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl;
			}
		}
		else if (firstMotion && !secondMotion)
		{
			firstPose->setWeight(weightFactor);
		}
	}

	// blend poses
	mPoseBlender.blendAndApply();

	llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl;

	return TRUE;
}