diff options
Diffstat (limited to 'indra/llcharacter/llkeyframemotionparam.cpp')
-rw-r--r-- | indra/llcharacter/llkeyframemotionparam.cpp | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp new file mode 100644 index 0000000000..c57079fc2b --- /dev/null +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -0,0 +1,442 @@ +/** + * @file llkeyframemotionparam.cpp + * @brief Implementation of LLKeyframeMotion class. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llkeyframemotionparam.h" +#include "llcharacter.h" +#include "llmath.h" +#include "m3math.h" +#include "lldir.h" +#include "llanimationstates.h" + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// sortFunc() +//----------------------------------------------------------------------------- +BOOL LLKeyframeMotionParam::sortFunc(ParameterizedMotion *new_motion, ParameterizedMotion *tested_motion) +{ + return (new_motion->second < tested_motion->second); +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id) +{ + mJointStates = NULL; + mDefaultKeyframeMotion = NULL; + mCharacter = NULL; + + mEaseInDuration = 0.f; + mEaseOutDuration = 0.f; + mDuration = 0.f; + mPriority = LLJoint::LOW_PRIORITY; +} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeMotionParam() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeMotionParam::~LLKeyframeMotionParam() +{ + for (U32 i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + delete paramMotion->first; + } + delete motionList; + } + + mParameterizedMotions.removeAll(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + if (!loadMotions()) + { + return STATUS_FAILURE; + } + + for (U32 i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + paramMotion->first->onInitialize(character); + + if (paramMotion->first->getDuration() > mEaseInDuration) + { + mEaseInDuration = paramMotion->first->getEaseInDuration(); + } + + if (paramMotion->first->getEaseOutDuration() > mEaseOutDuration) + { + mEaseOutDuration = paramMotion->first->getEaseOutDuration(); + } + + if (paramMotion->first->getDuration() > mDuration) + { + mDuration = paramMotion->first->getDuration(); + } + + if (paramMotion->first->getPriority() > mPriority) + { + mPriority = paramMotion->first->getPriority(); + } + + LLPose *pose = paramMotion->first->getPose(); + + mPoseBlender.addMotion(paramMotion->first); + for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) + { + LLPose *blendedPose = mPoseBlender.getBlendedPose(); + blendedPose->addJointState(jsp); + } + } + } + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onActivate() +//----------------------------------------------------------------------------- +BOOL LLKeyframeMotionParam::onActivate() +{ + for (U32 i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + paramMotion->first->activate(); + } + } + return TRUE; +} + + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onUpdate() +//----------------------------------------------------------------------------- +BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) +{ + F32 weightFactor = 1.f / (F32)mParameterizedMotions.length(); + U32 i; + + // zero out all pose weights + for (i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { +// llinfos << "Weight for pose " << paramMotion->first->getName() << " is " << paramMotion->first->getPose()->getWeight() << llendl; + paramMotion->first->getPose()->setWeight(0.f); + } + } + + + for (i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + std::string *paramName = mParameterizedMotions.getIndexAt(i); + F32* paramValue = (F32 *)mCharacter->getAnimationData(*paramName); + ParameterizedMotion* firstMotion = NULL; + ParameterizedMotion* secondMotion = NULL; + + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + paramMotion->first->onUpdate(time, joint_mask); + + F32 distToParam = paramMotion->second - *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->first->getPose(); + else + firstPose = NULL; + + if (secondMotion) + secondPose = secondMotion->first->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->second == secondMotion->second) + { + firstPose->setWeight(0.5f * weightFactor); + secondPose->setWeight(0.5f * weightFactor); + } + else + { + F32 first_weight = 1.f - + ((llclamp(*paramValue - firstMotion->second, 0.f, (secondMotion->second - firstMotion->second))) / + (secondMotion->second - firstMotion->second)); + 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; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onDeactivate() +//----------------------------------------------------------------------------- +void LLKeyframeMotionParam::onDeactivate() +{ + for (U32 i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + paramMotion->first->onDeactivate(); + } + } +} + +//----------------------------------------------------------------------------- +// 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); + + // make sure a list of motions exists for this parameter + LLLinkedList< ParameterizedMotion > *motionList; + if (mParameterizedMotions.getValue(param)) + { + motionList = *mParameterizedMotions.getValue(param); + } + else + { + motionList = new LLLinkedList< ParameterizedMotion >; + motionList->setInsertBefore(sortFunc); + mParameterizedMotions.addToHead(param, motionList); + } + + // now add motion to this list + ParameterizedMotion *parameterizedMotion = new ParameterizedMotion(newMotion, value); + + motionList->addDataSorted(parameterizedMotion); + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::setDefaultKeyframeMotion() +//----------------------------------------------------------------------------- +void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name) +{ + for (U32 i = 0; i < mParameterizedMotions.length(); i++) + { + LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i); + for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData()) + { + if (paramMotion->first->getName() == name) + { + mDefaultKeyframeMotion = paramMotion->first; + } + } + } +} + +//----------------------------------------------------------------------------- +// loadMotions() +//----------------------------------------------------------------------------- +BOOL LLKeyframeMotionParam::loadMotions() +{ + //------------------------------------------------------------------------- + // Load named file by concatenating the character prefix with the motion name. + // Load data into a buffer to be parsed. + //------------------------------------------------------------------------- + char path[LL_MAX_PATH]; /* Flawfinder: ignore */ + snprintf( path, sizeof(path), "%s_%s.llp", + gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()).c_str(), + getName().c_str() ); /* Flawfinder: ignore */ + + //------------------------------------------------------------------------- + // open the file + //------------------------------------------------------------------------- + S32 fileSize = 0; + apr_file_t* fp = ll_apr_file_open(path, LL_APR_R, &fileSize); + if (!fp || fileSize == 0) + { + llinfos << "ERROR: can't open: " << path << llendl; + return FALSE; + } + + // allocate a text buffer + char *text = new char[ fileSize+1 ]; + if ( !text ) + { + llinfos << "ERROR: can't allocated keyframe text buffer." << llendl; + apr_file_close(fp); + return FALSE; + } + + //------------------------------------------------------------------------- + // load data from file into buffer + //------------------------------------------------------------------------- + bool error = false; + char *p = text; + while ( 1 ) + { + if (apr_file_eof(fp) == APR_EOF) + { + break; + } + if (apr_file_gets(p, 1024, fp) != APR_SUCCESS) + { + error = true; + break; + } + while ( *(++p) ) + ; + } + + //------------------------------------------------------------------------- + // close the file + //------------------------------------------------------------------------- + apr_file_close( fp ); + + //------------------------------------------------------------------------- + // check for error + //------------------------------------------------------------------------- + llassert( p <= (text+fileSize) ); + + if ( error ) + { + llinfos << "ERROR: error while reading from " << path << llendl; + delete [] text; + return FALSE; + } + + llinfos << "Loading parametric keyframe data for: " << getName() << llendl; + + //------------------------------------------------------------------------- + // parse the text and build keyframe data structures + //------------------------------------------------------------------------- + p = text; + S32 num; + char strA[80]; /* Flawfinder: ignore */ + char strB[80]; /* Flawfinder: ignore */ + F32 floatA = 0.0f; + + + //------------------------------------------------------------------------- + // get priority + //------------------------------------------------------------------------- + BOOL isFirstMotion = TRUE; + num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); + + while(1) + { + if (num == 0 || num == EOF) break; + if ((num != 3)) + { + llinfos << "WARNING: can't read parametric motion" << llendl; + delete [] text; + return FALSE; + } + + addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(strA), strB, floatA); + if (isFirstMotion) + { + isFirstMotion = FALSE; + setDefaultKeyframeMotion(strA); + } + + p = strstr(p, "\n"); + if (!p) + { + break; + } + + p++; + num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); + } + + delete [] text; + return TRUE; +} + +// End |