diff options
Diffstat (limited to 'indra/llappearance/llavatarappearance.cpp')
-rw-r--r-- | indra/llappearance/llavatarappearance.cpp | 4162 |
1 files changed, 2081 insertions, 2081 deletions
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index ed023c670b..f06845f084 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1,2081 +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();
-
- 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();
- }
-}
+/** + * @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(); + } +} |