diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llappearance/llavatarappearance.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/llappearance/llavatarappearance.cpp')
-rw-r--r-- | indra/llappearance/llavatarappearance.cpp | 4187 |
1 files changed, 2081 insertions, 2106 deletions
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index b46edf573c..ed023c670b 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1,2106 +1,2081 @@ -/** - * @File llavatarappearance.cpp - * @brief Implementation of LLAvatarAppearance class - * - * $LicenseInfo:firstyear=2012&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$ - */ - -#include "linden_common.h" - -#include "llavatarappearance.h" -#include "llavatarappearancedefines.h" -#include "llavatarjointmesh.h" -#include "llstl.h" -#include "lldir.h" -#include "llpolymorph.h" -#include "llpolymesh.h" -#include "llpolyskeletaldistortion.h" -#include "llstl.h" -#include "lltexglobalcolor.h" -#include "llwearabledata.h" -#include "boost/bind.hpp" -#include "boost/tokenizer.hpp" - -using namespace LLAvatarAppearanceDefines; - -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - -const std::string AVATAR_DEFAULT_CHAR = "avatar"; -const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); - -/********************************************************************************* - ** ** - ** Begin private LLAvatarAppearance Support classes - ** - **/ - -//------------------------------------------------------------------------ -// LLAvatarBoneInfo -// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton. -//------------------------------------------------------------------------ -class LLAvatarBoneInfo -{ - friend class LLAvatarAppearance; - friend class LLAvatarSkeletonInfo; -public: - LLAvatarBoneInfo() : mIsJoint(false) {} - ~LLAvatarBoneInfo() - { - std::for_each(mChildren.begin(), mChildren.end(), DeletePointer()); - mChildren.clear(); - } - bool parseXml(LLXmlTreeNode* node); - -private: - std::string mName; - std::string mSupport; - std::string mAliases; - bool mIsJoint; - LLVector3 mPos; - LLVector3 mEnd; - LLVector3 mRot; - LLVector3 mScale; - LLVector3 mPivot; - typedef std::vector<LLAvatarBoneInfo*> bones_t; - bones_t mChildren; -}; - -//------------------------------------------------------------------------ -// LLAvatarSkeletonInfo -// Overall avatar skeleton -//------------------------------------------------------------------------ -class LLAvatarSkeletonInfo -{ - friend class LLAvatarAppearance; -public: - LLAvatarSkeletonInfo() : - mNumBones(0), mNumCollisionVolumes(0) {} - ~LLAvatarSkeletonInfo() - { - std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer()); - mBoneInfoList.clear(); - } - bool parseXml(LLXmlTreeNode* node); - S32 getNumBones() const { return mNumBones; } - S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; } - -private: - S32 mNumBones; - S32 mNumCollisionVolumes; - LLAvatarAppearance::joint_alias_map_t mJointAliasMap; - typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t; - bone_info_list_t mBoneInfoList; -}; - -//----------------------------------------------------------------------------- -// LLAvatarXmlInfo -//----------------------------------------------------------------------------- - -LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo() - : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0) -{ -} - -LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo() -{ - std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); - mMeshInfoList.clear(); - - std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); - mSkeletalDistortionInfoList.clear(); - - std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); - mAttachmentInfoList.clear(); - - delete_and_clear(mTexSkinColorInfo); - delete_and_clear(mTexHairColorInfo); - delete_and_clear(mTexEyeColorInfo); - - std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); - mLayerInfoList.clear(); - - std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); - mDriverInfoList.clear(); - - std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); - mMorphMaskInfoList.clear(); -} - - -/** - ** - ** End LLAvatarAppearance Support classes - ** ** - *********************************************************************************/ - -//----------------------------------------------------------------------------- -// Static Data -//----------------------------------------------------------------------------- -LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL; -LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL; -LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* LLAvatarAppearance::sAvatarDictionary = NULL; - - -LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : - LLCharacter(), - mIsDummy(false), - mTexSkinColor( NULL ), - mTexHairColor( NULL ), - mTexEyeColor( NULL ), - mPelvisToFoot(0.f), - mHeadOffset(), - mRoot(NULL), - mWearableData(wearable_data), - mNumBones(0), - mNumCollisionVolumes(0), - mCollisionVolumes(NULL), - mIsBuilt(false), - mInitFlags(0) -{ - llassert_always(mWearableData); - mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); - for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) - { - mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR; - mBakedTextureDatas[i].mTexLayerSet = NULL; - mBakedTextureDatas[i].mIsLoaded = false; - mBakedTextureDatas[i].mIsUsed = false; - mBakedTextureDatas[i].mMaskTexName = 0; - mBakedTextureDatas[i].mTextureIndex = sAvatarDictionary->bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); - } -} - -// virtual -void LLAvatarAppearance::initInstance() -{ - //------------------------------------------------------------------------- - // initialize joint, mesh and shape members - //------------------------------------------------------------------------- - mRoot = createAvatarJoint(); - mRoot->setName( "mRoot" ); - - for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries()) - { - const EMeshIndex mesh_index = mesh_pair.first; - const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second; - LLAvatarJoint* joint = createAvatarJoint(); - joint->setName(mesh_dict->mName); - joint->setMeshID(mesh_index); - mMeshLOD.push_back(joint); - - /* mHairLOD.setName("mHairLOD"); - mHairMesh0.setName("mHairMesh0"); - mHairMesh0.setMeshID(MESH_ID_HAIR); - mHairMesh1.setName("mHairMesh1"); */ - for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) - { - LLAvatarJointMesh* mesh = createAvatarJointMesh(); - std::string mesh_name = "m" + mesh_dict->mName + std::to_string(lod); - // We pre-pended an m - need to capitalize first character for camelCase - mesh_name[1] = toupper(mesh_name[1]); - mesh->setName(mesh_name); - mesh->setMeshID(mesh_index); - mesh->setPickName(mesh_dict->mPickName); - mesh->setIsTransparent(false); - switch((S32)mesh_index) - { - case MESH_ID_HAIR: - mesh->setIsTransparent(true); - break; - case MESH_ID_SKIRT: - mesh->setIsTransparent(true); - break; - case MESH_ID_EYEBALL_LEFT: - case MESH_ID_EYEBALL_RIGHT: - mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); - break; - } - - joint->mMeshParts.push_back(mesh); - } - } - - //------------------------------------------------------------------------- - // associate baked textures with meshes - //------------------------------------------------------------------------- - for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries()) - { - const EMeshIndex mesh_index = mesh_pair.first; - const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second; - const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; - // Skip it if there's no associated baked texture. - if (baked_texture_index == BAKED_NUM_INDICES) continue; - - for (LLAvatarJointMesh* mesh : mMeshLOD[mesh_index]->mMeshParts) - { - mBakedTextureDatas[(S32)baked_texture_index].mJointMeshes.push_back(mesh); - } - } - - buildCharacter(); - - mInitFlags |= 1<<0; - -} - -// virtual -LLAvatarAppearance::~LLAvatarAppearance() -{ - delete_and_clear(mTexSkinColor); - delete_and_clear(mTexHairColor); - delete_and_clear(mTexEyeColor); - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - delete_and_clear(mBakedTextureDatas[i].mTexLayerSet); - mBakedTextureDatas[i].mJointMeshes.clear(); - - for (LLMaskedMorph* masked_morph : mBakedTextureDatas[i].mMaskedMorphs) - { - delete masked_morph; - } - } - - if (mRoot) - { - mRoot->removeAllChildren(); - delete mRoot; - mRoot = nullptr; - } - mJointMap.clear(); - - clearSkeleton(); - delete_and_clear_array(mCollisionVolumes); - - std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer()); - mPolyMeshes.clear(); - - for (LLAvatarJoint* joint : mMeshLOD) - { - std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); - joint->mMeshParts.clear(); - } - std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer()); - mMeshLOD.clear(); -} - -//static -void LLAvatarAppearance::initClass() -{ - initClass("",""); -} - -//static -void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg) -{ - // init dictionary (don't repeat on second login attempt) - if (!sAvatarDictionary) - { - sAvatarDictionary = new LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary(); - } - - std::string avatar_file_name; - - if (!avatar_file_name_arg.empty()) - { - avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg); - } - else - { - avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml"); - } - LLXmlTree xml_tree; - bool success = xml_tree.parseFile( avatar_file_name, false ); - if (!success) - { - LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL; - } - - // now sanity check xml file - LLXmlTreeNode* root = xml_tree.getRoot(); - if (!root) - { - LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL; - return; - } - - //------------------------------------------------------------------------- - // <linden_avatar version="2.0"> (root) - //------------------------------------------------------------------------- - if( !root->hasName( "linden_avatar" ) ) - { - LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL; - } - - std::string version; - static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) - { - LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL; - } - - S32 wearable_def_version = 1; - static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version"); - root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version ); - LLWearable::setCurrentDefinitionVersion( wearable_def_version ); - - std::string mesh_file_name; - - LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); - if (!skeleton_node) - { - LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL; - return; - } - - std::string skeleton_file_name = skeleton_file_name_arg; - if (skeleton_file_name.empty()) - { - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) - { - LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL; - } - } - - std::string skeleton_path; - LLXmlTree skeleton_xml_tree; - skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); - if (!parseSkeletonFile(skeleton_path, skeleton_xml_tree)) - { - LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL; - } - - // Process XML data - - // avatar_skeleton.xml - if (sAvatarSkeletonInfo) - { //this can happen if a login attempt failed - delete sAvatarSkeletonInfo; - } - sAvatarSkeletonInfo = new LLAvatarSkeletonInfo; - if (!sAvatarSkeletonInfo->parseXml(skeleton_xml_tree.getRoot())) - { - LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL; - } - // parse avatar_lad.xml - if (sAvatarXmlInfo) - { //this can happen if a login attempt failed - delete_and_clear(sAvatarXmlInfo); - } - sAvatarXmlInfo = new LLAvatarXmlInfo; - if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } - if (!sAvatarXmlInfo->parseXmlMeshNodes(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } - if (!sAvatarXmlInfo->parseXmlColorNodes(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } - if (!sAvatarXmlInfo->parseXmlLayerNodes(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } - if (!sAvatarXmlInfo->parseXmlDriverNodes(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } - if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) - { - LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; - } -} - -void LLAvatarAppearance::cleanupClass() -{ - delete_and_clear(sAvatarXmlInfo); - delete_and_clear(sAvatarDictionary); - delete_and_clear(sAvatarSkeletonInfo); -} - -using namespace LLAvatarAppearanceDefines; - -void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state, - joint_state_map_t& curr_state) -{ - if (!last_state.empty() && (last_state != curr_state)) - { - S32 diff_count = 0; - for (joint_state_map_t::value_type& pair : last_state) - { - const std::string& key = pair.first; - if (last_state[key] != curr_state[key]) - { - LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL; - diff_count++; - } - } - if (diff_count > 0) - { - LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL; - } - - } -} - -//------------------------------------------------------------------------ -// The viewer can only suggest a good size for the agent, -// the simulator will keep it inside a reasonable range. -void LLAvatarAppearance::computeBodySize() -{ - mLastBodySizeState = mCurrBodySizeState; - - mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale(); - mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition(); - mCurrBodySizeState["mSkull scale"] = mSkullp->getScale(); - mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition(); - mCurrBodySizeState["mNeck scale"] = mNeckp->getScale(); - mCurrBodySizeState["mChest pos"] = mChestp->getPosition(); - mCurrBodySizeState["mChest scale"] = mChestp->getScale(); - mCurrBodySizeState["mHead pos"] = mHeadp->getPosition(); - mCurrBodySizeState["mHead scale"] = mHeadp->getScale(); - mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition(); - mCurrBodySizeState["mTorso scale"] = mTorsop->getScale(); - mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition(); - mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale(); - mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition(); - mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale(); - mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition(); - mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale(); - mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition(); - - LLVector3 pelvis_scale = mPelvisp->getScale(); - - // some of the joints have not been cached - LLVector3 skull = mSkullp->getPosition(); - //LLVector3 skull_scale = mSkullp->getScale(); - - LLVector3 neck = mNeckp->getPosition(); - LLVector3 neck_scale = mNeckp->getScale(); - - LLVector3 chest = mChestp->getPosition(); - LLVector3 chest_scale = mChestp->getScale(); - - // the rest of the joints have been cached - LLVector3 head = mHeadp->getPosition(); - LLVector3 head_scale = mHeadp->getScale(); - - LLVector3 torso = mTorsop->getPosition(); - LLVector3 torso_scale = mTorsop->getScale(); - - LLVector3 hip = mHipLeftp->getPosition(); - LLVector3 hip_scale = mHipLeftp->getScale(); - - LLVector3 knee = mKneeLeftp->getPosition(); - LLVector3 knee_scale = mKneeLeftp->getScale(); - - LLVector3 ankle = mAnkleLeftp->getPosition(); - LLVector3 ankle_scale = mAnkleLeftp->getScale(); - - LLVector3 foot = mFootLeftp->getPosition(); - - F32 old_offset = mAvatarOffset.mV[VZ]; - - mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER); - - mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - - knee.mV[VZ] * hip_scale.mV[VZ] - - ankle.mV[VZ] * knee_scale.mV[VZ] - - foot.mV[VZ] * ankle_scale.mV[VZ]; - - LLVector3 new_body_size; - new_body_size.mV[VZ] = mPelvisToFoot + - // the sqrt(2) correction below is an approximate - // correction to get to the top of the head - F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + - head.mV[VZ] * neck_scale.mV[VZ] + - neck.mV[VZ] * chest_scale.mV[VZ] + - chest.mV[VZ] * torso_scale.mV[VZ] + - torso.mV[VZ] * pelvis_scale.mV[VZ]; - - // TODO -- measure the real depth and width - new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; - new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; - - mAvatarOffset.mV[VX] = 0.0f; - mAvatarOffset.mV[VY] = 0.0f; - - if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) - { - mBodySize = new_body_size; - - compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); - } -} - -//----------------------------------------------------------------------------- -// parseSkeletonFile() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree) -{ - //------------------------------------------------------------------------- - // parse the file - //------------------------------------------------------------------------- - bool parsesuccess = skeleton_xml_tree.parseFile( filename, false ); - - if (!parsesuccess) - { - LL_ERRS() << "Can't parse skeleton file: " << filename << LL_ENDL; - return false; - } - - // now sanity check xml file - LLXmlTreeNode* root = skeleton_xml_tree.getRoot(); - if (!root) - { - LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL; - return false; - } - - if( !root->hasName( "linden_skeleton" ) ) - { - LL_ERRS() << "Invalid avatar skeleton file header: " << filename << LL_ENDL; - return false; - } - - std::string version; - static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) - { - LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL; - return false; - } - - return true; -} - -//----------------------------------------------------------------------------- -// setupBone() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num) -{ - LLJoint* joint = NULL; - - LL_DEBUGS("BVH") << "bone info: name " << info->mName - << " isJoint " << info->mIsJoint - << " volume_num " << volume_num - << " joint_num " << joint_num - << LL_ENDL; - - if (info->mIsJoint) - { - joint = getCharacterJoint(joint_num); - if (!joint) - { - LL_WARNS() << "Too many bones" << LL_ENDL; - return false; - } - joint->setName( info->mName ); - } - else // collision volume - { - if (volume_num >= (S32)mNumCollisionVolumes) - { - LL_WARNS() << "Too many collision volumes" << LL_ENDL; - return false; - } - joint = (&mCollisionVolumes[volume_num]); - joint->setName( info->mName ); - } - - // add to parent - if (parent && (joint->getParent()!=parent)) - { - parent->addChild( joint ); - } - - // SL-315 - joint->setPosition(info->mPos); - joint->setDefaultPosition(info->mPos); - joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], - info->mRot.mV[VZ], LLQuaternion::XYZ)); - joint->setScale(info->mScale); - joint->setDefaultScale(info->mScale); - joint->setSupport(info->mSupport); - joint->setEnd(info->mEnd); - - if (info->mIsJoint) - { - joint->setSkinOffset( info->mPivot ); - joint->setJointNum(joint_num); - joint_num++; - } - else // collision volume - { - joint->setJointNum(mNumBones+volume_num); - volume_num++; - } - - - // setup children - for (LLAvatarBoneInfo* child_info : info->mChildren) - { - if (!setupBone(child_info, joint, volume_num, joint_num)) - { - return false; - } - } - - return true; -} - -//----------------------------------------------------------------------------- -// allocateCharacterJoints() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::allocateCharacterJoints( U32 num ) -{ - if (mSkeleton.size() != num) - { - clearSkeleton(); - mSkeleton = avatar_joint_list_t(num,NULL); - mNumBones = num; - } - - return true; -} - - -//----------------------------------------------------------------------------- -// buildSkeleton() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) -{ - LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL; - - // allocate joints - if (!allocateCharacterJoints(info->mNumBones)) - { - LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL; - return false; - } - - // allocate volumes - if (info->mNumCollisionVolumes) - { - if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) - { - LL_ERRS() << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << LL_ENDL; - return false; - } - } - - S32 current_joint_num = 0; - S32 current_volume_num = 0; - for (LLAvatarBoneInfo* bone_info : info->mBoneInfoList) - { - if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num)) - { - LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL; - return false; - } - } - - return true; -} - -//----------------------------------------------------------------------------- -// clearSkeleton() -//----------------------------------------------------------------------------- -void LLAvatarAppearance::clearSkeleton() -{ - std::for_each(mSkeleton.begin(), mSkeleton.end(), DeletePointer()); - mSkeleton.clear(); -} - -//------------------------------------------------------------------------ -// addPelvisFixup -//------------------------------------------------------------------------ -void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id ) -{ - LLVector3 pos(0.0,0.0,fixup); - mPelvisFixups.add(mesh_id,pos); -} - -//------------------------------------------------------------------------ -// addPelvisFixup -//------------------------------------------------------------------------ -void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id ) -{ - mPelvisFixups.remove(mesh_id); -} - -//------------------------------------------------------------------------ -// hasPelvisFixup -//------------------------------------------------------------------------ -bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const -{ - LLVector3 pos; - if (mPelvisFixups.findActiveOverride(mesh_id,pos)) - { - fixup = pos[2]; - return true; - } - return false; -} - -bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const -{ - LLUUID mesh_id; - return hasPelvisFixup( fixup, mesh_id ); -} -//----------------------------------------------------------------------------- -// LLAvatarAppearance::buildCharacter() -// Deferred initialization and rebuild of the avatar. -//----------------------------------------------------------------------------- -void LLAvatarAppearance::buildCharacter() -{ - //------------------------------------------------------------------------- - // remove all references to our existing skeleton - // so we can rebuild it - //------------------------------------------------------------------------- - flushAllMotions(); - - //------------------------------------------------------------------------- - // remove all of mRoot's children - //------------------------------------------------------------------------- - mRoot->removeAllChildren(); - mJointMap.clear(); - mIsBuilt = false; - - //------------------------------------------------------------------------- - // clear mesh data - //------------------------------------------------------------------------- - for (LLAvatarJoint* joint : mMeshLOD) - { - for (LLAvatarJointMesh* mesh : joint->mMeshParts) - { - mesh->setMesh(NULL); - } - } - - //------------------------------------------------------------------------- - // (re)load our skeleton and meshes - //------------------------------------------------------------------------- - LLTimer timer; - - bool status = loadAvatar(); - stop_glerror(); - -// gPrintMessagesThisFrame = true; - LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL; - - if (!status) - { - if (isSelf()) - { - LL_ERRS() << "Unable to load user's avatar" << LL_ENDL; - } - else - { - LL_WARNS() << "Unable to load other's avatar" << LL_ENDL; - } - return; - } - - //------------------------------------------------------------------------- - // initialize "well known" joint pointers - //------------------------------------------------------------------------- - mPelvisp = mRoot->findJoint("mPelvis"); - mTorsop = mRoot->findJoint("mTorso"); - mChestp = mRoot->findJoint("mChest"); - mNeckp = mRoot->findJoint("mNeck"); - mHeadp = mRoot->findJoint("mHead"); - mSkullp = mRoot->findJoint("mSkull"); - mHipLeftp = mRoot->findJoint("mHipLeft"); - mHipRightp = mRoot->findJoint("mHipRight"); - mKneeLeftp = mRoot->findJoint("mKneeLeft"); - mKneeRightp = mRoot->findJoint("mKneeRight"); - mAnkleLeftp = mRoot->findJoint("mAnkleLeft"); - mAnkleRightp = mRoot->findJoint("mAnkleRight"); - mFootLeftp = mRoot->findJoint("mFootLeft"); - mFootRightp = mRoot->findJoint("mFootRight"); - mWristLeftp = mRoot->findJoint("mWristLeft"); - mWristRightp = mRoot->findJoint("mWristRight"); - mEyeLeftp = mRoot->findJoint("mEyeLeft"); - mEyeRightp = mRoot->findJoint("mEyeRight"); - - //------------------------------------------------------------------------- - // Make sure "well known" pointers exist - //------------------------------------------------------------------------- - if (!(mPelvisp && - mTorsop && - mChestp && - mNeckp && - mHeadp && - mSkullp && - mHipLeftp && - mHipRightp && - mKneeLeftp && - mKneeRightp && - mAnkleLeftp && - mAnkleRightp && - mFootLeftp && - mFootRightp && - mWristLeftp && - mWristRightp && - mEyeLeftp && - mEyeRightp)) - { - LL_ERRS() << "Failed to create avatar." << LL_ENDL; - return; - } - - //------------------------------------------------------------------------- - // initialize the pelvis - //------------------------------------------------------------------------- - // SL-315 - mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); - - mIsBuilt = true; - stop_glerror(); - -} - -bool LLAvatarAppearance::loadAvatar() -{ -// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR); - - // avatar_skeleton.xml - if( !buildSkeleton(sAvatarSkeletonInfo) ) - { - LL_ERRS() << "avatar file: buildSkeleton() failed" << LL_ENDL; - return false; - } - - // initialize mJointAliasMap - getJointAliases(); - - // avatar_lad.xml : <skeleton> - if( !loadSkeletonNode() ) - { - LL_ERRS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL; - return false; - } - - // avatar_lad.xml : <mesh> - if( !loadMeshNodes() ) - { - LL_ERRS() << "avatar file: loadNodeMesh() failed" << LL_ENDL; - return false; - } - - // avatar_lad.xml : <global_color> - if( sAvatarXmlInfo->mTexSkinColorInfo ) - { - mTexSkinColor = new LLTexGlobalColor( this ); - if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) - { - LL_ERRS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL; - return false; - } - } - else - { - LL_ERRS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL; - return false; - } - if( sAvatarXmlInfo->mTexHairColorInfo ) - { - mTexHairColor = new LLTexGlobalColor( this ); - if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) - { - LL_ERRS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL; - return false; - } - } - else - { - LL_ERRS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL; - return false; - } - if( sAvatarXmlInfo->mTexEyeColorInfo ) - { - mTexEyeColor = new LLTexGlobalColor( this ); - if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) - { - LL_ERRS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL; - return false; - } - } - else - { - LL_ERRS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL; - return false; - } - - // avatar_lad.xml : <layer_set> - if (sAvatarXmlInfo->mLayerInfoList.empty()) - { - LL_ERRS() << "avatar file: missing <layer_set> node" << LL_ENDL; - return false; - } - - if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) - { - LL_ERRS() << "avatar file: missing <morph_masks> node" << LL_ENDL; - return false; - } - - // avatar_lad.xml : <morph_masks> - for (LLAvatarXmlInfo::LLAvatarMorphInfo* info : sAvatarXmlInfo->mMorphMaskInfoList) - { - EBakedTextureIndex baked = sAvatarDictionary->findBakedByRegionName(info->mRegion); - if (baked != BAKED_NUM_INDICES) - { - LLVisualParam* morph_param; - const std::string *name = &info->mName; - morph_param = getVisualParam(name->c_str()); - if (morph_param) - { - bool invert = info->mInvert; - addMaskedMorph(baked, morph_param, invert, info->mLayer); - } - } - - } - - loadLayersets(); - - // avatar_lad.xml : <driver_parameters> - for (LLDriverParamInfo* info : sAvatarXmlInfo->mDriverInfoList) - { - LLDriverParam* driver_param = new LLDriverParam( this ); - if (driver_param->setInfo(info)) - { - addVisualParam( driver_param ); - driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); - LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam; - if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false)) - { - LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL; - continue; - } - } - else - { - delete driver_param; - LL_WARNS() << "avatar file: driver_param->parseData() failed" << LL_ENDL; - return false; - } - } - - return true; -} - -//----------------------------------------------------------------------------- -// loadSkeletonNode(): loads <skeleton> node from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::loadSkeletonNode () -{ - mRoot->addChild( mSkeleton[0] ); - - // make meshes children before calling parent version of the function - for (LLAvatarJoint* joint : mMeshLOD) - { - joint->mUpdateXform = false; - joint->setMeshesToChildren(); - } - - mRoot->addChild(mMeshLOD[MESH_ID_HEAD]); - mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]); - mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]); - mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]); - mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]); - - LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull"); - if (skull) - { - skull->addChild(mMeshLOD[MESH_ID_HAIR] ); - } - - LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft"); - if (eyeL) - { - eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] ); - } - - LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight"); - if (eyeR) - { - eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] ); - } - - // SKELETAL DISTORTIONS - { - for (LLViewerVisualParamInfo* visual_param_info : sAvatarXmlInfo->mSkeletalDistortionInfoList) - { - LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)visual_param_info; - LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this); - if (!param->setInfo(info)) - { - delete param; - return false; - } - else - { - addVisualParam(param); - param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); - } - } - } - - - return true; -} - -//----------------------------------------------------------------------------- -// loadMeshNodes(): loads <mesh> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::loadMeshNodes() -{ - for (const LLAvatarXmlInfo::LLAvatarMeshInfo* info : sAvatarXmlInfo->mMeshInfoList) - { - const std::string &type = info->mType; - S32 lod = info->mLOD; - - LLAvatarJointMesh* mesh = NULL; - U8 mesh_id = 0; - bool found_mesh_id = false; - - /* if (type == "hairMesh") - switch(lod) - case 0: - mesh = &mHairMesh0; */ - for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries()) - { - const EMeshIndex mesh_index = mesh_pair.first; - const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second; - if (type.compare(mesh_dict->mName) == 0) - { - mesh_id = mesh_index; - found_mesh_id = true; - break; - } - } - - if (found_mesh_id) - { - if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size()) - { - mesh = mMeshLOD[mesh_id]->mMeshParts[lod]; - } - else - { - LL_WARNS() << "Avatar file: <mesh> has invalid lod setting " << lod << LL_ENDL; - return false; - } - } - else - { - LL_WARNS() << "Ignoring unrecognized mesh type: " << type << LL_ENDL; - return false; - } - - // LL_INFOS() << "Parsing mesh data for " << type << "..." << LL_ENDL; - - // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings. - // Do not touch!!! - mesh->setColor( LLColor4::white ); - - LLPolyMesh *poly_mesh = NULL; - - if (!info->mReferenceMeshName.empty()) - { - polymesh_map_t::const_iterator polymesh_iter = mPolyMeshes.find(info->mReferenceMeshName); - if (polymesh_iter != mPolyMeshes.end()) - { - poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second); - poly_mesh->setAvatar(this); - } - else - { - // This should never happen - LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; - return false; - } - } - else - { - poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName); - poly_mesh->setAvatar(this); - } - - if( !poly_mesh ) - { - LL_WARNS() << "Failed to load mesh of type " << type << LL_ENDL; - return false; - } - - // Multimap insert - mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); - - mesh->setMesh( poly_mesh ); - mesh->setLOD( info->mMinPixelArea ); - - for (const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t& info_pair : info->mPolyMorphTargetInfoList) - { - LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh()); - if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair.first)) - { - delete param; - return false; - } - else - { - if (info_pair.second) - { - addSharedVisualParam(param); - param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); - } - else - { - addVisualParam(param); - param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); - } - } - } - } - - return true; -} - -//----------------------------------------------------------------------------- -// loadLayerSets() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::loadLayersets() -{ - bool success = true; - for (LLTexLayerSetInfo* layerset_info : sAvatarXmlInfo->mLayerInfoList) - { - if (isSelf()) - { - // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. - LLTexLayerSet* layer_set = createTexLayerSet(); - - if (!layer_set->setInfo(layerset_info)) - { - stop_glerror(); - delete layer_set; - LL_WARNS() << "avatar file: layer_set->setInfo() failed" << LL_ENDL; - return false; - } - - // scan baked textures and associate the layerset with the appropriate one - EBakedTextureIndex baked_index = BAKED_NUM_INDICES; - for (const LLAvatarAppearanceDictionary::BakedTextures::value_type& baked_pair : sAvatarDictionary->getBakedTextures()) - { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_pair.second; - if (layer_set->isBodyRegion(baked_dict->mName)) - { - baked_index = baked_pair.first; - // ensure both structures are aware of each other - mBakedTextureDatas[baked_index].mTexLayerSet = layer_set; - layer_set->setBakedTexIndex(baked_index); - break; - } - } - // if no baked texture was found, warn and cleanup - if (baked_index == BAKED_NUM_INDICES) - { - LL_WARNS() << "<layer_set> has invalid body_region attribute" << LL_ENDL; - delete layer_set; - return false; - } - - // scan morph masks and let any affected layers know they have an associated morph - for (LLMaskedMorph* morph : mBakedTextureDatas[baked_index].mMaskedMorphs) - { - LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer); - if (layer) - { - layer->setHasMorph(true); - } - else - { - LL_WARNS() << "Could not find layer named " << morph->mLayer << " to set morph flag" << LL_ENDL; - success = false; - } - } - } - else // !isSelf() - { - // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. - layerset_info->createVisualParams(this); - } - } - return success; -} - -//----------------------------------------------------------------------------- -// getCharacterJoint() -//----------------------------------------------------------------------------- -LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num ) -{ - if ((S32)num >= mSkeleton.size() - || (S32)num < 0) - { - return NULL; - } - if (!mSkeleton[num]) - { - mSkeleton[num] = createAvatarJoint(); - } - return mSkeleton[num]; -} - - -//----------------------------------------------------------------------------- -// getVolumePos() -//----------------------------------------------------------------------------- -LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_offset) -{ - if (joint_index > mNumCollisionVolumes) - { - return LLVector3::zero; - } - - return mCollisionVolumes[joint_index].getVolumePos(volume_offset); -} - -//----------------------------------------------------------------------------- -// findCollisionVolume() -//----------------------------------------------------------------------------- -LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id) -{ - if ((volume_id < 0) || (volume_id >= mNumCollisionVolumes)) - { - return NULL; - } - - return &mCollisionVolumes[volume_id]; -} - -//----------------------------------------------------------------------------- -// findCollisionVolume() -//----------------------------------------------------------------------------- -S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name) -{ - for (S32 i = 0; i < mNumCollisionVolumes; i++) - { - if (mCollisionVolumes[i].getName() == name) - { - return i; - } - } - - return -1; -} - -//----------------------------------------------------------------------------- -// LLAvatarAppearance::getHeadMesh() -//----------------------------------------------------------------------------- -LLPolyMesh* LLAvatarAppearance::getHeadMesh() -{ - return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh(); -} - - -//----------------------------------------------------------------------------- -// LLAvatarAppearance::getUpperBodyMesh() -//----------------------------------------------------------------------------- -LLPolyMesh* LLAvatarAppearance::getUpperBodyMesh() -{ - return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh(); -} - - - -// virtual -bool LLAvatarAppearance::isValid() const -{ - // This should only be called on ourself. - if (!isSelf()) - { - LL_ERRS() << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << LL_ENDL; - } - return true; -} - - -// adds a morph mask to the appropriate baked texture structure -void LLAvatarAppearance::addMaskedMorph(EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer) -{ - if (index < BAKED_NUM_INDICES) - { - LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); - mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); - } -} - - -//static -bool LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) -{ - switch( te ) - { - case TEX_UPPER_SHIRT: - param_name[0] = 803; //"shirt_red"; - param_name[1] = 804; //"shirt_green"; - param_name[2] = 805; //"shirt_blue"; - break; - - case TEX_LOWER_PANTS: - param_name[0] = 806; //"pants_red"; - param_name[1] = 807; //"pants_green"; - param_name[2] = 808; //"pants_blue"; - break; - - case TEX_LOWER_SHOES: - param_name[0] = 812; //"shoes_red"; - param_name[1] = 813; //"shoes_green"; - param_name[2] = 817; //"shoes_blue"; - break; - - case TEX_LOWER_SOCKS: - param_name[0] = 818; //"socks_red"; - param_name[1] = 819; //"socks_green"; - param_name[2] = 820; //"socks_blue"; - break; - - case TEX_UPPER_JACKET: - case TEX_LOWER_JACKET: - param_name[0] = 834; //"jacket_red"; - param_name[1] = 835; //"jacket_green"; - param_name[2] = 836; //"jacket_blue"; - break; - - case TEX_UPPER_GLOVES: - param_name[0] = 827; //"gloves_red"; - param_name[1] = 829; //"gloves_green"; - param_name[2] = 830; //"gloves_blue"; - break; - - case TEX_UPPER_UNDERSHIRT: - param_name[0] = 821; //"undershirt_red"; - param_name[1] = 822; //"undershirt_green"; - param_name[2] = 823; //"undershirt_blue"; - break; - - case TEX_LOWER_UNDERPANTS: - param_name[0] = 824; //"underpants_red"; - param_name[1] = 825; //"underpants_green"; - param_name[2] = 826; //"underpants_blue"; - break; - - case TEX_SKIRT: - param_name[0] = 921; //"skirt_red"; - param_name[1] = 922; //"skirt_green"; - param_name[2] = 923; //"skirt_blue"; - break; - - case TEX_HEAD_TATTOO: - case TEX_LOWER_TATTOO: - case TEX_UPPER_TATTOO: - param_name[0] = 1071; //"tattoo_red"; - param_name[1] = 1072; //"tattoo_green"; - param_name[2] = 1073; //"tattoo_blue"; - break; - case TEX_HEAD_UNIVERSAL_TATTOO: - case TEX_UPPER_UNIVERSAL_TATTOO: - case TEX_LOWER_UNIVERSAL_TATTOO: - case TEX_SKIRT_TATTOO: - case TEX_HAIR_TATTOO: - case TEX_EYES_TATTOO: - case TEX_LEFT_ARM_TATTOO: - case TEX_LEFT_LEG_TATTOO: - case TEX_AUX1_TATTOO: - case TEX_AUX2_TATTOO: - case TEX_AUX3_TATTOO: - param_name[0] = 1238; //"tattoo_universal_red"; - param_name[1] = 1239; //"tattoo_universal_green"; - param_name[2] = 1240; //"tattoo_universal_blue"; - break; - - default: - llassert(0); - return false; - } - - return true; -} - -void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color) -{ - U32 param_name[3]; - if( teToColorParams( te, param_name ) ) - { - setVisualParamWeight( param_name[0], new_color.mV[VX]); - setVisualParamWeight( param_name[1], new_color.mV[VY]); - setVisualParamWeight( param_name[2], new_color.mV[VZ]); - } -} - -LLColor4 LLAvatarAppearance::getClothesColor( ETextureIndex te ) -{ - LLColor4 color; - U32 param_name[3]; - if( teToColorParams( te, param_name ) ) - { - color.mV[VX] = getVisualParamWeight( param_name[0] ); - color.mV[VY] = getVisualParamWeight( param_name[1] ); - color.mV[VZ] = getVisualParamWeight( param_name[2] ); - } - return color; -} - -// static -LLColor4 LLAvatarAppearance::getDummyColor() -{ - return DUMMY_COLOR; -} - -LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) const -{ - if (color_name=="skin_color" && mTexSkinColor) - { - return mTexSkinColor->getColor(); - } - else if(color_name=="hair_color" && mTexHairColor) - { - return mTexHairColor->getColor(); - } - if(color_name=="eye_color" && mTexEyeColor) - { - return mTexEyeColor->getColor(); - } - else - { -// return LLColor4( .5f, .5f, .5f, .5f ); - return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color - } -} - -// Unlike most wearable functions, this works for both self and other. -// virtual -bool LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const -{ - return mWearableData->getWearableCount(type) > 0; -} - -LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const -{ - /* switch(index) - case TEX_HEAD_BAKED: - case TEX_HEAD_BODYPAINT: - return mHeadLayerSet; */ - return mBakedTextureDatas[baked_index].mTexLayerSet; -} - -//----------------------------------------------------------------------------- -// allocateCollisionVolumes() -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::allocateCollisionVolumes( U32 num ) -{ - if (mNumCollisionVolumes !=num) - { - delete_and_clear_array(mCollisionVolumes); - mNumCollisionVolumes = 0; - - mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; - if (!mCollisionVolumes) - { - LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL; - return false; - } - - mNumCollisionVolumes = num; - } - return true; -} - -//----------------------------------------------------------------------------- -// LLAvatarBoneInfo::parseXml() -//----------------------------------------------------------------------------- -bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) -{ - if (node->hasName("bone")) - { - mIsJoint = true; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!node->getFastAttributeString(name_string, mName)) - { - LL_WARNS() << "Bone without name" << LL_ENDL; - return false; - } - - static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases"); - node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required. - } - else if (node->hasName("collision_volume")) - { - mIsJoint = false; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!node->getFastAttributeString(name_string, mName)) - { - mName = "Collision Volume"; - } - } - else - { - LL_WARNS() << "Invalid node " << node->getName() << LL_ENDL; - return false; - } - - static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); - if (!node->getFastAttributeVector3(pos_string, mPos)) - { - LL_WARNS() << "Bone without position" << LL_ENDL; - return false; - } - - static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot"); - if (!node->getFastAttributeVector3(rot_string, mRot)) - { - LL_WARNS() << "Bone without rotation" << LL_ENDL; - return false; - } - - static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); - if (!node->getFastAttributeVector3(scale_string, mScale)) - { - LL_WARNS() << "Bone without scale" << LL_ENDL; - return false; - } - - static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end"); - if (!node->getFastAttributeVector3(end_string, mEnd)) - { - LL_WARNS() << "Bone without end " << mName << LL_ENDL; - mEnd = LLVector3(0.0f, 0.0f, 0.0f); - } - - static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support"); - if (!node->getFastAttributeString(support_string,mSupport)) - { - LL_WARNS() << "Bone without support " << mName << LL_ENDL; - mSupport = "base"; - } - - if (mIsJoint) - { - static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); - if (!node->getFastAttributeVector3(pivot_string, mPivot)) - { - LL_WARNS() << "Bone without pivot" << LL_ENDL; - return false; - } - } - - // parse children - LLXmlTreeNode* child; - for( child = node->getFirstChild(); child; child = node->getNextChild() ) - { - LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo; - if (!child_info->parseXml(child)) - { - delete child_info; - return false; - } - mChildren.push_back(child_info); - } - return true; -} - -//----------------------------------------------------------------------------- -// LLAvatarSkeletonInfo::parseXml() -//----------------------------------------------------------------------------- -bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) -{ - static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); - if (!node->getFastAttributeS32(num_bones_string, mNumBones)) - { - LL_WARNS() << "Couldn't find number of bones." << LL_ENDL; - return false; - } - - static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes"); - node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes); - - LLXmlTreeNode* child; - for( child = node->getFirstChild(); child; child = node->getNextChild() ) - { - LLAvatarBoneInfo *info = new LLAvatarBoneInfo; - if (!info->parseXml(child)) - { - delete info; - LL_WARNS() << "Error parsing bone in skeleton file" << LL_ENDL; - return false; - } - mBoneInfoList.push_back(info); - } - return true; -} - -//Make aliases for joint and push to map. -void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info) -{ - if (! bone_info->mIsJoint ) - { - return; - } - - std::string bone_name = bone_info->mName; - mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias. - - std::string aliases = bone_info->mAliases; - - boost::char_separator<char> sep(" "); - boost::tokenizer<boost::char_separator<char> > tok(aliases, sep); - for(const std::string& i : tok) - { - if ( mJointAliasMap.find(i) != mJointAliasMap.end() ) - { - LL_WARNS() << "avatar skeleton: Joint alias \"" << i << "\" remapped from " << mJointAliasMap[i] << " to " << bone_name << LL_ENDL; - } - mJointAliasMap[i] = bone_name; - } - - for (LLAvatarBoneInfo* bone : bone_info->mChildren) - { - makeJointAliases(bone); - } -} - -const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases () -{ - LLAvatarAppearance::joint_alias_map_t alias_map; - if (mJointAliasMap.empty()) - { - - for (LLAvatarBoneInfo* bone_info : sAvatarSkeletonInfo->mBoneInfoList) - { - //LLAvatarBoneInfo *bone_info = *iter; - makeJointAliases(bone_info); - } - - for (LLAvatarXmlInfo::LLAvatarAttachmentInfo* info : sAvatarXmlInfo->mAttachmentInfoList) - { - std::string bone_name = info->mName; - - // Also accept the name with spaces substituted with - // underscores. This gives a mechanism for referencing such joints - // in daes, which don't allow spaces. - std::string sub_space_to_underscore = bone_name; - LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_'); - if (sub_space_to_underscore != bone_name) - { - mJointAliasMap[sub_space_to_underscore] = bone_name; - } - } - } - - return mJointAliasMap; -} - - -//----------------------------------------------------------------------------- -// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) -{ - LLXmlTreeNode* node = root->getChildByName( "skeleton" ); - if( !node ) - { - LL_WARNS() << "avatar file: missing <skeleton>" << LL_ENDL; - return false; - } - - LLXmlTreeNode* child; - - // SKELETON DISTORTIONS - for (child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if (!child->getChildByName("param_skeleton")) - { - if (child->getChildByName("param_morph")) - { - LL_WARNS() << "Can't specify morph param in skeleton definition." << LL_ENDL; - } - else - { - LL_WARNS() << "Unknown param type." << LL_ENDL; - } - return false; - } - - LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; - if (!info->parseXml(child)) - { - delete info; - return false; - } - - mSkeletalDistortionInfoList.push_back(info); - } - - // ATTACHMENT POINTS - for (child = node->getChildByName( "attachment_point" ); - child; - child = node->getNextNamedChild()) - { - LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo(); - - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (!child->getFastAttributeString(name_string, info->mName)) - { - LL_WARNS() << "No name supplied for attachment point." << LL_ENDL; - delete info; - return false; - } - - static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); - if (!child->getFastAttributeString(joint_string, info->mJointName)) - { - LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL; - delete info; - return false; - } - - static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); - if (child->getFastAttributeVector3(position_string, info->mPosition)) - { - info->mHasPosition = true; - } - - static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation"); - if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler)) - { - info->mHasRotation = true; - } - static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group"); - if (child->getFastAttributeS32(group_string, info->mGroup)) - { - if (info->mGroup == -1) - info->mGroup = -1111; // -1 = none parsed, < -1 = bad value - } - - static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); - if (!child->getFastAttributeS32(id_string, info->mAttachmentID)) - { - LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL; - delete info; - return false; - } - - static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); - child->getFastAttributeS32(slot_string, info->mPieMenuSlice); - - static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person"); - child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson); - - static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud"); - child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment); - - mAttachmentInfoList.push_back(info); - } - - return true; -} - -//----------------------------------------------------------------------------- -// parseXmlMeshNodes(): parses <mesh> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* node = root->getChildByName( "mesh" ); - node; - node = root->getNextNamedChild()) - { - LLAvatarMeshInfo *info = new LLAvatarMeshInfo; - - // attribute: type - static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type"); - if( !node->getFastAttributeString( type_string, info->mType ) ) - { - LL_WARNS() << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << LL_ENDL; - delete info; - return false; // Ignore this element - } - - static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod"); - if (!node->getFastAttributeS32( lod_string, info->mLOD )) - { - LL_WARNS() << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << LL_ENDL; - delete info; - return false; // Ignore this element - } - - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) ) - { - LL_WARNS() << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << LL_ENDL; - delete info; - return false; // Ignore this element - } - - static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference"); - node->getFastAttributeString( reference_string, info->mReferenceMeshName ); - - // attribute: min_pixel_area - static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area"); - static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width"); - if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea )) - { - F32 min_pixel_area = 0.1f; - if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area )) - { - // this is square root of pixel area (sensible to use linear space in defining lods) - min_pixel_area = min_pixel_area * min_pixel_area; - } - info->mMinPixelArea = min_pixel_area; - } - - // Parse visual params for this node only if we haven't already - for (LLXmlTreeNode* child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if (!child->getChildByName("param_morph")) - { - if (child->getChildByName("param_skeleton")) - { - LL_WARNS() << "Can't specify skeleton param in a mesh definition." << LL_ENDL; - } - else - { - LL_WARNS() << "Unknown param type." << LL_ENDL; - } - return false; - } - - LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); - if (!morphinfo->parseXml(child)) - { - delete morphinfo; - delete info; - return false; - } - bool shared = false; - static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared"); - child->getFastAttributeBOOL(shared_string, shared); - - info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared)); - } - - mMeshInfoList.push_back(info); - } - return true; -} - -//----------------------------------------------------------------------------- -// parseXmlColorNodes(): parses <global_color> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" ); - color_node; - color_node = root->getNextNamedChild()) - { - std::string global_color_name; - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if (color_node->getFastAttributeString( name_string, global_color_name ) ) - { - if( global_color_name == "skin_color" ) - { - if (mTexSkinColorInfo) - { - LL_WARNS() << "avatar file: multiple instances of skin_color" << LL_ENDL; - return false; - } - mTexSkinColorInfo = new LLTexGlobalColorInfo; - if( !mTexSkinColorInfo->parseXml( color_node ) ) - { - delete_and_clear(mTexSkinColorInfo); - LL_WARNS() << "avatar file: mTexSkinColor->parseXml() failed" << LL_ENDL; - return false; - } - } - else if( global_color_name == "hair_color" ) - { - if (mTexHairColorInfo) - { - LL_WARNS() << "avatar file: multiple instances of hair_color" << LL_ENDL; - return false; - } - mTexHairColorInfo = new LLTexGlobalColorInfo; - if( !mTexHairColorInfo->parseXml( color_node ) ) - { - delete_and_clear(mTexHairColorInfo); - LL_WARNS() << "avatar file: mTexHairColor->parseXml() failed" << LL_ENDL; - return false; - } - } - else if( global_color_name == "eye_color" ) - { - if (mTexEyeColorInfo) - { - LL_WARNS() << "avatar file: multiple instances of eye_color" << LL_ENDL; - return false; - } - mTexEyeColorInfo = new LLTexGlobalColorInfo; - if( !mTexEyeColorInfo->parseXml( color_node ) ) - { - LL_WARNS() << "avatar file: mTexEyeColor->parseXml() failed" << LL_ENDL; - return false; - } - } - } - } - return true; -} - -//----------------------------------------------------------------------------- -// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) -{ - for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" ); - layer_node; - layer_node = root->getNextNamedChild()) - { - LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo(); - if( layer_info->parseXml( layer_node ) ) - { - mLayerInfoList.push_back(layer_info); - } - else - { - delete layer_info; - LL_WARNS() << "avatar file: layer_set->parseXml() failed" << LL_ENDL; - return false; - } - } - return true; -} - -//----------------------------------------------------------------------------- -// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) -{ - LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" ); - if( driver ) - { - for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" ); - grand_child; - grand_child = driver->getNextNamedChild()) - { - if( grand_child->getChildByName( "param_driver" ) ) - { - LLDriverParamInfo* driver_info = new LLDriverParamInfo(); - if( driver_info->parseXml( grand_child ) ) - { - mDriverInfoList.push_back(driver_info); - } - else - { - delete driver_info; - LL_WARNS() << "avatar file: driver_param->parseXml() failed" << LL_ENDL; - return false; - } - } - } - } - return true; -} - -//----------------------------------------------------------------------------- -// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree -//----------------------------------------------------------------------------- -bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) -{ - LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); - if( !masks ) - { - return false; - } - - for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); - grand_child; - grand_child = masks->getNextNamedChild()) - { - LLAvatarMorphInfo* info = new LLAvatarMorphInfo(); - - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); - if (!grand_child->getFastAttributeString(name_string, info->mName)) - { - LL_WARNS() << "No name supplied for morph mask." << LL_ENDL; - delete info; - return false; - } - - static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); - if (!grand_child->getFastAttributeString(region_string, info->mRegion)) - { - LL_WARNS() << "No region supplied for morph mask." << LL_ENDL; - delete info; - return false; - } - - static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); - if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) - { - LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL; - delete info; - return false; - } - - // optional parameter. don't throw a warning if not present. - static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); - grand_child->getFastAttributeBOOL(invert_string, info->mInvert); - - mMorphMaskInfoList.push_back(info); - } - - return true; -} - -//virtual -LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer) : - mMorphTarget(morph_target), - mInvert(invert), - mLayer(layer) -{ - LLPolyMorphTarget *target = dynamic_cast<LLPolyMorphTarget*>(morph_target); - if (target) - { - target->addPendingMorphMask(); - } -} +/**
+ * @File llavatarappearance.cpp
+ * @brief Implementation of LLAvatarAppearance class
+ *
+ * $LicenseInfo:firstyear=2012&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$
+ */
+
+#include "linden_common.h"
+
+#include "llavatarappearance.h"
+#include "llavatarappearancedefines.h"
+#include "llavatarjointmesh.h"
+#include "llstl.h"
+#include "lldir.h"
+#include "llpolymorph.h"
+#include "llpolymesh.h"
+#include "llpolyskeletaldistortion.h"
+#include "llstl.h"
+#include "lltexglobalcolor.h"
+#include "llwearabledata.h"
+#include "boost/bind.hpp"
+#include "boost/tokenizer.hpp"
+
+using namespace LLAvatarAppearanceDefines;
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+const std::string AVATAR_DEFAULT_CHAR = "avatar";
+const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
+
+/*********************************************************************************
+ ** **
+ ** Begin private LLAvatarAppearance Support classes
+ **
+ **/
+
+//------------------------------------------------------------------------
+// LLAvatarBoneInfo
+// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
+//------------------------------------------------------------------------
+class LLAvatarBoneInfo
+{
+ friend class LLAvatarAppearance;
+ friend class LLAvatarSkeletonInfo;
+public:
+ LLAvatarBoneInfo() : mIsJoint(false) {}
+ ~LLAvatarBoneInfo()
+ {
+ std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
+ mChildren.clear();
+ }
+ bool parseXml(LLXmlTreeNode* node);
+
+private:
+ std::string mName;
+ std::string mSupport;
+ std::string mAliases;
+ bool mIsJoint;
+ LLVector3 mPos;
+ LLVector3 mEnd;
+ LLVector3 mRot;
+ LLVector3 mScale;
+ LLVector3 mPivot;
+ typedef std::vector<LLAvatarBoneInfo*> bones_t;
+ bones_t mChildren;
+};
+
+//------------------------------------------------------------------------
+// LLAvatarSkeletonInfo
+// Overall avatar skeleton
+//------------------------------------------------------------------------
+class LLAvatarSkeletonInfo
+{
+ friend class LLAvatarAppearance;
+public:
+ LLAvatarSkeletonInfo() :
+ mNumBones(0), mNumCollisionVolumes(0) {}
+ ~LLAvatarSkeletonInfo()
+ {
+ std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
+ mBoneInfoList.clear();
+ }
+ bool parseXml(LLXmlTreeNode* node);
+ S32 getNumBones() const { return mNumBones; }
+ S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
+
+private:
+ S32 mNumBones;
+ S32 mNumCollisionVolumes;
+ LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
+ typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
+ bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLAvatarXmlInfo
+//-----------------------------------------------------------------------------
+
+LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo()
+ : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
+{
+}
+
+LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo()
+{
+ std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
+ mMeshInfoList.clear();
+
+ std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
+ mSkeletalDistortionInfoList.clear();
+
+ std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
+ mAttachmentInfoList.clear();
+
+ delete_and_clear(mTexSkinColorInfo);
+ delete_and_clear(mTexHairColorInfo);
+ delete_and_clear(mTexEyeColorInfo);
+
+ std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ mLayerInfoList.clear();
+
+ std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+ mDriverInfoList.clear();
+
+ std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
+ mMorphMaskInfoList.clear();
+}
+
+
+/**
+ **
+ ** End LLAvatarAppearance Support classes
+ ** **
+ *********************************************************************************/
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL;
+LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL;
+LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* LLAvatarAppearance::sAvatarDictionary = NULL;
+
+
+LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
+ LLCharacter(),
+ mIsDummy(false),
+ mTexSkinColor( NULL ),
+ mTexHairColor( NULL ),
+ mTexEyeColor( NULL ),
+ mPelvisToFoot(0.f),
+ mHeadOffset(),
+ mRoot(NULL),
+ mWearableData(wearable_data),
+ mNumBones(0),
+ mNumCollisionVolumes(0),
+ mCollisionVolumes(NULL),
+ mIsBuilt(false),
+ mInitFlags(0)
+{
+ llassert_always(mWearableData);
+ mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
+ {
+ mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR;
+ mBakedTextureDatas[i].mTexLayerSet = NULL;
+ mBakedTextureDatas[i].mIsLoaded = false;
+ mBakedTextureDatas[i].mIsUsed = false;
+ mBakedTextureDatas[i].mMaskTexName = 0;
+ mBakedTextureDatas[i].mTextureIndex = sAvatarDictionary->bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
+ }
+}
+
+// virtual
+void LLAvatarAppearance::initInstance()
+{
+ //-------------------------------------------------------------------------
+ // initialize joint, mesh and shape members
+ //-------------------------------------------------------------------------
+ mRoot = createAvatarJoint();
+ mRoot->setName( "mRoot" );
+
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ LLAvatarJoint* joint = createAvatarJoint();
+ joint->setName(mesh_dict->mName);
+ joint->setMeshID(mesh_index);
+ mMeshLOD.push_back(joint);
+
+ /* mHairLOD.setName("mHairLOD");
+ mHairMesh0.setName("mHairMesh0");
+ mHairMesh0.setMeshID(MESH_ID_HAIR);
+ mHairMesh1.setName("mHairMesh1"); */
+ for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
+ {
+ LLAvatarJointMesh* mesh = createAvatarJointMesh();
+ std::string mesh_name = "m" + mesh_dict->mName + std::to_string(lod);
+ // We pre-pended an m - need to capitalize first character for camelCase
+ mesh_name[1] = toupper(mesh_name[1]);
+ mesh->setName(mesh_name);
+ mesh->setMeshID(mesh_index);
+ mesh->setPickName(mesh_dict->mPickName);
+ mesh->setIsTransparent(false);
+ switch((S32)mesh_index)
+ {
+ case MESH_ID_HAIR:
+ mesh->setIsTransparent(true);
+ break;
+ case MESH_ID_SKIRT:
+ mesh->setIsTransparent(true);
+ break;
+ case MESH_ID_EYEBALL_LEFT:
+ case MESH_ID_EYEBALL_RIGHT:
+ mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f );
+ break;
+ }
+
+ joint->mMeshParts.push_back(mesh);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // associate baked textures with meshes
+ //-------------------------------------------------------------------------
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID;
+ // Skip it if there's no associated baked texture.
+ if (baked_texture_index == BAKED_NUM_INDICES) continue;
+
+ for (LLAvatarJointMesh* mesh : mMeshLOD[mesh_index]->mMeshParts)
+ {
+ mBakedTextureDatas[(S32)baked_texture_index].mJointMeshes.push_back(mesh);
+ }
+ }
+
+ buildCharacter();
+
+ mInitFlags |= 1<<0;
+
+}
+
+// virtual
+LLAvatarAppearance::~LLAvatarAppearance()
+{
+ delete_and_clear(mTexSkinColor);
+ delete_and_clear(mTexHairColor);
+ delete_and_clear(mTexEyeColor);
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ delete_and_clear(mBakedTextureDatas[i].mTexLayerSet);
+ mBakedTextureDatas[i].mJointMeshes.clear();
+
+ for (LLMaskedMorph* masked_morph : mBakedTextureDatas[i].mMaskedMorphs)
+ {
+ delete masked_morph;
+ }
+ }
+
+ if (mRoot)
+ {
+ mRoot->removeAllChildren();
+ delete mRoot;
+ mRoot = nullptr;
+ }
+ mJointMap.clear();
+
+ clearSkeleton();
+ delete_and_clear_array(mCollisionVolumes);
+
+ std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer());
+ mPolyMeshes.clear();
+
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
+ joint->mMeshParts.clear();
+ }
+ std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
+ mMeshLOD.clear();
+}
+
+//static
+void LLAvatarAppearance::initClass()
+{
+ initClass("","");
+}
+
+//static
+void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg)
+{
+ // init dictionary (don't repeat on second login attempt)
+ if (!sAvatarDictionary)
+ {
+ sAvatarDictionary = new LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary();
+ }
+
+ std::string avatar_file_name;
+
+ if (!avatar_file_name_arg.empty())
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg);
+ }
+ else
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml");
+ }
+ LLXmlTree xml_tree;
+ bool success = xml_tree.parseFile( avatar_file_name, false );
+ if (!success)
+ {
+ LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = xml_tree.getRoot();
+ if (!root)
+ {
+ LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // <linden_avatar version="2.0"> (root)
+ //-------------------------------------------------------------------------
+ if( !root->hasName( "linden_avatar" ) )
+ {
+ LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
+ {
+ LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL;
+ }
+
+ S32 wearable_def_version = 1;
+ static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
+ root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
+ LLWearable::setCurrentDefinitionVersion( wearable_def_version );
+
+ std::string mesh_file_name;
+
+ LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
+ if (!skeleton_node)
+ {
+ LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL;
+ return;
+ }
+
+ std::string skeleton_file_name = skeleton_file_name_arg;
+ if (skeleton_file_name.empty())
+ {
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+ {
+ LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL;
+ }
+ }
+
+ std::string skeleton_path;
+ LLXmlTree skeleton_xml_tree;
+ skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
+ if (!parseSkeletonFile(skeleton_path, skeleton_xml_tree))
+ {
+ LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL;
+ }
+
+ // Process XML data
+
+ // avatar_skeleton.xml
+ if (sAvatarSkeletonInfo)
+ { //this can happen if a login attempt failed
+ delete sAvatarSkeletonInfo;
+ }
+ sAvatarSkeletonInfo = new LLAvatarSkeletonInfo;
+ if (!sAvatarSkeletonInfo->parseXml(skeleton_xml_tree.getRoot()))
+ {
+ LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL;
+ }
+ // parse avatar_lad.xml
+ if (sAvatarXmlInfo)
+ { //this can happen if a login attempt failed
+ delete_and_clear(sAvatarXmlInfo);
+ }
+ sAvatarXmlInfo = new LLAvatarXmlInfo;
+ if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlColorNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+}
+
+void LLAvatarAppearance::cleanupClass()
+{
+ delete_and_clear(sAvatarXmlInfo);
+ delete_and_clear(sAvatarDictionary);
+ delete_and_clear(sAvatarSkeletonInfo);
+}
+
+using namespace LLAvatarAppearanceDefines;
+
+void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state,
+ joint_state_map_t& curr_state)
+{
+ if (!last_state.empty() && (last_state != curr_state))
+ {
+ S32 diff_count = 0;
+ for (joint_state_map_t::value_type& pair : last_state)
+ {
+ const std::string& key = pair.first;
+ if (last_state[key] != curr_state[key])
+ {
+ LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL;
+ diff_count++;
+ }
+ }
+ if (diff_count > 0)
+ {
+ LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL;
+ }
+
+ }
+}
+
+//------------------------------------------------------------------------
+// The viewer can only suggest a good size for the agent,
+// the simulator will keep it inside a reasonable range.
+void LLAvatarAppearance::computeBodySize()
+{
+ mLastBodySizeState = mCurrBodySizeState;
+
+ mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale();
+ mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition();
+ mCurrBodySizeState["mSkull scale"] = mSkullp->getScale();
+ mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition();
+ mCurrBodySizeState["mNeck scale"] = mNeckp->getScale();
+ mCurrBodySizeState["mChest pos"] = mChestp->getPosition();
+ mCurrBodySizeState["mChest scale"] = mChestp->getScale();
+ mCurrBodySizeState["mHead pos"] = mHeadp->getPosition();
+ mCurrBodySizeState["mHead scale"] = mHeadp->getScale();
+ mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition();
+ mCurrBodySizeState["mTorso scale"] = mTorsop->getScale();
+ mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition();
+ mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale();
+ mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition();
+ mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale();
+ mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition();
+ mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
+ mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
+
+ F32 old_height = mBodySize.mV[VZ];
+ F32 old_offset = mAvatarOffset.mV[VZ];
+
+ // TODO: Measure the real depth and width
+ mPelvisToFoot = computePelvisToFoot();
+ F32 new_height = computeBodyHeight();
+ mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height);
+ F32 new_offset = getVisualParamWeight(AVATAR_HOVER);
+ mAvatarOffset.set(0, 0, new_offset);
+
+ if (mBodySize.mV[VZ] != old_height || new_offset != old_offset)
+ {
+ compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
+ }
+}
+
+F32 LLAvatarAppearance::computeBodyHeight()
+{
+ F32 result = mPelvisToFoot +
+ // all these relative positions usually are positive
+ mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] +
+ mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] +
+ mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] +
+ mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] +
+ mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2;
+ return result;
+}
+
+F32 LLAvatarAppearance::computePelvisToFoot()
+{
+ F32 result =
+ // all these relative positions usually are negative
+ mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] +
+ mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] +
+ mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] +
+ mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2;
+ return -result;
+}
+
+//-----------------------------------------------------------------------------
+// parseSkeletonFile()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree)
+{
+ //-------------------------------------------------------------------------
+ // parse the file
+ //-------------------------------------------------------------------------
+ bool parsesuccess = skeleton_xml_tree.parseFile( filename, false );
+
+ if (!parsesuccess)
+ {
+ LL_ERRS() << "Can't parse skeleton file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = skeleton_xml_tree.getRoot();
+ if (!root)
+ {
+ LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ if( !root->hasName( "linden_skeleton" ) )
+ {
+ LL_ERRS() << "Invalid avatar skeleton file header: " << filename << LL_ENDL;
+ return false;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
+ {
+ LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// setupBone()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num)
+{
+ LLJoint* joint = NULL;
+
+ LL_DEBUGS("BVH") << "bone info: name " << info->mName
+ << " isJoint " << info->mIsJoint
+ << " volume_num " << volume_num
+ << " joint_num " << joint_num
+ << LL_ENDL;
+
+ if (info->mIsJoint)
+ {
+ joint = getCharacterJoint(joint_num);
+ if (!joint)
+ {
+ LL_WARNS() << "Too many bones" << LL_ENDL;
+ return false;
+ }
+ joint->setName( info->mName );
+ }
+ else // collision volume
+ {
+ if (volume_num >= (S32)mNumCollisionVolumes)
+ {
+ LL_WARNS() << "Too many collision volumes" << LL_ENDL;
+ return false;
+ }
+ joint = (&mCollisionVolumes[volume_num]);
+ joint->setName( info->mName );
+ }
+
+ // add to parent
+ if (parent && (joint->getParent()!=parent))
+ {
+ parent->addChild( joint );
+ }
+
+ // SL-315
+ joint->setPosition(info->mPos);
+ joint->setDefaultPosition(info->mPos);
+ joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
+ info->mRot.mV[VZ], LLQuaternion::XYZ));
+ joint->setScale(info->mScale);
+ joint->setDefaultScale(info->mScale);
+ joint->setSupport(info->mSupport);
+ joint->setEnd(info->mEnd);
+
+ if (info->mIsJoint)
+ {
+ joint->setSkinOffset( info->mPivot );
+ joint->setJointNum(joint_num);
+ joint_num++;
+ }
+ else // collision volume
+ {
+ joint->setJointNum(mNumBones+volume_num);
+ volume_num++;
+ }
+
+
+ // setup children
+ for (LLAvatarBoneInfo* child_info : info->mChildren)
+ {
+ if (!setupBone(child_info, joint, volume_num, joint_num))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// allocateCharacterJoints()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::allocateCharacterJoints( U32 num )
+{
+ if (mSkeleton.size() != num)
+ {
+ clearSkeleton();
+ mSkeleton = avatar_joint_list_t(num,NULL);
+ mNumBones = num;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// buildSkeleton()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
+{
+ LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
+
+ // allocate joints
+ if (!allocateCharacterJoints(info->mNumBones))
+ {
+ LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL;
+ return false;
+ }
+
+ // allocate volumes
+ if (info->mNumCollisionVolumes)
+ {
+ if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
+ {
+ LL_ERRS() << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << LL_ENDL;
+ return false;
+ }
+ }
+
+ S32 current_joint_num = 0;
+ S32 current_volume_num = 0;
+ for (LLAvatarBoneInfo* bone_info : info->mBoneInfoList)
+ {
+ if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num))
+ {
+ LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// clearSkeleton()
+//-----------------------------------------------------------------------------
+void LLAvatarAppearance::clearSkeleton()
+{
+ std::for_each(mSkeleton.begin(), mSkeleton.end(), DeletePointer());
+ mSkeleton.clear();
+}
+
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id )
+{
+ LLVector3 pos(0.0,0.0,fixup);
+ mPelvisFixups.add(mesh_id,pos);
+}
+
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id )
+{
+ mPelvisFixups.remove(mesh_id);
+}
+
+//------------------------------------------------------------------------
+// hasPelvisFixup
+//------------------------------------------------------------------------
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const
+{
+ LLVector3 pos;
+ if (mPelvisFixups.findActiveOverride(mesh_id,pos))
+ {
+ fixup = pos[2];
+ return true;
+ }
+ return false;
+}
+
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const
+{
+ LLUUID mesh_id;
+ return hasPelvisFixup( fixup, mesh_id );
+}
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::buildCharacter()
+// Deferred initialization and rebuild of the avatar.
+//-----------------------------------------------------------------------------
+void LLAvatarAppearance::buildCharacter()
+{
+ //-------------------------------------------------------------------------
+ // remove all references to our existing skeleton
+ // so we can rebuild it
+ //-------------------------------------------------------------------------
+ flushAllMotions();
+
+ //-------------------------------------------------------------------------
+ // remove all of mRoot's children
+ //-------------------------------------------------------------------------
+ mRoot->removeAllChildren();
+ mJointMap.clear();
+ mIsBuilt = false;
+
+ //-------------------------------------------------------------------------
+ // clear mesh data
+ //-------------------------------------------------------------------------
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ for (LLAvatarJointMesh* mesh : joint->mMeshParts)
+ {
+ mesh->setMesh(NULL);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // (re)load our skeleton and meshes
+ //-------------------------------------------------------------------------
+ LLTimer timer;
+
+ bool status = loadAvatar();
+ stop_glerror();
+
+// gPrintMessagesThisFrame = true;
+ LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
+
+ if (!status)
+ {
+ if (isSelf())
+ {
+ LL_ERRS() << "Unable to load user's avatar" << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unable to load other's avatar" << LL_ENDL;
+ }
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize "well known" joint pointers
+ //-------------------------------------------------------------------------
+ mPelvisp = mRoot->findJoint("mPelvis");
+ mTorsop = mRoot->findJoint("mTorso");
+ mChestp = mRoot->findJoint("mChest");
+ mNeckp = mRoot->findJoint("mNeck");
+ mHeadp = mRoot->findJoint("mHead");
+ mSkullp = mRoot->findJoint("mSkull");
+ mHipLeftp = mRoot->findJoint("mHipLeft");
+ mHipRightp = mRoot->findJoint("mHipRight");
+ mKneeLeftp = mRoot->findJoint("mKneeLeft");
+ mKneeRightp = mRoot->findJoint("mKneeRight");
+ mAnkleLeftp = mRoot->findJoint("mAnkleLeft");
+ mAnkleRightp = mRoot->findJoint("mAnkleRight");
+ mFootLeftp = mRoot->findJoint("mFootLeft");
+ mFootRightp = mRoot->findJoint("mFootRight");
+ mWristLeftp = mRoot->findJoint("mWristLeft");
+ mWristRightp = mRoot->findJoint("mWristRight");
+ mEyeLeftp = mRoot->findJoint("mEyeLeft");
+ mEyeRightp = mRoot->findJoint("mEyeRight");
+
+ //-------------------------------------------------------------------------
+ // Make sure "well known" pointers exist
+ //-------------------------------------------------------------------------
+ if (!(mPelvisp &&
+ mTorsop &&
+ mChestp &&
+ mNeckp &&
+ mHeadp &&
+ mSkullp &&
+ mHipLeftp &&
+ mHipRightp &&
+ mKneeLeftp &&
+ mKneeRightp &&
+ mAnkleLeftp &&
+ mAnkleRightp &&
+ mFootLeftp &&
+ mFootRightp &&
+ mWristLeftp &&
+ mWristRightp &&
+ mEyeLeftp &&
+ mEyeRightp))
+ {
+ LL_ERRS() << "Failed to create avatar." << LL_ENDL;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize the pelvis
+ //-------------------------------------------------------------------------
+ // SL-315
+ mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
+
+ mIsBuilt = true;
+ stop_glerror();
+
+}
+
+bool LLAvatarAppearance::loadAvatar()
+{
+// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR);
+
+ // avatar_skeleton.xml
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ LL_ERRS() << "avatar file: buildSkeleton() failed" << LL_ENDL;
+ return false;
+ }
+
+ // initialize mJointAliasMap
+ getJointAliases();
+
+ // avatar_lad.xml : <skeleton>
+ if( !loadSkeletonNode() )
+ {
+ LL_ERRS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <mesh>
+ if( !loadMeshNodes() )
+ {
+ LL_ERRS() << "avatar file: loadNodeMesh() failed" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <global_color>
+ if( sAvatarXmlInfo->mTexSkinColorInfo )
+ {
+ mTexSkinColor = new LLTexGlobalColor( this );
+ if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL;
+ return false;
+ }
+ if( sAvatarXmlInfo->mTexHairColorInfo )
+ {
+ mTexHairColor = new LLTexGlobalColor( this );
+ if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL;
+ return false;
+ }
+ if( sAvatarXmlInfo->mTexEyeColorInfo )
+ {
+ mTexEyeColor = new LLTexGlobalColor( this );
+ if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <layer_set>
+ if (sAvatarXmlInfo->mLayerInfoList.empty())
+ {
+ LL_ERRS() << "avatar file: missing <layer_set> node" << LL_ENDL;
+ return false;
+ }
+
+ if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
+ {
+ LL_ERRS() << "avatar file: missing <morph_masks> node" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <morph_masks>
+ for (LLAvatarXmlInfo::LLAvatarMorphInfo* info : sAvatarXmlInfo->mMorphMaskInfoList)
+ {
+ EBakedTextureIndex baked = sAvatarDictionary->findBakedByRegionName(info->mRegion);
+ if (baked != BAKED_NUM_INDICES)
+ {
+ LLVisualParam* morph_param;
+ const std::string *name = &info->mName;
+ morph_param = getVisualParam(name->c_str());
+ if (morph_param)
+ {
+ bool invert = info->mInvert;
+ addMaskedMorph(baked, morph_param, invert, info->mLayer);
+ }
+ }
+
+ }
+
+ loadLayersets();
+
+ // avatar_lad.xml : <driver_parameters>
+ for (LLDriverParamInfo* info : sAvatarXmlInfo->mDriverInfoList)
+ {
+ LLDriverParam* driver_param = new LLDriverParam( this );
+ if (driver_param->setInfo(info))
+ {
+ addVisualParam( driver_param );
+ driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam;
+ if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false))
+ {
+ LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL;
+ continue;
+ }
+ }
+ else
+ {
+ delete driver_param;
+ LL_WARNS() << "avatar file: driver_param->parseData() failed" << LL_ENDL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadSkeletonNode(): loads <skeleton> node from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadSkeletonNode ()
+{
+ mRoot->addChild( mSkeleton[0] );
+
+ // make meshes children before calling parent version of the function
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ joint->mUpdateXform = false;
+ joint->setMeshesToChildren();
+ }
+
+ mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
+ mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]);
+ mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
+ mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
+ mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
+
+ LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
+ if (skull)
+ {
+ skull->addChild(mMeshLOD[MESH_ID_HAIR] );
+ }
+
+ LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft");
+ if (eyeL)
+ {
+ eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
+ }
+
+ LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight");
+ if (eyeR)
+ {
+ eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
+ }
+
+ // SKELETAL DISTORTIONS
+ {
+ for (LLViewerVisualParamInfo* visual_param_info : sAvatarXmlInfo->mSkeletalDistortionInfoList)
+ {
+ LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)visual_param_info;
+ LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
+ if (!param->setInfo(info))
+ {
+ delete param;
+ return false;
+ }
+ else
+ {
+ addVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ }
+ }
+
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadMeshNodes(): loads <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadMeshNodes()
+{
+ for (const LLAvatarXmlInfo::LLAvatarMeshInfo* info : sAvatarXmlInfo->mMeshInfoList)
+ {
+ const std::string &type = info->mType;
+ S32 lod = info->mLOD;
+
+ LLAvatarJointMesh* mesh = NULL;
+ U8 mesh_id = 0;
+ bool found_mesh_id = false;
+
+ /* if (type == "hairMesh")
+ switch(lod)
+ case 0:
+ mesh = &mHairMesh0; */
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ if (type.compare(mesh_dict->mName) == 0)
+ {
+ mesh_id = mesh_index;
+ found_mesh_id = true;
+ break;
+ }
+ }
+
+ if (found_mesh_id)
+ {
+ if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
+ {
+ mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
+ }
+ else
+ {
+ LL_WARNS() << "Avatar file: <mesh> has invalid lod setting " << lod << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Ignoring unrecognized mesh type: " << type << LL_ENDL;
+ return false;
+ }
+
+ // LL_INFOS() << "Parsing mesh data for " << type << "..." << LL_ENDL;
+
+ // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
+ // Do not touch!!!
+ mesh->setColor( LLColor4::white );
+
+ LLPolyMesh *poly_mesh = NULL;
+
+ if (!info->mReferenceMeshName.empty())
+ {
+ polymesh_map_t::const_iterator polymesh_iter = mPolyMeshes.find(info->mReferenceMeshName);
+ if (polymesh_iter != mPolyMeshes.end())
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
+ poly_mesh->setAvatar(this);
+ }
+ else
+ {
+ // This should never happen
+ LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
+ poly_mesh->setAvatar(this);
+ }
+
+ if( !poly_mesh )
+ {
+ LL_WARNS() << "Failed to load mesh of type " << type << LL_ENDL;
+ return false;
+ }
+
+ // Multimap insert
+ mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
+
+ mesh->setMesh( poly_mesh );
+ mesh->setLOD( info->mMinPixelArea );
+
+ for (const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t& info_pair : info->mPolyMorphTargetInfoList)
+ {
+ LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
+ if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair.first))
+ {
+ delete param;
+ return false;
+ }
+ else
+ {
+ if (info_pair.second)
+ {
+ addSharedVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ else
+ {
+ addVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadLayerSets()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadLayersets()
+{
+ bool success = true;
+ for (LLTexLayerSetInfo* layerset_info : sAvatarXmlInfo->mLayerInfoList)
+ {
+ if (isSelf())
+ {
+ // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+ LLTexLayerSet* layer_set = createTexLayerSet();
+
+ if (!layer_set->setInfo(layerset_info))
+ {
+ stop_glerror();
+ delete layer_set;
+ LL_WARNS() << "avatar file: layer_set->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+
+ // scan baked textures and associate the layerset with the appropriate one
+ EBakedTextureIndex baked_index = BAKED_NUM_INDICES;
+ for (const LLAvatarAppearanceDictionary::BakedTextures::value_type& baked_pair : sAvatarDictionary->getBakedTextures())
+ {
+ const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_pair.second;
+ if (layer_set->isBodyRegion(baked_dict->mName))
+ {
+ baked_index = baked_pair.first;
+ // ensure both structures are aware of each other
+ mBakedTextureDatas[baked_index].mTexLayerSet = layer_set;
+ layer_set->setBakedTexIndex(baked_index);
+ break;
+ }
+ }
+ // if no baked texture was found, warn and cleanup
+ if (baked_index == BAKED_NUM_INDICES)
+ {
+ LL_WARNS() << "<layer_set> has invalid body_region attribute" << LL_ENDL;
+ delete layer_set;
+ return false;
+ }
+
+ // scan morph masks and let any affected layers know they have an associated morph
+ for (LLMaskedMorph* morph : mBakedTextureDatas[baked_index].mMaskedMorphs)
+ {
+ LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer);
+ if (layer)
+ {
+ layer->setHasMorph(true);
+ }
+ else
+ {
+ LL_WARNS() << "Could not find layer named " << morph->mLayer << " to set morph flag" << LL_ENDL;
+ success = false;
+ }
+ }
+ }
+ else // !isSelf()
+ {
+ // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+ layerset_info->createVisualParams(this);
+ }
+ }
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// getCharacterJoint()
+//-----------------------------------------------------------------------------
+LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
+{
+ if ((S32)num >= mSkeleton.size()
+ || (S32)num < 0)
+ {
+ return NULL;
+ }
+ if (!mSkeleton[num])
+ {
+ mSkeleton[num] = createAvatarJoint();
+ }
+ return mSkeleton[num];
+}
+
+
+//-----------------------------------------------------------------------------
+// getVolumePos()
+//-----------------------------------------------------------------------------
+LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_offset)
+{
+ if (joint_index > mNumCollisionVolumes)
+ {
+ return LLVector3::zero;
+ }
+
+ return mCollisionVolumes[joint_index].getVolumePos(volume_offset);
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id)
+{
+ if ((volume_id < 0) || (volume_id >= mNumCollisionVolumes))
+ {
+ return NULL;
+ }
+
+ return &mCollisionVolumes[volume_id];
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name)
+{
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ if (mCollisionVolumes[i].getName() == name)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::getHeadMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLAvatarAppearance::getHeadMesh()
+{
+ return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::getUpperBodyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLAvatarAppearance::getUpperBodyMesh()
+{
+ return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh();
+}
+
+
+
+// virtual
+bool LLAvatarAppearance::isValid() const
+{
+ // This should only be called on ourself.
+ if (!isSelf())
+ {
+ LL_ERRS() << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << LL_ENDL;
+ }
+ return true;
+}
+
+
+// adds a morph mask to the appropriate baked texture structure
+void LLAvatarAppearance::addMaskedMorph(EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer)
+{
+ if (index < BAKED_NUM_INDICES)
+ {
+ LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer);
+ mBakedTextureDatas[index].mMaskedMorphs.push_front(morph);
+ }
+}
+
+
+//static
+bool LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
+{
+ switch( te )
+ {
+ case TEX_UPPER_SHIRT:
+ param_name[0] = 803; //"shirt_red";
+ param_name[1] = 804; //"shirt_green";
+ param_name[2] = 805; //"shirt_blue";
+ break;
+
+ case TEX_LOWER_PANTS:
+ param_name[0] = 806; //"pants_red";
+ param_name[1] = 807; //"pants_green";
+ param_name[2] = 808; //"pants_blue";
+ break;
+
+ case TEX_LOWER_SHOES:
+ param_name[0] = 812; //"shoes_red";
+ param_name[1] = 813; //"shoes_green";
+ param_name[2] = 817; //"shoes_blue";
+ break;
+
+ case TEX_LOWER_SOCKS:
+ param_name[0] = 818; //"socks_red";
+ param_name[1] = 819; //"socks_green";
+ param_name[2] = 820; //"socks_blue";
+ break;
+
+ case TEX_UPPER_JACKET:
+ case TEX_LOWER_JACKET:
+ param_name[0] = 834; //"jacket_red";
+ param_name[1] = 835; //"jacket_green";
+ param_name[2] = 836; //"jacket_blue";
+ break;
+
+ case TEX_UPPER_GLOVES:
+ param_name[0] = 827; //"gloves_red";
+ param_name[1] = 829; //"gloves_green";
+ param_name[2] = 830; //"gloves_blue";
+ break;
+
+ case TEX_UPPER_UNDERSHIRT:
+ param_name[0] = 821; //"undershirt_red";
+ param_name[1] = 822; //"undershirt_green";
+ param_name[2] = 823; //"undershirt_blue";
+ break;
+
+ case TEX_LOWER_UNDERPANTS:
+ param_name[0] = 824; //"underpants_red";
+ param_name[1] = 825; //"underpants_green";
+ param_name[2] = 826; //"underpants_blue";
+ break;
+
+ case TEX_SKIRT:
+ param_name[0] = 921; //"skirt_red";
+ param_name[1] = 922; //"skirt_green";
+ param_name[2] = 923; //"skirt_blue";
+ break;
+
+ case TEX_HEAD_TATTOO:
+ case TEX_LOWER_TATTOO:
+ case TEX_UPPER_TATTOO:
+ param_name[0] = 1071; //"tattoo_red";
+ param_name[1] = 1072; //"tattoo_green";
+ param_name[2] = 1073; //"tattoo_blue";
+ break;
+ case TEX_HEAD_UNIVERSAL_TATTOO:
+ case TEX_UPPER_UNIVERSAL_TATTOO:
+ case TEX_LOWER_UNIVERSAL_TATTOO:
+ case TEX_SKIRT_TATTOO:
+ case TEX_HAIR_TATTOO:
+ case TEX_EYES_TATTOO:
+ case TEX_LEFT_ARM_TATTOO:
+ case TEX_LEFT_LEG_TATTOO:
+ case TEX_AUX1_TATTOO:
+ case TEX_AUX2_TATTOO:
+ case TEX_AUX3_TATTOO:
+ param_name[0] = 1238; //"tattoo_universal_red";
+ param_name[1] = 1239; //"tattoo_universal_green";
+ param_name[2] = 1240; //"tattoo_universal_blue";
+ break;
+
+ default:
+ llassert(0);
+ return false;
+ }
+
+ return true;
+}
+
+void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
+{
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ setVisualParamWeight( param_name[0], new_color.mV[VX]);
+ setVisualParamWeight( param_name[1], new_color.mV[VY]);
+ setVisualParamWeight( param_name[2], new_color.mV[VZ]);
+ }
+}
+
+LLColor4 LLAvatarAppearance::getClothesColor( ETextureIndex te )
+{
+ LLColor4 color;
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ color.mV[VX] = getVisualParamWeight( param_name[0] );
+ color.mV[VY] = getVisualParamWeight( param_name[1] );
+ color.mV[VZ] = getVisualParamWeight( param_name[2] );
+ }
+ return color;
+}
+
+// static
+LLColor4 LLAvatarAppearance::getDummyColor()
+{
+ return DUMMY_COLOR;
+}
+
+LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) const
+{
+ if (color_name=="skin_color" && mTexSkinColor)
+ {
+ return mTexSkinColor->getColor();
+ }
+ else if(color_name=="hair_color" && mTexHairColor)
+ {
+ return mTexHairColor->getColor();
+ }
+ if(color_name=="eye_color" && mTexEyeColor)
+ {
+ return mTexEyeColor->getColor();
+ }
+ else
+ {
+// return LLColor4( .5f, .5f, .5f, .5f );
+ return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color
+ }
+}
+
+// Unlike most wearable functions, this works for both self and other.
+// virtual
+bool LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
+{
+ return mWearableData->getWearableCount(type) > 0;
+}
+
+LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const
+{
+ /* switch(index)
+ case TEX_HEAD_BAKED:
+ case TEX_HEAD_BODYPAINT:
+ return mHeadLayerSet; */
+ return mBakedTextureDatas[baked_index].mTexLayerSet;
+}
+
+//-----------------------------------------------------------------------------
+// allocateCollisionVolumes()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::allocateCollisionVolumes( U32 num )
+{
+ if (mNumCollisionVolumes !=num)
+ {
+ delete_and_clear_array(mCollisionVolumes);
+ mNumCollisionVolumes = 0;
+
+ mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
+ if (!mCollisionVolumes)
+ {
+ LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
+ return false;
+ }
+
+ mNumCollisionVolumes = num;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarBoneInfo::parseXml()
+//-----------------------------------------------------------------------------
+bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
+{
+ if (node->hasName("bone"))
+ {
+ mIsJoint = true;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ LL_WARNS() << "Bone without name" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases");
+ node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required.
+ }
+ else if (node->hasName("collision_volume"))
+ {
+ mIsJoint = false;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ mName = "Collision Volume";
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Invalid node " << node->getName() << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+ if (!node->getFastAttributeVector3(pos_string, mPos))
+ {
+ LL_WARNS() << "Bone without position" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
+ if (!node->getFastAttributeVector3(rot_string, mRot))
+ {
+ LL_WARNS() << "Bone without rotation" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!node->getFastAttributeVector3(scale_string, mScale))
+ {
+ LL_WARNS() << "Bone without scale" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end");
+ if (!node->getFastAttributeVector3(end_string, mEnd))
+ {
+ LL_WARNS() << "Bone without end " << mName << LL_ENDL;
+ mEnd = LLVector3(0.0f, 0.0f, 0.0f);
+ }
+
+ static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support");
+ if (!node->getFastAttributeString(support_string,mSupport))
+ {
+ LL_WARNS() << "Bone without support " << mName << LL_ENDL;
+ mSupport = "base";
+ }
+
+ if (mIsJoint)
+ {
+ static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
+ if (!node->getFastAttributeVector3(pivot_string, mPivot))
+ {
+ LL_WARNS() << "Bone without pivot" << LL_ENDL;
+ return false;
+ }
+ }
+
+ // parse children
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo;
+ if (!child_info->parseXml(child))
+ {
+ delete child_info;
+ return false;
+ }
+ mChildren.push_back(child_info);
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarSkeletonInfo::parseXml()
+//-----------------------------------------------------------------------------
+bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
+{
+ static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
+ if (!node->getFastAttributeS32(num_bones_string, mNumBones))
+ {
+ LL_WARNS() << "Couldn't find number of bones." << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
+ node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
+
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLAvatarBoneInfo *info = new LLAvatarBoneInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ LL_WARNS() << "Error parsing bone in skeleton file" << LL_ENDL;
+ return false;
+ }
+ mBoneInfoList.push_back(info);
+ }
+ return true;
+}
+
+//Make aliases for joint and push to map.
+void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
+{
+ if (! bone_info->mIsJoint )
+ {
+ return;
+ }
+
+ std::string bone_name = bone_info->mName;
+ mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias.
+
+ std::string aliases = bone_info->mAliases;
+
+ boost::char_separator<char> sep(" ");
+ boost::tokenizer<boost::char_separator<char> > tok(aliases, sep);
+ for(const std::string& i : tok)
+ {
+ if ( mJointAliasMap.find(i) != mJointAliasMap.end() )
+ {
+ LL_WARNS() << "avatar skeleton: Joint alias \"" << i << "\" remapped from " << mJointAliasMap[i] << " to " << bone_name << LL_ENDL;
+ }
+ mJointAliasMap[i] = bone_name;
+ }
+
+ for (LLAvatarBoneInfo* bone : bone_info->mChildren)
+ {
+ makeJointAliases(bone);
+ }
+}
+
+const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases ()
+{
+ LLAvatarAppearance::joint_alias_map_t alias_map;
+ if (mJointAliasMap.empty())
+ {
+
+ for (LLAvatarBoneInfo* bone_info : sAvatarSkeletonInfo->mBoneInfoList)
+ {
+ //LLAvatarBoneInfo *bone_info = *iter;
+ makeJointAliases(bone_info);
+ }
+
+ for (LLAvatarXmlInfo::LLAvatarAttachmentInfo* info : sAvatarXmlInfo->mAttachmentInfoList)
+ {
+ std::string bone_name = info->mName;
+
+ // Also accept the name with spaces substituted with
+ // underscores. This gives a mechanism for referencing such joints
+ // in daes, which don't allow spaces.
+ std::string sub_space_to_underscore = bone_name;
+ LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_');
+ if (sub_space_to_underscore != bone_name)
+ {
+ mJointAliasMap[sub_space_to_underscore] = bone_name;
+ }
+ }
+ }
+
+ return mJointAliasMap;
+}
+
+
+//-----------------------------------------------------------------------------
+// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* node = root->getChildByName( "skeleton" );
+ if( !node )
+ {
+ LL_WARNS() << "avatar file: missing <skeleton>" << LL_ENDL;
+ return false;
+ }
+
+ LLXmlTreeNode* child;
+
+ // SKELETON DISTORTIONS
+ for (child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_skeleton"))
+ {
+ if (child->getChildByName("param_morph"))
+ {
+ LL_WARNS() << "Can't specify morph param in skeleton definition." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unknown param type." << LL_ENDL;
+ }
+ return false;
+ }
+
+ LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return false;
+ }
+
+ mSkeletalDistortionInfoList.push_back(info);
+ }
+
+ // ATTACHMENT POINTS
+ for (child = node->getChildByName( "attachment_point" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!child->getFastAttributeString(name_string, info->mName))
+ {
+ LL_WARNS() << "No name supplied for attachment point." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
+ if (!child->getFastAttributeString(joint_string, info->mJointName))
+ {
+ LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
+ if (child->getFastAttributeVector3(position_string, info->mPosition))
+ {
+ info->mHasPosition = true;
+ }
+
+ static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
+ if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
+ {
+ info->mHasRotation = true;
+ }
+ static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
+ if (child->getFastAttributeS32(group_string, info->mGroup))
+ {
+ if (info->mGroup == -1)
+ info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
+ }
+
+ static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+ if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
+ {
+ LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
+ child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
+
+ static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
+ child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
+
+ static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
+ child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
+
+ mAttachmentInfoList.push_back(info);
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
+ node;
+ node = root->getNextNamedChild())
+ {
+ LLAvatarMeshInfo *info = new LLAvatarMeshInfo;
+
+ // attribute: type
+ static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
+ if( !node->getFastAttributeString( type_string, info->mType ) )
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
+ if (!node->getFastAttributeS32( lod_string, info->mLOD ))
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
+ node->getFastAttributeString( reference_string, info->mReferenceMeshName );
+
+ // attribute: min_pixel_area
+ static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
+ static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
+ if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
+ {
+ F32 min_pixel_area = 0.1f;
+ if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
+ {
+ // this is square root of pixel area (sensible to use linear space in defining lods)
+ min_pixel_area = min_pixel_area * min_pixel_area;
+ }
+ info->mMinPixelArea = min_pixel_area;
+ }
+
+ // Parse visual params for this node only if we haven't already
+ for (LLXmlTreeNode* child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_morph"))
+ {
+ if (child->getChildByName("param_skeleton"))
+ {
+ LL_WARNS() << "Can't specify skeleton param in a mesh definition." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unknown param type." << LL_ENDL;
+ }
+ return false;
+ }
+
+ LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
+ if (!morphinfo->parseXml(child))
+ {
+ delete morphinfo;
+ delete info;
+ return false;
+ }
+ bool shared = false;
+ static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
+ child->getFastAttributeBOOL(shared_string, shared);
+
+ info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
+ }
+
+ mMeshInfoList.push_back(info);
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlColorNodes(): parses <global_color> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
+ color_node;
+ color_node = root->getNextNamedChild())
+ {
+ std::string global_color_name;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (color_node->getFastAttributeString( name_string, global_color_name ) )
+ {
+ if( global_color_name == "skin_color" )
+ {
+ if (mTexSkinColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of skin_color" << LL_ENDL;
+ return false;
+ }
+ mTexSkinColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexSkinColorInfo->parseXml( color_node ) )
+ {
+ delete_and_clear(mTexSkinColorInfo);
+ LL_WARNS() << "avatar file: mTexSkinColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else if( global_color_name == "hair_color" )
+ {
+ if (mTexHairColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of hair_color" << LL_ENDL;
+ return false;
+ }
+ mTexHairColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexHairColorInfo->parseXml( color_node ) )
+ {
+ delete_and_clear(mTexHairColorInfo);
+ LL_WARNS() << "avatar file: mTexHairColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else if( global_color_name == "eye_color" )
+ {
+ if (mTexEyeColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of eye_color" << LL_ENDL;
+ return false;
+ }
+ mTexEyeColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexEyeColorInfo->parseXml( color_node ) )
+ {
+ LL_WARNS() << "avatar file: mTexEyeColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
+ layer_node;
+ layer_node = root->getNextNamedChild())
+ {
+ LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
+ if( layer_info->parseXml( layer_node ) )
+ {
+ mLayerInfoList.push_back(layer_info);
+ }
+ else
+ {
+ delete layer_info;
+ LL_WARNS() << "avatar file: layer_set->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
+ if( driver )
+ {
+ for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
+ grand_child;
+ grand_child = driver->getNextNamedChild())
+ {
+ if( grand_child->getChildByName( "param_driver" ) )
+ {
+ LLDriverParamInfo* driver_info = new LLDriverParamInfo();
+ if( driver_info->parseXml( grand_child ) )
+ {
+ mDriverInfoList.push_back(driver_info);
+ }
+ else
+ {
+ delete driver_info;
+ LL_WARNS() << "avatar file: driver_param->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
+ if( !masks )
+ {
+ return false;
+ }
+
+ for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
+ grand_child;
+ grand_child = masks->getNextNamedChild())
+ {
+ LLAvatarMorphInfo* info = new LLAvatarMorphInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
+ if (!grand_child->getFastAttributeString(name_string, info->mName))
+ {
+ LL_WARNS() << "No name supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
+ if (!grand_child->getFastAttributeString(region_string, info->mRegion))
+ {
+ LL_WARNS() << "No region supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
+ if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
+ {
+ LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ // optional parameter. don't throw a warning if not present.
+ static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
+ grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
+
+ mMorphMaskInfoList.push_back(info);
+ }
+
+ return true;
+}
+
+//virtual
+LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer) :
+ mMorphTarget(morph_target),
+ mInvert(invert),
+ mLayer(layer)
+{
+ LLPolyMorphTarget *target = dynamic_cast<LLPolyMorphTarget*>(morph_target);
+ if (target)
+ {
+ target->addPendingMorphMask();
+ }
+}
|