/** * @file llpolyskeletaldistortion.cpp * @brief Implementation of LLPolySkeletalDistortion classes * * $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 "llpreprocessor.h" #include "llerror.h" #include "llavatarappearance.h" #include "llavatarjoint.h" #include "llpolymorph.h" #include "llwearable.h" #include "llfasttimer.h" #include "llpolyskeletaldistortion.h" //----------------------------------------------------------------------------- // LLPolySkeletalDistortionInfo() //----------------------------------------------------------------------------- LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo() { } BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) { llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) ); if (!LLViewerVisualParamInfo::parseXml(node)) return FALSE; LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton"); if (NULL == skeletalParam) { LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")" << LL_ENDL; return FALSE; } for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() ) { if (bone->hasName("bone")) { std::string name; LLVector3 scale; LLVector3 pos; BOOL haspos = FALSE; static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if (!bone->getFastAttributeString(name_string, name)) { LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL; continue; } static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); if (!bone->getFastAttributeVector3(scale_string, scale)) { LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL; continue; } // optional offset deformation (translation) static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset"); if (bone->getFastAttributeVector3(offset_string, pos)) { haspos = TRUE; } mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos)); } else { LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL; continue; } } return TRUE; } //----------------------------------------------------------------------------- // LLPolySkeletalDistortion() //----------------------------------------------------------------------------- LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp) : LLViewerVisualParam(), mDefaultVec(), mJointScales(), mJointOffsets(), mAvatar(avatarp) { mDefaultVec.splat(0.001f); } //----------------------------------------------------------------------------- // LLPolySkeletalDistortion() //----------------------------------------------------------------------------- LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther) : LLViewerVisualParam(pOther), mDefaultVec(pOther.mDefaultVec), mJointScales(pOther.mJointScales), mJointOffsets(pOther.mJointOffsets), mAvatar(pOther.mAvatar) { } //----------------------------------------------------------------------------- // ~LLPolySkeletalDistortion() //----------------------------------------------------------------------------- LLPolySkeletalDistortion::~LLPolySkeletalDistortion() { } BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight()); LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) { LLPolySkeletalBoneInfo *bone_info = &(*iter); LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); if (!joint) { LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; continue; } if (mJointScales.find(joint) != mJointScales.end()) { LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; } // store it mJointScales[joint] = bone_info->mScaleDeformation; // apply to children that need to inherit it for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); if (child_joint->inheritScale()) { LLVector3 childDeformation = LLVector3(child_joint->getScale()); childDeformation.scaleVec(bone_info->mScaleDeformation); mJointScales[child_joint] = childDeformation; } } if (bone_info->mHasPositionDeformation) { if (mJointOffsets.find(joint) != mJointOffsets.end()) { LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; } mJointOffsets[joint] = bone_info->mPositionDeformation; } } return TRUE; } /*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const { return new LLPolySkeletalDistortion(*this); } //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); iter++) { joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached joint->storeScaleForReset( newScale ); joint->setScale(newScale); } for (iter = mJointOffsets.begin(); iter != mJointOffsets.end(); iter++) { joint = iter->first; LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); joint->setPosition(newPosition); } if (mLastWeight != mCurWeight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } mLastWeight = mCurWeight; } LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, const std::string &name) { LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); cloned_morph_data->mName = name; for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) { cloned_morph_data->mCoords[v] = src_data->mCoords[v]; cloned_morph_data->mNormals[v] = src_data->mNormals[v]; cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]; } return cloned_morph_data; } LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, const LLVector3 &direction, const std::string &name) { LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); cloned_morph_data->mName = name; LLVector4a dir; dir.load3(direction.mV); for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) { cloned_morph_data->mCoords[v] = dir; cloned_morph_data->mNormals[v].clear(); cloned_morph_data->mBinormals[v].clear(); } return cloned_morph_data; } LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, F32 scale, const std::string &name) { LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); cloned_morph_data->mName = name; LLVector4a sc; sc.splat(scale); LLVector4a nsc; nsc.set(scale, -scale, scale, scale); for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) { if (cloned_morph_data->mCoords[v][1] < 0) { cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc); cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc); cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc); } else { cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc); cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc); cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc); } } return cloned_morph_data; } // End