summaryrefslogtreecommitdiff
path: root/indra/llappearance
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llappearance')
-rw-r--r--indra/llappearance/llavatarappearance.cpp4187
-rw-r--r--indra/llappearance/llavatarappearance.h940
-rw-r--r--indra/llappearance/llavatarappearancedefines.cpp826
-rw-r--r--indra/llappearance/llavatarappearancedefines.h510
-rw-r--r--indra/llappearance/llavatarjoint.cpp632
-rw-r--r--indra/llappearance/llavatarjoint.h280
-rw-r--r--indra/llappearance/llavatarjointmesh.cpp780
-rw-r--r--indra/llappearance/llavatarjointmesh.h282
-rw-r--r--indra/llappearance/lldriverparam.cpp1244
-rw-r--r--indra/llappearance/lldriverparam.h278
-rw-r--r--indra/llappearance/lljointpickname.h24
-rw-r--r--indra/llappearance/lllocaltextureobject.cpp424
-rw-r--r--indra/llappearance/lllocaltextureobject.h172
-rw-r--r--indra/llappearance/llpolymesh.cpp2080
-rw-r--r--indra/llappearance/llpolymesh.h736
-rw-r--r--indra/llappearance/llpolymorph.cpp1688
-rw-r--r--indra/llappearance/llpolymorph.h386
-rw-r--r--indra/llappearance/llpolyskeletaldistortion.cpp594
-rw-r--r--indra/llappearance/llpolyskeletaldistortion.h246
-rw-r--r--indra/llappearance/lltexglobalcolor.cpp330
-rw-r--r--indra/llappearance/lltexglobalcolor.h170
-rw-r--r--indra/llappearance/lltexlayer.cpp3840
-rw-r--r--indra/llappearance/lltexlayer.h626
-rw-r--r--indra/llappearance/lltexlayerparams.cpp1188
-rw-r--r--indra/llappearance/lltexlayerparams.h412
-rw-r--r--indra/llappearance/llviewervisualparam.cpp358
-rw-r--r--indra/llappearance/llviewervisualparam.h224
-rw-r--r--indra/llappearance/llwearable.cpp1546
-rw-r--r--indra/llappearance/llwearable.h276
-rw-r--r--indra/llappearance/llwearabledata.cpp688
-rw-r--r--indra/llappearance/llwearabledata.h204
-rw-r--r--indra/llappearance/llwearabletype.cpp268
-rw-r--r--indra/llappearance/llwearabletype.h236
33 files changed, 13326 insertions, 13349 deletions
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index b46edf573c..ed023c670b 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -1,2106 +1,2081 @@
-/**
- * @File llavatarappearance.cpp
- * @brief Implementation of LLAvatarAppearance class
- *
- * $LicenseInfo:firstyear=2012&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llavatarappearance.h"
-#include "llavatarappearancedefines.h"
-#include "llavatarjointmesh.h"
-#include "llstl.h"
-#include "lldir.h"
-#include "llpolymorph.h"
-#include "llpolymesh.h"
-#include "llpolyskeletaldistortion.h"
-#include "llstl.h"
-#include "lltexglobalcolor.h"
-#include "llwearabledata.h"
-#include "boost/bind.hpp"
-#include "boost/tokenizer.hpp"
-
-using namespace LLAvatarAppearanceDefines;
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
-const std::string AVATAR_DEFAULT_CHAR = "avatar";
-const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
-
-/*********************************************************************************
- ** **
- ** Begin private LLAvatarAppearance Support classes
- **
- **/
-
-//------------------------------------------------------------------------
-// LLAvatarBoneInfo
-// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
-//------------------------------------------------------------------------
-class LLAvatarBoneInfo
-{
- friend class LLAvatarAppearance;
- friend class LLAvatarSkeletonInfo;
-public:
- LLAvatarBoneInfo() : mIsJoint(false) {}
- ~LLAvatarBoneInfo()
- {
- std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
- mChildren.clear();
- }
- bool parseXml(LLXmlTreeNode* node);
-
-private:
- std::string mName;
- std::string mSupport;
- std::string mAliases;
- bool mIsJoint;
- LLVector3 mPos;
- LLVector3 mEnd;
- LLVector3 mRot;
- LLVector3 mScale;
- LLVector3 mPivot;
- typedef std::vector<LLAvatarBoneInfo*> bones_t;
- bones_t mChildren;
-};
-
-//------------------------------------------------------------------------
-// LLAvatarSkeletonInfo
-// Overall avatar skeleton
-//------------------------------------------------------------------------
-class LLAvatarSkeletonInfo
-{
- friend class LLAvatarAppearance;
-public:
- LLAvatarSkeletonInfo() :
- mNumBones(0), mNumCollisionVolumes(0) {}
- ~LLAvatarSkeletonInfo()
- {
- std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
- mBoneInfoList.clear();
- }
- bool parseXml(LLXmlTreeNode* node);
- S32 getNumBones() const { return mNumBones; }
- S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
-
-private:
- S32 mNumBones;
- S32 mNumCollisionVolumes;
- LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
- typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
- bone_info_list_t mBoneInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// LLAvatarXmlInfo
-//-----------------------------------------------------------------------------
-
-LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo()
- : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
-{
-}
-
-LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo()
-{
- std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
- mMeshInfoList.clear();
-
- std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
- mSkeletalDistortionInfoList.clear();
-
- std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
- mAttachmentInfoList.clear();
-
- delete_and_clear(mTexSkinColorInfo);
- delete_and_clear(mTexHairColorInfo);
- delete_and_clear(mTexEyeColorInfo);
-
- std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
- mLayerInfoList.clear();
-
- std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
- mDriverInfoList.clear();
-
- std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
- mMorphMaskInfoList.clear();
-}
-
-
-/**
- **
- ** End LLAvatarAppearance Support classes
- ** **
- *********************************************************************************/
-
-//-----------------------------------------------------------------------------
-// Static Data
-//-----------------------------------------------------------------------------
-LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL;
-LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL;
-LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* LLAvatarAppearance::sAvatarDictionary = NULL;
-
-
-LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
- LLCharacter(),
- mIsDummy(false),
- mTexSkinColor( NULL ),
- mTexHairColor( NULL ),
- mTexEyeColor( NULL ),
- mPelvisToFoot(0.f),
- mHeadOffset(),
- mRoot(NULL),
- mWearableData(wearable_data),
- mNumBones(0),
- mNumCollisionVolumes(0),
- mCollisionVolumes(NULL),
- mIsBuilt(false),
- mInitFlags(0)
-{
- llassert_always(mWearableData);
- mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
- {
- mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR;
- mBakedTextureDatas[i].mTexLayerSet = NULL;
- mBakedTextureDatas[i].mIsLoaded = false;
- mBakedTextureDatas[i].mIsUsed = false;
- mBakedTextureDatas[i].mMaskTexName = 0;
- mBakedTextureDatas[i].mTextureIndex = sAvatarDictionary->bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
- }
-}
-
-// virtual
-void LLAvatarAppearance::initInstance()
-{
- //-------------------------------------------------------------------------
- // initialize joint, mesh and shape members
- //-------------------------------------------------------------------------
- mRoot = createAvatarJoint();
- mRoot->setName( "mRoot" );
-
- for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
- {
- const EMeshIndex mesh_index = mesh_pair.first;
- const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
- LLAvatarJoint* joint = createAvatarJoint();
- joint->setName(mesh_dict->mName);
- joint->setMeshID(mesh_index);
- mMeshLOD.push_back(joint);
-
- /* mHairLOD.setName("mHairLOD");
- mHairMesh0.setName("mHairMesh0");
- mHairMesh0.setMeshID(MESH_ID_HAIR);
- mHairMesh1.setName("mHairMesh1"); */
- for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
- {
- LLAvatarJointMesh* mesh = createAvatarJointMesh();
- std::string mesh_name = "m" + mesh_dict->mName + std::to_string(lod);
- // We pre-pended an m - need to capitalize first character for camelCase
- mesh_name[1] = toupper(mesh_name[1]);
- mesh->setName(mesh_name);
- mesh->setMeshID(mesh_index);
- mesh->setPickName(mesh_dict->mPickName);
- mesh->setIsTransparent(false);
- switch((S32)mesh_index)
- {
- case MESH_ID_HAIR:
- mesh->setIsTransparent(true);
- break;
- case MESH_ID_SKIRT:
- mesh->setIsTransparent(true);
- break;
- case MESH_ID_EYEBALL_LEFT:
- case MESH_ID_EYEBALL_RIGHT:
- mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f );
- break;
- }
-
- joint->mMeshParts.push_back(mesh);
- }
- }
-
- //-------------------------------------------------------------------------
- // associate baked textures with meshes
- //-------------------------------------------------------------------------
- for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
- {
- const EMeshIndex mesh_index = mesh_pair.first;
- const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
- const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID;
- // Skip it if there's no associated baked texture.
- if (baked_texture_index == BAKED_NUM_INDICES) continue;
-
- for (LLAvatarJointMesh* mesh : mMeshLOD[mesh_index]->mMeshParts)
- {
- mBakedTextureDatas[(S32)baked_texture_index].mJointMeshes.push_back(mesh);
- }
- }
-
- buildCharacter();
-
- mInitFlags |= 1<<0;
-
-}
-
-// virtual
-LLAvatarAppearance::~LLAvatarAppearance()
-{
- delete_and_clear(mTexSkinColor);
- delete_and_clear(mTexHairColor);
- delete_and_clear(mTexEyeColor);
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- delete_and_clear(mBakedTextureDatas[i].mTexLayerSet);
- mBakedTextureDatas[i].mJointMeshes.clear();
-
- for (LLMaskedMorph* masked_morph : mBakedTextureDatas[i].mMaskedMorphs)
- {
- delete masked_morph;
- }
- }
-
- if (mRoot)
- {
- mRoot->removeAllChildren();
- delete mRoot;
- mRoot = nullptr;
- }
- mJointMap.clear();
-
- clearSkeleton();
- delete_and_clear_array(mCollisionVolumes);
-
- std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer());
- mPolyMeshes.clear();
-
- for (LLAvatarJoint* joint : mMeshLOD)
- {
- std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
- joint->mMeshParts.clear();
- }
- std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
- mMeshLOD.clear();
-}
-
-//static
-void LLAvatarAppearance::initClass()
-{
- initClass("","");
-}
-
-//static
-void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg)
-{
- // init dictionary (don't repeat on second login attempt)
- if (!sAvatarDictionary)
- {
- sAvatarDictionary = new LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary();
- }
-
- std::string avatar_file_name;
-
- if (!avatar_file_name_arg.empty())
- {
- avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg);
- }
- else
- {
- avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml");
- }
- LLXmlTree xml_tree;
- bool success = xml_tree.parseFile( avatar_file_name, false );
- if (!success)
- {
- LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL;
- }
-
- // now sanity check xml file
- LLXmlTreeNode* root = xml_tree.getRoot();
- if (!root)
- {
- LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL;
- return;
- }
-
- //-------------------------------------------------------------------------
- // <linden_avatar version="2.0"> (root)
- //-------------------------------------------------------------------------
- if( !root->hasName( "linden_avatar" ) )
- {
- LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL;
- }
-
- std::string version;
- static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
- {
- LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL;
- }
-
- S32 wearable_def_version = 1;
- static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
- root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
- LLWearable::setCurrentDefinitionVersion( wearable_def_version );
-
- std::string mesh_file_name;
-
- LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
- if (!skeleton_node)
- {
- LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL;
- return;
- }
-
- std::string skeleton_file_name = skeleton_file_name_arg;
- if (skeleton_file_name.empty())
- {
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
- {
- LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL;
- }
- }
-
- std::string skeleton_path;
- LLXmlTree skeleton_xml_tree;
- skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
- if (!parseSkeletonFile(skeleton_path, skeleton_xml_tree))
- {
- LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL;
- }
-
- // Process XML data
-
- // avatar_skeleton.xml
- if (sAvatarSkeletonInfo)
- { //this can happen if a login attempt failed
- delete sAvatarSkeletonInfo;
- }
- sAvatarSkeletonInfo = new LLAvatarSkeletonInfo;
- if (!sAvatarSkeletonInfo->parseXml(skeleton_xml_tree.getRoot()))
- {
- LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL;
- }
- // parse avatar_lad.xml
- if (sAvatarXmlInfo)
- { //this can happen if a login attempt failed
- delete_and_clear(sAvatarXmlInfo);
- }
- sAvatarXmlInfo = new LLAvatarXmlInfo;
- if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
- if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
- if (!sAvatarXmlInfo->parseXmlColorNodes(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
- if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
- if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
- if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
- {
- LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
- }
-}
-
-void LLAvatarAppearance::cleanupClass()
-{
- delete_and_clear(sAvatarXmlInfo);
- delete_and_clear(sAvatarDictionary);
- delete_and_clear(sAvatarSkeletonInfo);
-}
-
-using namespace LLAvatarAppearanceDefines;
-
-void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state,
- joint_state_map_t& curr_state)
-{
- if (!last_state.empty() && (last_state != curr_state))
- {
- S32 diff_count = 0;
- for (joint_state_map_t::value_type& pair : last_state)
- {
- const std::string& key = pair.first;
- if (last_state[key] != curr_state[key])
- {
- LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL;
- diff_count++;
- }
- }
- if (diff_count > 0)
- {
- LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL;
- }
-
- }
-}
-
-//------------------------------------------------------------------------
-// The viewer can only suggest a good size for the agent,
-// the simulator will keep it inside a reasonable range.
-void LLAvatarAppearance::computeBodySize()
-{
- mLastBodySizeState = mCurrBodySizeState;
-
- mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale();
- mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition();
- mCurrBodySizeState["mSkull scale"] = mSkullp->getScale();
- mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition();
- mCurrBodySizeState["mNeck scale"] = mNeckp->getScale();
- mCurrBodySizeState["mChest pos"] = mChestp->getPosition();
- mCurrBodySizeState["mChest scale"] = mChestp->getScale();
- mCurrBodySizeState["mHead pos"] = mHeadp->getPosition();
- mCurrBodySizeState["mHead scale"] = mHeadp->getScale();
- mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition();
- mCurrBodySizeState["mTorso scale"] = mTorsop->getScale();
- mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition();
- mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale();
- mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition();
- mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale();
- mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition();
- mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
- mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
-
- LLVector3 pelvis_scale = mPelvisp->getScale();
-
- // some of the joints have not been cached
- LLVector3 skull = mSkullp->getPosition();
- //LLVector3 skull_scale = mSkullp->getScale();
-
- LLVector3 neck = mNeckp->getPosition();
- LLVector3 neck_scale = mNeckp->getScale();
-
- LLVector3 chest = mChestp->getPosition();
- LLVector3 chest_scale = mChestp->getScale();
-
- // the rest of the joints have been cached
- LLVector3 head = mHeadp->getPosition();
- LLVector3 head_scale = mHeadp->getScale();
-
- LLVector3 torso = mTorsop->getPosition();
- LLVector3 torso_scale = mTorsop->getScale();
-
- LLVector3 hip = mHipLeftp->getPosition();
- LLVector3 hip_scale = mHipLeftp->getScale();
-
- LLVector3 knee = mKneeLeftp->getPosition();
- LLVector3 knee_scale = mKneeLeftp->getScale();
-
- LLVector3 ankle = mAnkleLeftp->getPosition();
- LLVector3 ankle_scale = mAnkleLeftp->getScale();
-
- LLVector3 foot = mFootLeftp->getPosition();
-
- F32 old_offset = mAvatarOffset.mV[VZ];
-
- mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER);
-
- mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
- knee.mV[VZ] * hip_scale.mV[VZ] -
- ankle.mV[VZ] * knee_scale.mV[VZ] -
- foot.mV[VZ] * ankle_scale.mV[VZ];
-
- LLVector3 new_body_size;
- new_body_size.mV[VZ] = mPelvisToFoot +
- // the sqrt(2) correction below is an approximate
- // correction to get to the top of the head
- F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
- head.mV[VZ] * neck_scale.mV[VZ] +
- neck.mV[VZ] * chest_scale.mV[VZ] +
- chest.mV[VZ] * torso_scale.mV[VZ] +
- torso.mV[VZ] * pelvis_scale.mV[VZ];
-
- // TODO -- measure the real depth and width
- new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
- new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
-
- mAvatarOffset.mV[VX] = 0.0f;
- mAvatarOffset.mV[VY] = 0.0f;
-
- if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
- {
- mBodySize = new_body_size;
-
- compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
- }
-}
-
-//-----------------------------------------------------------------------------
-// parseSkeletonFile()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree)
-{
- //-------------------------------------------------------------------------
- // parse the file
- //-------------------------------------------------------------------------
- bool parsesuccess = skeleton_xml_tree.parseFile( filename, false );
-
- if (!parsesuccess)
- {
- LL_ERRS() << "Can't parse skeleton file: " << filename << LL_ENDL;
- return false;
- }
-
- // now sanity check xml file
- LLXmlTreeNode* root = skeleton_xml_tree.getRoot();
- if (!root)
- {
- LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL;
- return false;
- }
-
- if( !root->hasName( "linden_skeleton" ) )
- {
- LL_ERRS() << "Invalid avatar skeleton file header: " << filename << LL_ENDL;
- return false;
- }
-
- std::string version;
- static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
- {
- LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL;
- return false;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// setupBone()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num)
-{
- LLJoint* joint = NULL;
-
- LL_DEBUGS("BVH") << "bone info: name " << info->mName
- << " isJoint " << info->mIsJoint
- << " volume_num " << volume_num
- << " joint_num " << joint_num
- << LL_ENDL;
-
- if (info->mIsJoint)
- {
- joint = getCharacterJoint(joint_num);
- if (!joint)
- {
- LL_WARNS() << "Too many bones" << LL_ENDL;
- return false;
- }
- joint->setName( info->mName );
- }
- else // collision volume
- {
- if (volume_num >= (S32)mNumCollisionVolumes)
- {
- LL_WARNS() << "Too many collision volumes" << LL_ENDL;
- return false;
- }
- joint = (&mCollisionVolumes[volume_num]);
- joint->setName( info->mName );
- }
-
- // add to parent
- if (parent && (joint->getParent()!=parent))
- {
- parent->addChild( joint );
- }
-
- // SL-315
- joint->setPosition(info->mPos);
- joint->setDefaultPosition(info->mPos);
- joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
- info->mRot.mV[VZ], LLQuaternion::XYZ));
- joint->setScale(info->mScale);
- joint->setDefaultScale(info->mScale);
- joint->setSupport(info->mSupport);
- joint->setEnd(info->mEnd);
-
- if (info->mIsJoint)
- {
- joint->setSkinOffset( info->mPivot );
- joint->setJointNum(joint_num);
- joint_num++;
- }
- else // collision volume
- {
- joint->setJointNum(mNumBones+volume_num);
- volume_num++;
- }
-
-
- // setup children
- for (LLAvatarBoneInfo* child_info : info->mChildren)
- {
- if (!setupBone(child_info, joint, volume_num, joint_num))
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// allocateCharacterJoints()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::allocateCharacterJoints( U32 num )
-{
- if (mSkeleton.size() != num)
- {
- clearSkeleton();
- mSkeleton = avatar_joint_list_t(num,NULL);
- mNumBones = num;
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// buildSkeleton()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
-{
- LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
-
- // allocate joints
- if (!allocateCharacterJoints(info->mNumBones))
- {
- LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL;
- return false;
- }
-
- // allocate volumes
- if (info->mNumCollisionVolumes)
- {
- if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
- {
- LL_ERRS() << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << LL_ENDL;
- return false;
- }
- }
-
- S32 current_joint_num = 0;
- S32 current_volume_num = 0;
- for (LLAvatarBoneInfo* bone_info : info->mBoneInfoList)
- {
- if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num))
- {
- LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL;
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// clearSkeleton()
-//-----------------------------------------------------------------------------
-void LLAvatarAppearance::clearSkeleton()
-{
- std::for_each(mSkeleton.begin(), mSkeleton.end(), DeletePointer());
- mSkeleton.clear();
-}
-
-//------------------------------------------------------------------------
-// addPelvisFixup
-//------------------------------------------------------------------------
-void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id )
-{
- LLVector3 pos(0.0,0.0,fixup);
- mPelvisFixups.add(mesh_id,pos);
-}
-
-//------------------------------------------------------------------------
-// addPelvisFixup
-//------------------------------------------------------------------------
-void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id )
-{
- mPelvisFixups.remove(mesh_id);
-}
-
-//------------------------------------------------------------------------
-// hasPelvisFixup
-//------------------------------------------------------------------------
-bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const
-{
- LLVector3 pos;
- if (mPelvisFixups.findActiveOverride(mesh_id,pos))
- {
- fixup = pos[2];
- return true;
- }
- return false;
-}
-
-bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const
-{
- LLUUID mesh_id;
- return hasPelvisFixup( fixup, mesh_id );
-}
-//-----------------------------------------------------------------------------
-// LLAvatarAppearance::buildCharacter()
-// Deferred initialization and rebuild of the avatar.
-//-----------------------------------------------------------------------------
-void LLAvatarAppearance::buildCharacter()
-{
- //-------------------------------------------------------------------------
- // remove all references to our existing skeleton
- // so we can rebuild it
- //-------------------------------------------------------------------------
- flushAllMotions();
-
- //-------------------------------------------------------------------------
- // remove all of mRoot's children
- //-------------------------------------------------------------------------
- mRoot->removeAllChildren();
- mJointMap.clear();
- mIsBuilt = false;
-
- //-------------------------------------------------------------------------
- // clear mesh data
- //-------------------------------------------------------------------------
- for (LLAvatarJoint* joint : mMeshLOD)
- {
- for (LLAvatarJointMesh* mesh : joint->mMeshParts)
- {
- mesh->setMesh(NULL);
- }
- }
-
- //-------------------------------------------------------------------------
- // (re)load our skeleton and meshes
- //-------------------------------------------------------------------------
- LLTimer timer;
-
- bool status = loadAvatar();
- stop_glerror();
-
-// gPrintMessagesThisFrame = true;
- LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
-
- if (!status)
- {
- if (isSelf())
- {
- LL_ERRS() << "Unable to load user's avatar" << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Unable to load other's avatar" << LL_ENDL;
- }
- return;
- }
-
- //-------------------------------------------------------------------------
- // initialize "well known" joint pointers
- //-------------------------------------------------------------------------
- mPelvisp = mRoot->findJoint("mPelvis");
- mTorsop = mRoot->findJoint("mTorso");
- mChestp = mRoot->findJoint("mChest");
- mNeckp = mRoot->findJoint("mNeck");
- mHeadp = mRoot->findJoint("mHead");
- mSkullp = mRoot->findJoint("mSkull");
- mHipLeftp = mRoot->findJoint("mHipLeft");
- mHipRightp = mRoot->findJoint("mHipRight");
- mKneeLeftp = mRoot->findJoint("mKneeLeft");
- mKneeRightp = mRoot->findJoint("mKneeRight");
- mAnkleLeftp = mRoot->findJoint("mAnkleLeft");
- mAnkleRightp = mRoot->findJoint("mAnkleRight");
- mFootLeftp = mRoot->findJoint("mFootLeft");
- mFootRightp = mRoot->findJoint("mFootRight");
- mWristLeftp = mRoot->findJoint("mWristLeft");
- mWristRightp = mRoot->findJoint("mWristRight");
- mEyeLeftp = mRoot->findJoint("mEyeLeft");
- mEyeRightp = mRoot->findJoint("mEyeRight");
-
- //-------------------------------------------------------------------------
- // Make sure "well known" pointers exist
- //-------------------------------------------------------------------------
- if (!(mPelvisp &&
- mTorsop &&
- mChestp &&
- mNeckp &&
- mHeadp &&
- mSkullp &&
- mHipLeftp &&
- mHipRightp &&
- mKneeLeftp &&
- mKneeRightp &&
- mAnkleLeftp &&
- mAnkleRightp &&
- mFootLeftp &&
- mFootRightp &&
- mWristLeftp &&
- mWristRightp &&
- mEyeLeftp &&
- mEyeRightp))
- {
- LL_ERRS() << "Failed to create avatar." << LL_ENDL;
- return;
- }
-
- //-------------------------------------------------------------------------
- // initialize the pelvis
- //-------------------------------------------------------------------------
- // SL-315
- mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
-
- mIsBuilt = true;
- stop_glerror();
-
-}
-
-bool LLAvatarAppearance::loadAvatar()
-{
-// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR);
-
- // avatar_skeleton.xml
- if( !buildSkeleton(sAvatarSkeletonInfo) )
- {
- LL_ERRS() << "avatar file: buildSkeleton() failed" << LL_ENDL;
- return false;
- }
-
- // initialize mJointAliasMap
- getJointAliases();
-
- // avatar_lad.xml : <skeleton>
- if( !loadSkeletonNode() )
- {
- LL_ERRS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL;
- return false;
- }
-
- // avatar_lad.xml : <mesh>
- if( !loadMeshNodes() )
- {
- LL_ERRS() << "avatar file: loadNodeMesh() failed" << LL_ENDL;
- return false;
- }
-
- // avatar_lad.xml : <global_color>
- if( sAvatarXmlInfo->mTexSkinColorInfo )
- {
- mTexSkinColor = new LLTexGlobalColor( this );
- if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
- {
- LL_ERRS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL;
- return false;
- }
- }
- else
- {
- LL_ERRS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL;
- return false;
- }
- if( sAvatarXmlInfo->mTexHairColorInfo )
- {
- mTexHairColor = new LLTexGlobalColor( this );
- if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
- {
- LL_ERRS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL;
- return false;
- }
- }
- else
- {
- LL_ERRS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL;
- return false;
- }
- if( sAvatarXmlInfo->mTexEyeColorInfo )
- {
- mTexEyeColor = new LLTexGlobalColor( this );
- if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
- {
- LL_ERRS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL;
- return false;
- }
- }
- else
- {
- LL_ERRS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL;
- return false;
- }
-
- // avatar_lad.xml : <layer_set>
- if (sAvatarXmlInfo->mLayerInfoList.empty())
- {
- LL_ERRS() << "avatar file: missing <layer_set> node" << LL_ENDL;
- return false;
- }
-
- if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
- {
- LL_ERRS() << "avatar file: missing <morph_masks> node" << LL_ENDL;
- return false;
- }
-
- // avatar_lad.xml : <morph_masks>
- for (LLAvatarXmlInfo::LLAvatarMorphInfo* info : sAvatarXmlInfo->mMorphMaskInfoList)
- {
- EBakedTextureIndex baked = sAvatarDictionary->findBakedByRegionName(info->mRegion);
- if (baked != BAKED_NUM_INDICES)
- {
- LLVisualParam* morph_param;
- const std::string *name = &info->mName;
- morph_param = getVisualParam(name->c_str());
- if (morph_param)
- {
- bool invert = info->mInvert;
- addMaskedMorph(baked, morph_param, invert, info->mLayer);
- }
- }
-
- }
-
- loadLayersets();
-
- // avatar_lad.xml : <driver_parameters>
- for (LLDriverParamInfo* info : sAvatarXmlInfo->mDriverInfoList)
- {
- LLDriverParam* driver_param = new LLDriverParam( this );
- if (driver_param->setInfo(info))
- {
- addVisualParam( driver_param );
- driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
- LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam;
- if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false))
- {
- LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL;
- continue;
- }
- }
- else
- {
- delete driver_param;
- LL_WARNS() << "avatar file: driver_param->parseData() failed" << LL_ENDL;
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// loadSkeletonNode(): loads <skeleton> node from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::loadSkeletonNode ()
-{
- mRoot->addChild( mSkeleton[0] );
-
- // make meshes children before calling parent version of the function
- for (LLAvatarJoint* joint : mMeshLOD)
- {
- joint->mUpdateXform = false;
- joint->setMeshesToChildren();
- }
-
- mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
- mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]);
- mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
- mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
- mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
-
- LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
- if (skull)
- {
- skull->addChild(mMeshLOD[MESH_ID_HAIR] );
- }
-
- LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft");
- if (eyeL)
- {
- eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
- }
-
- LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight");
- if (eyeR)
- {
- eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
- }
-
- // SKELETAL DISTORTIONS
- {
- for (LLViewerVisualParamInfo* visual_param_info : sAvatarXmlInfo->mSkeletalDistortionInfoList)
- {
- LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)visual_param_info;
- LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
- if (!param->setInfo(info))
- {
- delete param;
- return false;
- }
- else
- {
- addVisualParam(param);
- param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
- }
- }
- }
-
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// loadMeshNodes(): loads <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::loadMeshNodes()
-{
- for (const LLAvatarXmlInfo::LLAvatarMeshInfo* info : sAvatarXmlInfo->mMeshInfoList)
- {
- const std::string &type = info->mType;
- S32 lod = info->mLOD;
-
- LLAvatarJointMesh* mesh = NULL;
- U8 mesh_id = 0;
- bool found_mesh_id = false;
-
- /* if (type == "hairMesh")
- switch(lod)
- case 0:
- mesh = &mHairMesh0; */
- for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
- {
- const EMeshIndex mesh_index = mesh_pair.first;
- const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
- if (type.compare(mesh_dict->mName) == 0)
- {
- mesh_id = mesh_index;
- found_mesh_id = true;
- break;
- }
- }
-
- if (found_mesh_id)
- {
- if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
- {
- mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
- }
- else
- {
- LL_WARNS() << "Avatar file: <mesh> has invalid lod setting " << lod << LL_ENDL;
- return false;
- }
- }
- else
- {
- LL_WARNS() << "Ignoring unrecognized mesh type: " << type << LL_ENDL;
- return false;
- }
-
- // LL_INFOS() << "Parsing mesh data for " << type << "..." << LL_ENDL;
-
- // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
- // Do not touch!!!
- mesh->setColor( LLColor4::white );
-
- LLPolyMesh *poly_mesh = NULL;
-
- if (!info->mReferenceMeshName.empty())
- {
- polymesh_map_t::const_iterator polymesh_iter = mPolyMeshes.find(info->mReferenceMeshName);
- if (polymesh_iter != mPolyMeshes.end())
- {
- poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
- poly_mesh->setAvatar(this);
- }
- else
- {
- // This should never happen
- LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
- return false;
- }
- }
- else
- {
- poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
- poly_mesh->setAvatar(this);
- }
-
- if( !poly_mesh )
- {
- LL_WARNS() << "Failed to load mesh of type " << type << LL_ENDL;
- return false;
- }
-
- // Multimap insert
- mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
-
- mesh->setMesh( poly_mesh );
- mesh->setLOD( info->mMinPixelArea );
-
- for (const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t& info_pair : info->mPolyMorphTargetInfoList)
- {
- LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
- if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair.first))
- {
- delete param;
- return false;
- }
- else
- {
- if (info_pair.second)
- {
- addSharedVisualParam(param);
- param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
- }
- else
- {
- addVisualParam(param);
- param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
- }
- }
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// loadLayerSets()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::loadLayersets()
-{
- bool success = true;
- for (LLTexLayerSetInfo* layerset_info : sAvatarXmlInfo->mLayerInfoList)
- {
- if (isSelf())
- {
- // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
- LLTexLayerSet* layer_set = createTexLayerSet();
-
- if (!layer_set->setInfo(layerset_info))
- {
- stop_glerror();
- delete layer_set;
- LL_WARNS() << "avatar file: layer_set->setInfo() failed" << LL_ENDL;
- return false;
- }
-
- // scan baked textures and associate the layerset with the appropriate one
- EBakedTextureIndex baked_index = BAKED_NUM_INDICES;
- for (const LLAvatarAppearanceDictionary::BakedTextures::value_type& baked_pair : sAvatarDictionary->getBakedTextures())
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_pair.second;
- if (layer_set->isBodyRegion(baked_dict->mName))
- {
- baked_index = baked_pair.first;
- // ensure both structures are aware of each other
- mBakedTextureDatas[baked_index].mTexLayerSet = layer_set;
- layer_set->setBakedTexIndex(baked_index);
- break;
- }
- }
- // if no baked texture was found, warn and cleanup
- if (baked_index == BAKED_NUM_INDICES)
- {
- LL_WARNS() << "<layer_set> has invalid body_region attribute" << LL_ENDL;
- delete layer_set;
- return false;
- }
-
- // scan morph masks and let any affected layers know they have an associated morph
- for (LLMaskedMorph* morph : mBakedTextureDatas[baked_index].mMaskedMorphs)
- {
- LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer);
- if (layer)
- {
- layer->setHasMorph(true);
- }
- else
- {
- LL_WARNS() << "Could not find layer named " << morph->mLayer << " to set morph flag" << LL_ENDL;
- success = false;
- }
- }
- }
- else // !isSelf()
- {
- // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
- layerset_info->createVisualParams(this);
- }
- }
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// getCharacterJoint()
-//-----------------------------------------------------------------------------
-LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
-{
- if ((S32)num >= mSkeleton.size()
- || (S32)num < 0)
- {
- return NULL;
- }
- if (!mSkeleton[num])
- {
- mSkeleton[num] = createAvatarJoint();
- }
- return mSkeleton[num];
-}
-
-
-//-----------------------------------------------------------------------------
-// getVolumePos()
-//-----------------------------------------------------------------------------
-LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_offset)
-{
- if (joint_index > mNumCollisionVolumes)
- {
- return LLVector3::zero;
- }
-
- return mCollisionVolumes[joint_index].getVolumePos(volume_offset);
-}
-
-//-----------------------------------------------------------------------------
-// findCollisionVolume()
-//-----------------------------------------------------------------------------
-LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id)
-{
- if ((volume_id < 0) || (volume_id >= mNumCollisionVolumes))
- {
- return NULL;
- }
-
- return &mCollisionVolumes[volume_id];
-}
-
-//-----------------------------------------------------------------------------
-// findCollisionVolume()
-//-----------------------------------------------------------------------------
-S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name)
-{
- for (S32 i = 0; i < mNumCollisionVolumes; i++)
- {
- if (mCollisionVolumes[i].getName() == name)
- {
- return i;
- }
- }
-
- return -1;
-}
-
-//-----------------------------------------------------------------------------
-// LLAvatarAppearance::getHeadMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh* LLAvatarAppearance::getHeadMesh()
-{
- return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLAvatarAppearance::getUpperBodyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh* LLAvatarAppearance::getUpperBodyMesh()
-{
- return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh();
-}
-
-
-
-// virtual
-bool LLAvatarAppearance::isValid() const
-{
- // This should only be called on ourself.
- if (!isSelf())
- {
- LL_ERRS() << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << LL_ENDL;
- }
- return true;
-}
-
-
-// adds a morph mask to the appropriate baked texture structure
-void LLAvatarAppearance::addMaskedMorph(EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer)
-{
- if (index < BAKED_NUM_INDICES)
- {
- LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer);
- mBakedTextureDatas[index].mMaskedMorphs.push_front(morph);
- }
-}
-
-
-//static
-bool LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
-{
- switch( te )
- {
- case TEX_UPPER_SHIRT:
- param_name[0] = 803; //"shirt_red";
- param_name[1] = 804; //"shirt_green";
- param_name[2] = 805; //"shirt_blue";
- break;
-
- case TEX_LOWER_PANTS:
- param_name[0] = 806; //"pants_red";
- param_name[1] = 807; //"pants_green";
- param_name[2] = 808; //"pants_blue";
- break;
-
- case TEX_LOWER_SHOES:
- param_name[0] = 812; //"shoes_red";
- param_name[1] = 813; //"shoes_green";
- param_name[2] = 817; //"shoes_blue";
- break;
-
- case TEX_LOWER_SOCKS:
- param_name[0] = 818; //"socks_red";
- param_name[1] = 819; //"socks_green";
- param_name[2] = 820; //"socks_blue";
- break;
-
- case TEX_UPPER_JACKET:
- case TEX_LOWER_JACKET:
- param_name[0] = 834; //"jacket_red";
- param_name[1] = 835; //"jacket_green";
- param_name[2] = 836; //"jacket_blue";
- break;
-
- case TEX_UPPER_GLOVES:
- param_name[0] = 827; //"gloves_red";
- param_name[1] = 829; //"gloves_green";
- param_name[2] = 830; //"gloves_blue";
- break;
-
- case TEX_UPPER_UNDERSHIRT:
- param_name[0] = 821; //"undershirt_red";
- param_name[1] = 822; //"undershirt_green";
- param_name[2] = 823; //"undershirt_blue";
- break;
-
- case TEX_LOWER_UNDERPANTS:
- param_name[0] = 824; //"underpants_red";
- param_name[1] = 825; //"underpants_green";
- param_name[2] = 826; //"underpants_blue";
- break;
-
- case TEX_SKIRT:
- param_name[0] = 921; //"skirt_red";
- param_name[1] = 922; //"skirt_green";
- param_name[2] = 923; //"skirt_blue";
- break;
-
- case TEX_HEAD_TATTOO:
- case TEX_LOWER_TATTOO:
- case TEX_UPPER_TATTOO:
- param_name[0] = 1071; //"tattoo_red";
- param_name[1] = 1072; //"tattoo_green";
- param_name[2] = 1073; //"tattoo_blue";
- break;
- case TEX_HEAD_UNIVERSAL_TATTOO:
- case TEX_UPPER_UNIVERSAL_TATTOO:
- case TEX_LOWER_UNIVERSAL_TATTOO:
- case TEX_SKIRT_TATTOO:
- case TEX_HAIR_TATTOO:
- case TEX_EYES_TATTOO:
- case TEX_LEFT_ARM_TATTOO:
- case TEX_LEFT_LEG_TATTOO:
- case TEX_AUX1_TATTOO:
- case TEX_AUX2_TATTOO:
- case TEX_AUX3_TATTOO:
- param_name[0] = 1238; //"tattoo_universal_red";
- param_name[1] = 1239; //"tattoo_universal_green";
- param_name[2] = 1240; //"tattoo_universal_blue";
- break;
-
- default:
- llassert(0);
- return false;
- }
-
- return true;
-}
-
-void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
-{
- U32 param_name[3];
- if( teToColorParams( te, param_name ) )
- {
- setVisualParamWeight( param_name[0], new_color.mV[VX]);
- setVisualParamWeight( param_name[1], new_color.mV[VY]);
- setVisualParamWeight( param_name[2], new_color.mV[VZ]);
- }
-}
-
-LLColor4 LLAvatarAppearance::getClothesColor( ETextureIndex te )
-{
- LLColor4 color;
- U32 param_name[3];
- if( teToColorParams( te, param_name ) )
- {
- color.mV[VX] = getVisualParamWeight( param_name[0] );
- color.mV[VY] = getVisualParamWeight( param_name[1] );
- color.mV[VZ] = getVisualParamWeight( param_name[2] );
- }
- return color;
-}
-
-// static
-LLColor4 LLAvatarAppearance::getDummyColor()
-{
- return DUMMY_COLOR;
-}
-
-LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) const
-{
- if (color_name=="skin_color" && mTexSkinColor)
- {
- return mTexSkinColor->getColor();
- }
- else if(color_name=="hair_color" && mTexHairColor)
- {
- return mTexHairColor->getColor();
- }
- if(color_name=="eye_color" && mTexEyeColor)
- {
- return mTexEyeColor->getColor();
- }
- else
- {
-// return LLColor4( .5f, .5f, .5f, .5f );
- return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color
- }
-}
-
-// Unlike most wearable functions, this works for both self and other.
-// virtual
-bool LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
-{
- return mWearableData->getWearableCount(type) > 0;
-}
-
-LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const
-{
- /* switch(index)
- case TEX_HEAD_BAKED:
- case TEX_HEAD_BODYPAINT:
- return mHeadLayerSet; */
- return mBakedTextureDatas[baked_index].mTexLayerSet;
-}
-
-//-----------------------------------------------------------------------------
-// allocateCollisionVolumes()
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::allocateCollisionVolumes( U32 num )
-{
- if (mNumCollisionVolumes !=num)
- {
- delete_and_clear_array(mCollisionVolumes);
- mNumCollisionVolumes = 0;
-
- mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
- if (!mCollisionVolumes)
- {
- LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
- return false;
- }
-
- mNumCollisionVolumes = num;
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLAvatarBoneInfo::parseXml()
-//-----------------------------------------------------------------------------
-bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
-{
- if (node->hasName("bone"))
- {
- mIsJoint = true;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!node->getFastAttributeString(name_string, mName))
- {
- LL_WARNS() << "Bone without name" << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases");
- node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required.
- }
- else if (node->hasName("collision_volume"))
- {
- mIsJoint = false;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!node->getFastAttributeString(name_string, mName))
- {
- mName = "Collision Volume";
- }
- }
- else
- {
- LL_WARNS() << "Invalid node " << node->getName() << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
- if (!node->getFastAttributeVector3(pos_string, mPos))
- {
- LL_WARNS() << "Bone without position" << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
- if (!node->getFastAttributeVector3(rot_string, mRot))
- {
- LL_WARNS() << "Bone without rotation" << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
- if (!node->getFastAttributeVector3(scale_string, mScale))
- {
- LL_WARNS() << "Bone without scale" << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end");
- if (!node->getFastAttributeVector3(end_string, mEnd))
- {
- LL_WARNS() << "Bone without end " << mName << LL_ENDL;
- mEnd = LLVector3(0.0f, 0.0f, 0.0f);
- }
-
- static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support");
- if (!node->getFastAttributeString(support_string,mSupport))
- {
- LL_WARNS() << "Bone without support " << mName << LL_ENDL;
- mSupport = "base";
- }
-
- if (mIsJoint)
- {
- static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
- if (!node->getFastAttributeVector3(pivot_string, mPivot))
- {
- LL_WARNS() << "Bone without pivot" << LL_ENDL;
- return false;
- }
- }
-
- // parse children
- LLXmlTreeNode* child;
- for( child = node->getFirstChild(); child; child = node->getNextChild() )
- {
- LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo;
- if (!child_info->parseXml(child))
- {
- delete child_info;
- return false;
- }
- mChildren.push_back(child_info);
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLAvatarSkeletonInfo::parseXml()
-//-----------------------------------------------------------------------------
-bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
-{
- static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
- if (!node->getFastAttributeS32(num_bones_string, mNumBones))
- {
- LL_WARNS() << "Couldn't find number of bones." << LL_ENDL;
- return false;
- }
-
- static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
- node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
-
- LLXmlTreeNode* child;
- for( child = node->getFirstChild(); child; child = node->getNextChild() )
- {
- LLAvatarBoneInfo *info = new LLAvatarBoneInfo;
- if (!info->parseXml(child))
- {
- delete info;
- LL_WARNS() << "Error parsing bone in skeleton file" << LL_ENDL;
- return false;
- }
- mBoneInfoList.push_back(info);
- }
- return true;
-}
-
-//Make aliases for joint and push to map.
-void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
-{
- if (! bone_info->mIsJoint )
- {
- return;
- }
-
- std::string bone_name = bone_info->mName;
- mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias.
-
- std::string aliases = bone_info->mAliases;
-
- boost::char_separator<char> sep(" ");
- boost::tokenizer<boost::char_separator<char> > tok(aliases, sep);
- for(const std::string& i : tok)
- {
- if ( mJointAliasMap.find(i) != mJointAliasMap.end() )
- {
- LL_WARNS() << "avatar skeleton: Joint alias \"" << i << "\" remapped from " << mJointAliasMap[i] << " to " << bone_name << LL_ENDL;
- }
- mJointAliasMap[i] = bone_name;
- }
-
- for (LLAvatarBoneInfo* bone : bone_info->mChildren)
- {
- makeJointAliases(bone);
- }
-}
-
-const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases ()
-{
- LLAvatarAppearance::joint_alias_map_t alias_map;
- if (mJointAliasMap.empty())
- {
-
- for (LLAvatarBoneInfo* bone_info : sAvatarSkeletonInfo->mBoneInfoList)
- {
- //LLAvatarBoneInfo *bone_info = *iter;
- makeJointAliases(bone_info);
- }
-
- for (LLAvatarXmlInfo::LLAvatarAttachmentInfo* info : sAvatarXmlInfo->mAttachmentInfoList)
- {
- std::string bone_name = info->mName;
-
- // Also accept the name with spaces substituted with
- // underscores. This gives a mechanism for referencing such joints
- // in daes, which don't allow spaces.
- std::string sub_space_to_underscore = bone_name;
- LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_');
- if (sub_space_to_underscore != bone_name)
- {
- mJointAliasMap[sub_space_to_underscore] = bone_name;
- }
- }
- }
-
- return mJointAliasMap;
-}
-
-
-//-----------------------------------------------------------------------------
-// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* node = root->getChildByName( "skeleton" );
- if( !node )
- {
- LL_WARNS() << "avatar file: missing <skeleton>" << LL_ENDL;
- return false;
- }
-
- LLXmlTreeNode* child;
-
- // SKELETON DISTORTIONS
- for (child = node->getChildByName( "param" );
- child;
- child = node->getNextNamedChild())
- {
- if (!child->getChildByName("param_skeleton"))
- {
- if (child->getChildByName("param_morph"))
- {
- LL_WARNS() << "Can't specify morph param in skeleton definition." << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Unknown param type." << LL_ENDL;
- }
- return false;
- }
-
- LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
- if (!info->parseXml(child))
- {
- delete info;
- return false;
- }
-
- mSkeletalDistortionInfoList.push_back(info);
- }
-
- // ATTACHMENT POINTS
- for (child = node->getChildByName( "attachment_point" );
- child;
- child = node->getNextNamedChild())
- {
- LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo();
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!child->getFastAttributeString(name_string, info->mName))
- {
- LL_WARNS() << "No name supplied for attachment point." << LL_ENDL;
- delete info;
- return false;
- }
-
- static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
- if (!child->getFastAttributeString(joint_string, info->mJointName))
- {
- LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL;
- delete info;
- return false;
- }
-
- static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
- if (child->getFastAttributeVector3(position_string, info->mPosition))
- {
- info->mHasPosition = true;
- }
-
- static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
- if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
- {
- info->mHasRotation = true;
- }
- static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
- if (child->getFastAttributeS32(group_string, info->mGroup))
- {
- if (info->mGroup == -1)
- info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
- }
-
- static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
- if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
- {
- LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL;
- delete info;
- return false;
- }
-
- static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
- child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
-
- static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
- child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
-
- static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
- child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
-
- mAttachmentInfoList.push_back(info);
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
- node;
- node = root->getNextNamedChild())
- {
- LLAvatarMeshInfo *info = new LLAvatarMeshInfo;
-
- // attribute: type
- static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
- if( !node->getFastAttributeString( type_string, info->mType ) )
- {
- LL_WARNS() << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << LL_ENDL;
- delete info;
- return false; // Ignore this element
- }
-
- static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
- if (!node->getFastAttributeS32( lod_string, info->mLOD ))
- {
- LL_WARNS() << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << LL_ENDL;
- delete info;
- return false; // Ignore this element
- }
-
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
- {
- LL_WARNS() << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << LL_ENDL;
- delete info;
- return false; // Ignore this element
- }
-
- static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
- node->getFastAttributeString( reference_string, info->mReferenceMeshName );
-
- // attribute: min_pixel_area
- static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
- static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
- if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
- {
- F32 min_pixel_area = 0.1f;
- if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
- {
- // this is square root of pixel area (sensible to use linear space in defining lods)
- min_pixel_area = min_pixel_area * min_pixel_area;
- }
- info->mMinPixelArea = min_pixel_area;
- }
-
- // Parse visual params for this node only if we haven't already
- for (LLXmlTreeNode* child = node->getChildByName( "param" );
- child;
- child = node->getNextNamedChild())
- {
- if (!child->getChildByName("param_morph"))
- {
- if (child->getChildByName("param_skeleton"))
- {
- LL_WARNS() << "Can't specify skeleton param in a mesh definition." << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Unknown param type." << LL_ENDL;
- }
- return false;
- }
-
- LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
- if (!morphinfo->parseXml(child))
- {
- delete morphinfo;
- delete info;
- return false;
- }
- bool shared = false;
- static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
- child->getFastAttributeBOOL(shared_string, shared);
-
- info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
- }
-
- mMeshInfoList.push_back(info);
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlColorNodes(): parses <global_color> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
- color_node;
- color_node = root->getNextNamedChild())
- {
- std::string global_color_name;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (color_node->getFastAttributeString( name_string, global_color_name ) )
- {
- if( global_color_name == "skin_color" )
- {
- if (mTexSkinColorInfo)
- {
- LL_WARNS() << "avatar file: multiple instances of skin_color" << LL_ENDL;
- return false;
- }
- mTexSkinColorInfo = new LLTexGlobalColorInfo;
- if( !mTexSkinColorInfo->parseXml( color_node ) )
- {
- delete_and_clear(mTexSkinColorInfo);
- LL_WARNS() << "avatar file: mTexSkinColor->parseXml() failed" << LL_ENDL;
- return false;
- }
- }
- else if( global_color_name == "hair_color" )
- {
- if (mTexHairColorInfo)
- {
- LL_WARNS() << "avatar file: multiple instances of hair_color" << LL_ENDL;
- return false;
- }
- mTexHairColorInfo = new LLTexGlobalColorInfo;
- if( !mTexHairColorInfo->parseXml( color_node ) )
- {
- delete_and_clear(mTexHairColorInfo);
- LL_WARNS() << "avatar file: mTexHairColor->parseXml() failed" << LL_ENDL;
- return false;
- }
- }
- else if( global_color_name == "eye_color" )
- {
- if (mTexEyeColorInfo)
- {
- LL_WARNS() << "avatar file: multiple instances of eye_color" << LL_ENDL;
- return false;
- }
- mTexEyeColorInfo = new LLTexGlobalColorInfo;
- if( !mTexEyeColorInfo->parseXml( color_node ) )
- {
- LL_WARNS() << "avatar file: mTexEyeColor->parseXml() failed" << LL_ENDL;
- return false;
- }
- }
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
- layer_node;
- layer_node = root->getNextNamedChild())
- {
- LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
- if( layer_info->parseXml( layer_node ) )
- {
- mLayerInfoList.push_back(layer_info);
- }
- else
- {
- delete layer_info;
- LL_WARNS() << "avatar file: layer_set->parseXml() failed" << LL_ENDL;
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
- if( driver )
- {
- for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
- grand_child;
- grand_child = driver->getNextNamedChild())
- {
- if( grand_child->getChildByName( "param_driver" ) )
- {
- LLDriverParamInfo* driver_info = new LLDriverParamInfo();
- if( driver_info->parseXml( grand_child ) )
- {
- mDriverInfoList.push_back(driver_info);
- }
- else
- {
- delete driver_info;
- LL_WARNS() << "avatar file: driver_param->parseXml() failed" << LL_ENDL;
- return false;
- }
- }
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
- if( !masks )
- {
- return false;
- }
-
- for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
- grand_child;
- grand_child = masks->getNextNamedChild())
- {
- LLAvatarMorphInfo* info = new LLAvatarMorphInfo();
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
- if (!grand_child->getFastAttributeString(name_string, info->mName))
- {
- LL_WARNS() << "No name supplied for morph mask." << LL_ENDL;
- delete info;
- return false;
- }
-
- static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
- if (!grand_child->getFastAttributeString(region_string, info->mRegion))
- {
- LL_WARNS() << "No region supplied for morph mask." << LL_ENDL;
- delete info;
- return false;
- }
-
- static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
- if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
- {
- LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL;
- delete info;
- return false;
- }
-
- // optional parameter. don't throw a warning if not present.
- static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
- grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
-
- mMorphMaskInfoList.push_back(info);
- }
-
- return true;
-}
-
-//virtual
-LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer) :
- mMorphTarget(morph_target),
- mInvert(invert),
- mLayer(layer)
-{
- LLPolyMorphTarget *target = dynamic_cast<LLPolyMorphTarget*>(morph_target);
- if (target)
- {
- target->addPendingMorphMask();
- }
-}
+/**
+ * @File llavatarappearance.cpp
+ * @brief Implementation of LLAvatarAppearance class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llavatarappearance.h"
+#include "llavatarappearancedefines.h"
+#include "llavatarjointmesh.h"
+#include "llstl.h"
+#include "lldir.h"
+#include "llpolymorph.h"
+#include "llpolymesh.h"
+#include "llpolyskeletaldistortion.h"
+#include "llstl.h"
+#include "lltexglobalcolor.h"
+#include "llwearabledata.h"
+#include "boost/bind.hpp"
+#include "boost/tokenizer.hpp"
+
+using namespace LLAvatarAppearanceDefines;
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+const std::string AVATAR_DEFAULT_CHAR = "avatar";
+const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
+
+/*********************************************************************************
+ ** **
+ ** Begin private LLAvatarAppearance Support classes
+ **
+ **/
+
+//------------------------------------------------------------------------
+// LLAvatarBoneInfo
+// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
+//------------------------------------------------------------------------
+class LLAvatarBoneInfo
+{
+ friend class LLAvatarAppearance;
+ friend class LLAvatarSkeletonInfo;
+public:
+ LLAvatarBoneInfo() : mIsJoint(false) {}
+ ~LLAvatarBoneInfo()
+ {
+ std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
+ mChildren.clear();
+ }
+ bool parseXml(LLXmlTreeNode* node);
+
+private:
+ std::string mName;
+ std::string mSupport;
+ std::string mAliases;
+ bool mIsJoint;
+ LLVector3 mPos;
+ LLVector3 mEnd;
+ LLVector3 mRot;
+ LLVector3 mScale;
+ LLVector3 mPivot;
+ typedef std::vector<LLAvatarBoneInfo*> bones_t;
+ bones_t mChildren;
+};
+
+//------------------------------------------------------------------------
+// LLAvatarSkeletonInfo
+// Overall avatar skeleton
+//------------------------------------------------------------------------
+class LLAvatarSkeletonInfo
+{
+ friend class LLAvatarAppearance;
+public:
+ LLAvatarSkeletonInfo() :
+ mNumBones(0), mNumCollisionVolumes(0) {}
+ ~LLAvatarSkeletonInfo()
+ {
+ std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
+ mBoneInfoList.clear();
+ }
+ bool parseXml(LLXmlTreeNode* node);
+ S32 getNumBones() const { return mNumBones; }
+ S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
+
+private:
+ S32 mNumBones;
+ S32 mNumCollisionVolumes;
+ LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
+ typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
+ bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLAvatarXmlInfo
+//-----------------------------------------------------------------------------
+
+LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo()
+ : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
+{
+}
+
+LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo()
+{
+ std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
+ mMeshInfoList.clear();
+
+ std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
+ mSkeletalDistortionInfoList.clear();
+
+ std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
+ mAttachmentInfoList.clear();
+
+ delete_and_clear(mTexSkinColorInfo);
+ delete_and_clear(mTexHairColorInfo);
+ delete_and_clear(mTexEyeColorInfo);
+
+ std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ mLayerInfoList.clear();
+
+ std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+ mDriverInfoList.clear();
+
+ std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
+ mMorphMaskInfoList.clear();
+}
+
+
+/**
+ **
+ ** End LLAvatarAppearance Support classes
+ ** **
+ *********************************************************************************/
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL;
+LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL;
+LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* LLAvatarAppearance::sAvatarDictionary = NULL;
+
+
+LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
+ LLCharacter(),
+ mIsDummy(false),
+ mTexSkinColor( NULL ),
+ mTexHairColor( NULL ),
+ mTexEyeColor( NULL ),
+ mPelvisToFoot(0.f),
+ mHeadOffset(),
+ mRoot(NULL),
+ mWearableData(wearable_data),
+ mNumBones(0),
+ mNumCollisionVolumes(0),
+ mCollisionVolumes(NULL),
+ mIsBuilt(false),
+ mInitFlags(0)
+{
+ llassert_always(mWearableData);
+ mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
+ {
+ mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR;
+ mBakedTextureDatas[i].mTexLayerSet = NULL;
+ mBakedTextureDatas[i].mIsLoaded = false;
+ mBakedTextureDatas[i].mIsUsed = false;
+ mBakedTextureDatas[i].mMaskTexName = 0;
+ mBakedTextureDatas[i].mTextureIndex = sAvatarDictionary->bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
+ }
+}
+
+// virtual
+void LLAvatarAppearance::initInstance()
+{
+ //-------------------------------------------------------------------------
+ // initialize joint, mesh and shape members
+ //-------------------------------------------------------------------------
+ mRoot = createAvatarJoint();
+ mRoot->setName( "mRoot" );
+
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ LLAvatarJoint* joint = createAvatarJoint();
+ joint->setName(mesh_dict->mName);
+ joint->setMeshID(mesh_index);
+ mMeshLOD.push_back(joint);
+
+ /* mHairLOD.setName("mHairLOD");
+ mHairMesh0.setName("mHairMesh0");
+ mHairMesh0.setMeshID(MESH_ID_HAIR);
+ mHairMesh1.setName("mHairMesh1"); */
+ for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
+ {
+ LLAvatarJointMesh* mesh = createAvatarJointMesh();
+ std::string mesh_name = "m" + mesh_dict->mName + std::to_string(lod);
+ // We pre-pended an m - need to capitalize first character for camelCase
+ mesh_name[1] = toupper(mesh_name[1]);
+ mesh->setName(mesh_name);
+ mesh->setMeshID(mesh_index);
+ mesh->setPickName(mesh_dict->mPickName);
+ mesh->setIsTransparent(false);
+ switch((S32)mesh_index)
+ {
+ case MESH_ID_HAIR:
+ mesh->setIsTransparent(true);
+ break;
+ case MESH_ID_SKIRT:
+ mesh->setIsTransparent(true);
+ break;
+ case MESH_ID_EYEBALL_LEFT:
+ case MESH_ID_EYEBALL_RIGHT:
+ mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f );
+ break;
+ }
+
+ joint->mMeshParts.push_back(mesh);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // associate baked textures with meshes
+ //-------------------------------------------------------------------------
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID;
+ // Skip it if there's no associated baked texture.
+ if (baked_texture_index == BAKED_NUM_INDICES) continue;
+
+ for (LLAvatarJointMesh* mesh : mMeshLOD[mesh_index]->mMeshParts)
+ {
+ mBakedTextureDatas[(S32)baked_texture_index].mJointMeshes.push_back(mesh);
+ }
+ }
+
+ buildCharacter();
+
+ mInitFlags |= 1<<0;
+
+}
+
+// virtual
+LLAvatarAppearance::~LLAvatarAppearance()
+{
+ delete_and_clear(mTexSkinColor);
+ delete_and_clear(mTexHairColor);
+ delete_and_clear(mTexEyeColor);
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ delete_and_clear(mBakedTextureDatas[i].mTexLayerSet);
+ mBakedTextureDatas[i].mJointMeshes.clear();
+
+ for (LLMaskedMorph* masked_morph : mBakedTextureDatas[i].mMaskedMorphs)
+ {
+ delete masked_morph;
+ }
+ }
+
+ if (mRoot)
+ {
+ mRoot->removeAllChildren();
+ delete mRoot;
+ mRoot = nullptr;
+ }
+ mJointMap.clear();
+
+ clearSkeleton();
+ delete_and_clear_array(mCollisionVolumes);
+
+ std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer());
+ mPolyMeshes.clear();
+
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
+ joint->mMeshParts.clear();
+ }
+ std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
+ mMeshLOD.clear();
+}
+
+//static
+void LLAvatarAppearance::initClass()
+{
+ initClass("","");
+}
+
+//static
+void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg)
+{
+ // init dictionary (don't repeat on second login attempt)
+ if (!sAvatarDictionary)
+ {
+ sAvatarDictionary = new LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary();
+ }
+
+ std::string avatar_file_name;
+
+ if (!avatar_file_name_arg.empty())
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg);
+ }
+ else
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml");
+ }
+ LLXmlTree xml_tree;
+ bool success = xml_tree.parseFile( avatar_file_name, false );
+ if (!success)
+ {
+ LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = xml_tree.getRoot();
+ if (!root)
+ {
+ LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // <linden_avatar version="2.0"> (root)
+ //-------------------------------------------------------------------------
+ if( !root->hasName( "linden_avatar" ) )
+ {
+ LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
+ {
+ LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL;
+ }
+
+ S32 wearable_def_version = 1;
+ static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
+ root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
+ LLWearable::setCurrentDefinitionVersion( wearable_def_version );
+
+ std::string mesh_file_name;
+
+ LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
+ if (!skeleton_node)
+ {
+ LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL;
+ return;
+ }
+
+ std::string skeleton_file_name = skeleton_file_name_arg;
+ if (skeleton_file_name.empty())
+ {
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+ {
+ LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL;
+ }
+ }
+
+ std::string skeleton_path;
+ LLXmlTree skeleton_xml_tree;
+ skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
+ if (!parseSkeletonFile(skeleton_path, skeleton_xml_tree))
+ {
+ LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL;
+ }
+
+ // Process XML data
+
+ // avatar_skeleton.xml
+ if (sAvatarSkeletonInfo)
+ { //this can happen if a login attempt failed
+ delete sAvatarSkeletonInfo;
+ }
+ sAvatarSkeletonInfo = new LLAvatarSkeletonInfo;
+ if (!sAvatarSkeletonInfo->parseXml(skeleton_xml_tree.getRoot()))
+ {
+ LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL;
+ }
+ // parse avatar_lad.xml
+ if (sAvatarXmlInfo)
+ { //this can happen if a login attempt failed
+ delete_and_clear(sAvatarXmlInfo);
+ }
+ sAvatarXmlInfo = new LLAvatarXmlInfo;
+ if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlColorNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+ if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
+ {
+ LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL;
+ }
+}
+
+void LLAvatarAppearance::cleanupClass()
+{
+ delete_and_clear(sAvatarXmlInfo);
+ delete_and_clear(sAvatarDictionary);
+ delete_and_clear(sAvatarSkeletonInfo);
+}
+
+using namespace LLAvatarAppearanceDefines;
+
+void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state,
+ joint_state_map_t& curr_state)
+{
+ if (!last_state.empty() && (last_state != curr_state))
+ {
+ S32 diff_count = 0;
+ for (joint_state_map_t::value_type& pair : last_state)
+ {
+ const std::string& key = pair.first;
+ if (last_state[key] != curr_state[key])
+ {
+ LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL;
+ diff_count++;
+ }
+ }
+ if (diff_count > 0)
+ {
+ LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL;
+ }
+
+ }
+}
+
+//------------------------------------------------------------------------
+// The viewer can only suggest a good size for the agent,
+// the simulator will keep it inside a reasonable range.
+void LLAvatarAppearance::computeBodySize()
+{
+ mLastBodySizeState = mCurrBodySizeState;
+
+ mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale();
+ mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition();
+ mCurrBodySizeState["mSkull scale"] = mSkullp->getScale();
+ mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition();
+ mCurrBodySizeState["mNeck scale"] = mNeckp->getScale();
+ mCurrBodySizeState["mChest pos"] = mChestp->getPosition();
+ mCurrBodySizeState["mChest scale"] = mChestp->getScale();
+ mCurrBodySizeState["mHead pos"] = mHeadp->getPosition();
+ mCurrBodySizeState["mHead scale"] = mHeadp->getScale();
+ mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition();
+ mCurrBodySizeState["mTorso scale"] = mTorsop->getScale();
+ mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition();
+ mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale();
+ mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition();
+ mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale();
+ mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition();
+ mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
+ mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
+
+ F32 old_height = mBodySize.mV[VZ];
+ F32 old_offset = mAvatarOffset.mV[VZ];
+
+ // TODO: Measure the real depth and width
+ mPelvisToFoot = computePelvisToFoot();
+ F32 new_height = computeBodyHeight();
+ mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height);
+ F32 new_offset = getVisualParamWeight(AVATAR_HOVER);
+ mAvatarOffset.set(0, 0, new_offset);
+
+ if (mBodySize.mV[VZ] != old_height || new_offset != old_offset)
+ {
+ compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
+ }
+}
+
+F32 LLAvatarAppearance::computeBodyHeight()
+{
+ F32 result = mPelvisToFoot +
+ // all these relative positions usually are positive
+ mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] +
+ mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] +
+ mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] +
+ mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] +
+ mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2;
+ return result;
+}
+
+F32 LLAvatarAppearance::computePelvisToFoot()
+{
+ F32 result =
+ // all these relative positions usually are negative
+ mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] +
+ mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] +
+ mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] +
+ mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2;
+ return -result;
+}
+
+//-----------------------------------------------------------------------------
+// parseSkeletonFile()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree)
+{
+ //-------------------------------------------------------------------------
+ // parse the file
+ //-------------------------------------------------------------------------
+ bool parsesuccess = skeleton_xml_tree.parseFile( filename, false );
+
+ if (!parsesuccess)
+ {
+ LL_ERRS() << "Can't parse skeleton file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = skeleton_xml_tree.getRoot();
+ if (!root)
+ {
+ LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ if( !root->hasName( "linden_skeleton" ) )
+ {
+ LL_ERRS() << "Invalid avatar skeleton file header: " << filename << LL_ENDL;
+ return false;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
+ {
+ LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// setupBone()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num)
+{
+ LLJoint* joint = NULL;
+
+ LL_DEBUGS("BVH") << "bone info: name " << info->mName
+ << " isJoint " << info->mIsJoint
+ << " volume_num " << volume_num
+ << " joint_num " << joint_num
+ << LL_ENDL;
+
+ if (info->mIsJoint)
+ {
+ joint = getCharacterJoint(joint_num);
+ if (!joint)
+ {
+ LL_WARNS() << "Too many bones" << LL_ENDL;
+ return false;
+ }
+ joint->setName( info->mName );
+ }
+ else // collision volume
+ {
+ if (volume_num >= (S32)mNumCollisionVolumes)
+ {
+ LL_WARNS() << "Too many collision volumes" << LL_ENDL;
+ return false;
+ }
+ joint = (&mCollisionVolumes[volume_num]);
+ joint->setName( info->mName );
+ }
+
+ // add to parent
+ if (parent && (joint->getParent()!=parent))
+ {
+ parent->addChild( joint );
+ }
+
+ // SL-315
+ joint->setPosition(info->mPos);
+ joint->setDefaultPosition(info->mPos);
+ joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
+ info->mRot.mV[VZ], LLQuaternion::XYZ));
+ joint->setScale(info->mScale);
+ joint->setDefaultScale(info->mScale);
+ joint->setSupport(info->mSupport);
+ joint->setEnd(info->mEnd);
+
+ if (info->mIsJoint)
+ {
+ joint->setSkinOffset( info->mPivot );
+ joint->setJointNum(joint_num);
+ joint_num++;
+ }
+ else // collision volume
+ {
+ joint->setJointNum(mNumBones+volume_num);
+ volume_num++;
+ }
+
+
+ // setup children
+ for (LLAvatarBoneInfo* child_info : info->mChildren)
+ {
+ if (!setupBone(child_info, joint, volume_num, joint_num))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// allocateCharacterJoints()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::allocateCharacterJoints( U32 num )
+{
+ if (mSkeleton.size() != num)
+ {
+ clearSkeleton();
+ mSkeleton = avatar_joint_list_t(num,NULL);
+ mNumBones = num;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// buildSkeleton()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
+{
+ LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
+
+ // allocate joints
+ if (!allocateCharacterJoints(info->mNumBones))
+ {
+ LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL;
+ return false;
+ }
+
+ // allocate volumes
+ if (info->mNumCollisionVolumes)
+ {
+ if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
+ {
+ LL_ERRS() << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << LL_ENDL;
+ return false;
+ }
+ }
+
+ S32 current_joint_num = 0;
+ S32 current_volume_num = 0;
+ for (LLAvatarBoneInfo* bone_info : info->mBoneInfoList)
+ {
+ if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num))
+ {
+ LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// clearSkeleton()
+//-----------------------------------------------------------------------------
+void LLAvatarAppearance::clearSkeleton()
+{
+ std::for_each(mSkeleton.begin(), mSkeleton.end(), DeletePointer());
+ mSkeleton.clear();
+}
+
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id )
+{
+ LLVector3 pos(0.0,0.0,fixup);
+ mPelvisFixups.add(mesh_id,pos);
+}
+
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id )
+{
+ mPelvisFixups.remove(mesh_id);
+}
+
+//------------------------------------------------------------------------
+// hasPelvisFixup
+//------------------------------------------------------------------------
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const
+{
+ LLVector3 pos;
+ if (mPelvisFixups.findActiveOverride(mesh_id,pos))
+ {
+ fixup = pos[2];
+ return true;
+ }
+ return false;
+}
+
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const
+{
+ LLUUID mesh_id;
+ return hasPelvisFixup( fixup, mesh_id );
+}
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::buildCharacter()
+// Deferred initialization and rebuild of the avatar.
+//-----------------------------------------------------------------------------
+void LLAvatarAppearance::buildCharacter()
+{
+ //-------------------------------------------------------------------------
+ // remove all references to our existing skeleton
+ // so we can rebuild it
+ //-------------------------------------------------------------------------
+ flushAllMotions();
+
+ //-------------------------------------------------------------------------
+ // remove all of mRoot's children
+ //-------------------------------------------------------------------------
+ mRoot->removeAllChildren();
+ mJointMap.clear();
+ mIsBuilt = false;
+
+ //-------------------------------------------------------------------------
+ // clear mesh data
+ //-------------------------------------------------------------------------
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ for (LLAvatarJointMesh* mesh : joint->mMeshParts)
+ {
+ mesh->setMesh(NULL);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // (re)load our skeleton and meshes
+ //-------------------------------------------------------------------------
+ LLTimer timer;
+
+ bool status = loadAvatar();
+ stop_glerror();
+
+// gPrintMessagesThisFrame = true;
+ LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
+
+ if (!status)
+ {
+ if (isSelf())
+ {
+ LL_ERRS() << "Unable to load user's avatar" << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unable to load other's avatar" << LL_ENDL;
+ }
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize "well known" joint pointers
+ //-------------------------------------------------------------------------
+ mPelvisp = mRoot->findJoint("mPelvis");
+ mTorsop = mRoot->findJoint("mTorso");
+ mChestp = mRoot->findJoint("mChest");
+ mNeckp = mRoot->findJoint("mNeck");
+ mHeadp = mRoot->findJoint("mHead");
+ mSkullp = mRoot->findJoint("mSkull");
+ mHipLeftp = mRoot->findJoint("mHipLeft");
+ mHipRightp = mRoot->findJoint("mHipRight");
+ mKneeLeftp = mRoot->findJoint("mKneeLeft");
+ mKneeRightp = mRoot->findJoint("mKneeRight");
+ mAnkleLeftp = mRoot->findJoint("mAnkleLeft");
+ mAnkleRightp = mRoot->findJoint("mAnkleRight");
+ mFootLeftp = mRoot->findJoint("mFootLeft");
+ mFootRightp = mRoot->findJoint("mFootRight");
+ mWristLeftp = mRoot->findJoint("mWristLeft");
+ mWristRightp = mRoot->findJoint("mWristRight");
+ mEyeLeftp = mRoot->findJoint("mEyeLeft");
+ mEyeRightp = mRoot->findJoint("mEyeRight");
+
+ //-------------------------------------------------------------------------
+ // Make sure "well known" pointers exist
+ //-------------------------------------------------------------------------
+ if (!(mPelvisp &&
+ mTorsop &&
+ mChestp &&
+ mNeckp &&
+ mHeadp &&
+ mSkullp &&
+ mHipLeftp &&
+ mHipRightp &&
+ mKneeLeftp &&
+ mKneeRightp &&
+ mAnkleLeftp &&
+ mAnkleRightp &&
+ mFootLeftp &&
+ mFootRightp &&
+ mWristLeftp &&
+ mWristRightp &&
+ mEyeLeftp &&
+ mEyeRightp))
+ {
+ LL_ERRS() << "Failed to create avatar." << LL_ENDL;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize the pelvis
+ //-------------------------------------------------------------------------
+ // SL-315
+ mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
+
+ mIsBuilt = true;
+ stop_glerror();
+
+}
+
+bool LLAvatarAppearance::loadAvatar()
+{
+// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR);
+
+ // avatar_skeleton.xml
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ LL_ERRS() << "avatar file: buildSkeleton() failed" << LL_ENDL;
+ return false;
+ }
+
+ // initialize mJointAliasMap
+ getJointAliases();
+
+ // avatar_lad.xml : <skeleton>
+ if( !loadSkeletonNode() )
+ {
+ LL_ERRS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <mesh>
+ if( !loadMeshNodes() )
+ {
+ LL_ERRS() << "avatar file: loadNodeMesh() failed" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <global_color>
+ if( sAvatarXmlInfo->mTexSkinColorInfo )
+ {
+ mTexSkinColor = new LLTexGlobalColor( this );
+ if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL;
+ return false;
+ }
+ if( sAvatarXmlInfo->mTexHairColorInfo )
+ {
+ mTexHairColor = new LLTexGlobalColor( this );
+ if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL;
+ return false;
+ }
+ if( sAvatarXmlInfo->mTexEyeColorInfo )
+ {
+ mTexEyeColor = new LLTexGlobalColor( this );
+ if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
+ {
+ LL_ERRS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_ERRS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <layer_set>
+ if (sAvatarXmlInfo->mLayerInfoList.empty())
+ {
+ LL_ERRS() << "avatar file: missing <layer_set> node" << LL_ENDL;
+ return false;
+ }
+
+ if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
+ {
+ LL_ERRS() << "avatar file: missing <morph_masks> node" << LL_ENDL;
+ return false;
+ }
+
+ // avatar_lad.xml : <morph_masks>
+ for (LLAvatarXmlInfo::LLAvatarMorphInfo* info : sAvatarXmlInfo->mMorphMaskInfoList)
+ {
+ EBakedTextureIndex baked = sAvatarDictionary->findBakedByRegionName(info->mRegion);
+ if (baked != BAKED_NUM_INDICES)
+ {
+ LLVisualParam* morph_param;
+ const std::string *name = &info->mName;
+ morph_param = getVisualParam(name->c_str());
+ if (morph_param)
+ {
+ bool invert = info->mInvert;
+ addMaskedMorph(baked, morph_param, invert, info->mLayer);
+ }
+ }
+
+ }
+
+ loadLayersets();
+
+ // avatar_lad.xml : <driver_parameters>
+ for (LLDriverParamInfo* info : sAvatarXmlInfo->mDriverInfoList)
+ {
+ LLDriverParam* driver_param = new LLDriverParam( this );
+ if (driver_param->setInfo(info))
+ {
+ addVisualParam( driver_param );
+ driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam;
+ if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false))
+ {
+ LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL;
+ continue;
+ }
+ }
+ else
+ {
+ delete driver_param;
+ LL_WARNS() << "avatar file: driver_param->parseData() failed" << LL_ENDL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadSkeletonNode(): loads <skeleton> node from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadSkeletonNode ()
+{
+ mRoot->addChild( mSkeleton[0] );
+
+ // make meshes children before calling parent version of the function
+ for (LLAvatarJoint* joint : mMeshLOD)
+ {
+ joint->mUpdateXform = false;
+ joint->setMeshesToChildren();
+ }
+
+ mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
+ mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]);
+ mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
+ mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
+ mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
+
+ LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
+ if (skull)
+ {
+ skull->addChild(mMeshLOD[MESH_ID_HAIR] );
+ }
+
+ LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft");
+ if (eyeL)
+ {
+ eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
+ }
+
+ LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight");
+ if (eyeR)
+ {
+ eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
+ }
+
+ // SKELETAL DISTORTIONS
+ {
+ for (LLViewerVisualParamInfo* visual_param_info : sAvatarXmlInfo->mSkeletalDistortionInfoList)
+ {
+ LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)visual_param_info;
+ LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
+ if (!param->setInfo(info))
+ {
+ delete param;
+ return false;
+ }
+ else
+ {
+ addVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ }
+ }
+
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadMeshNodes(): loads <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadMeshNodes()
+{
+ for (const LLAvatarXmlInfo::LLAvatarMeshInfo* info : sAvatarXmlInfo->mMeshInfoList)
+ {
+ const std::string &type = info->mType;
+ S32 lod = info->mLOD;
+
+ LLAvatarJointMesh* mesh = NULL;
+ U8 mesh_id = 0;
+ bool found_mesh_id = false;
+
+ /* if (type == "hairMesh")
+ switch(lod)
+ case 0:
+ mesh = &mHairMesh0; */
+ for (const LLAvatarAppearanceDictionary::MeshEntries::value_type& mesh_pair : sAvatarDictionary->getMeshEntries())
+ {
+ const EMeshIndex mesh_index = mesh_pair.first;
+ const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_pair.second;
+ if (type.compare(mesh_dict->mName) == 0)
+ {
+ mesh_id = mesh_index;
+ found_mesh_id = true;
+ break;
+ }
+ }
+
+ if (found_mesh_id)
+ {
+ if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
+ {
+ mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
+ }
+ else
+ {
+ LL_WARNS() << "Avatar file: <mesh> has invalid lod setting " << lod << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Ignoring unrecognized mesh type: " << type << LL_ENDL;
+ return false;
+ }
+
+ // LL_INFOS() << "Parsing mesh data for " << type << "..." << LL_ENDL;
+
+ // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
+ // Do not touch!!!
+ mesh->setColor( LLColor4::white );
+
+ LLPolyMesh *poly_mesh = NULL;
+
+ if (!info->mReferenceMeshName.empty())
+ {
+ polymesh_map_t::const_iterator polymesh_iter = mPolyMeshes.find(info->mReferenceMeshName);
+ if (polymesh_iter != mPolyMeshes.end())
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
+ poly_mesh->setAvatar(this);
+ }
+ else
+ {
+ // This should never happen
+ LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
+ poly_mesh->setAvatar(this);
+ }
+
+ if( !poly_mesh )
+ {
+ LL_WARNS() << "Failed to load mesh of type " << type << LL_ENDL;
+ return false;
+ }
+
+ // Multimap insert
+ mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
+
+ mesh->setMesh( poly_mesh );
+ mesh->setLOD( info->mMinPixelArea );
+
+ for (const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t& info_pair : info->mPolyMorphTargetInfoList)
+ {
+ LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
+ if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair.first))
+ {
+ delete param;
+ return false;
+ }
+ else
+ {
+ if (info_pair.second)
+ {
+ addSharedVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ else
+ {
+ addVisualParam(param);
+ param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// loadLayerSets()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::loadLayersets()
+{
+ bool success = true;
+ for (LLTexLayerSetInfo* layerset_info : sAvatarXmlInfo->mLayerInfoList)
+ {
+ if (isSelf())
+ {
+ // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+ LLTexLayerSet* layer_set = createTexLayerSet();
+
+ if (!layer_set->setInfo(layerset_info))
+ {
+ stop_glerror();
+ delete layer_set;
+ LL_WARNS() << "avatar file: layer_set->setInfo() failed" << LL_ENDL;
+ return false;
+ }
+
+ // scan baked textures and associate the layerset with the appropriate one
+ EBakedTextureIndex baked_index = BAKED_NUM_INDICES;
+ for (const LLAvatarAppearanceDictionary::BakedTextures::value_type& baked_pair : sAvatarDictionary->getBakedTextures())
+ {
+ const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_pair.second;
+ if (layer_set->isBodyRegion(baked_dict->mName))
+ {
+ baked_index = baked_pair.first;
+ // ensure both structures are aware of each other
+ mBakedTextureDatas[baked_index].mTexLayerSet = layer_set;
+ layer_set->setBakedTexIndex(baked_index);
+ break;
+ }
+ }
+ // if no baked texture was found, warn and cleanup
+ if (baked_index == BAKED_NUM_INDICES)
+ {
+ LL_WARNS() << "<layer_set> has invalid body_region attribute" << LL_ENDL;
+ delete layer_set;
+ return false;
+ }
+
+ // scan morph masks and let any affected layers know they have an associated morph
+ for (LLMaskedMorph* morph : mBakedTextureDatas[baked_index].mMaskedMorphs)
+ {
+ LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer);
+ if (layer)
+ {
+ layer->setHasMorph(true);
+ }
+ else
+ {
+ LL_WARNS() << "Could not find layer named " << morph->mLayer << " to set morph flag" << LL_ENDL;
+ success = false;
+ }
+ }
+ }
+ else // !isSelf()
+ {
+ // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+ layerset_info->createVisualParams(this);
+ }
+ }
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// getCharacterJoint()
+//-----------------------------------------------------------------------------
+LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
+{
+ if ((S32)num >= mSkeleton.size()
+ || (S32)num < 0)
+ {
+ return NULL;
+ }
+ if (!mSkeleton[num])
+ {
+ mSkeleton[num] = createAvatarJoint();
+ }
+ return mSkeleton[num];
+}
+
+
+//-----------------------------------------------------------------------------
+// getVolumePos()
+//-----------------------------------------------------------------------------
+LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_offset)
+{
+ if (joint_index > mNumCollisionVolumes)
+ {
+ return LLVector3::zero;
+ }
+
+ return mCollisionVolumes[joint_index].getVolumePos(volume_offset);
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id)
+{
+ if ((volume_id < 0) || (volume_id >= mNumCollisionVolumes))
+ {
+ return NULL;
+ }
+
+ return &mCollisionVolumes[volume_id];
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name)
+{
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ if (mCollisionVolumes[i].getName() == name)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::getHeadMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLAvatarAppearance::getHeadMesh()
+{
+ return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::getUpperBodyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLAvatarAppearance::getUpperBodyMesh()
+{
+ return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh();
+}
+
+
+
+// virtual
+bool LLAvatarAppearance::isValid() const
+{
+ // This should only be called on ourself.
+ if (!isSelf())
+ {
+ LL_ERRS() << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << LL_ENDL;
+ }
+ return true;
+}
+
+
+// adds a morph mask to the appropriate baked texture structure
+void LLAvatarAppearance::addMaskedMorph(EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer)
+{
+ if (index < BAKED_NUM_INDICES)
+ {
+ LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer);
+ mBakedTextureDatas[index].mMaskedMorphs.push_front(morph);
+ }
+}
+
+
+//static
+bool LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
+{
+ switch( te )
+ {
+ case TEX_UPPER_SHIRT:
+ param_name[0] = 803; //"shirt_red";
+ param_name[1] = 804; //"shirt_green";
+ param_name[2] = 805; //"shirt_blue";
+ break;
+
+ case TEX_LOWER_PANTS:
+ param_name[0] = 806; //"pants_red";
+ param_name[1] = 807; //"pants_green";
+ param_name[2] = 808; //"pants_blue";
+ break;
+
+ case TEX_LOWER_SHOES:
+ param_name[0] = 812; //"shoes_red";
+ param_name[1] = 813; //"shoes_green";
+ param_name[2] = 817; //"shoes_blue";
+ break;
+
+ case TEX_LOWER_SOCKS:
+ param_name[0] = 818; //"socks_red";
+ param_name[1] = 819; //"socks_green";
+ param_name[2] = 820; //"socks_blue";
+ break;
+
+ case TEX_UPPER_JACKET:
+ case TEX_LOWER_JACKET:
+ param_name[0] = 834; //"jacket_red";
+ param_name[1] = 835; //"jacket_green";
+ param_name[2] = 836; //"jacket_blue";
+ break;
+
+ case TEX_UPPER_GLOVES:
+ param_name[0] = 827; //"gloves_red";
+ param_name[1] = 829; //"gloves_green";
+ param_name[2] = 830; //"gloves_blue";
+ break;
+
+ case TEX_UPPER_UNDERSHIRT:
+ param_name[0] = 821; //"undershirt_red";
+ param_name[1] = 822; //"undershirt_green";
+ param_name[2] = 823; //"undershirt_blue";
+ break;
+
+ case TEX_LOWER_UNDERPANTS:
+ param_name[0] = 824; //"underpants_red";
+ param_name[1] = 825; //"underpants_green";
+ param_name[2] = 826; //"underpants_blue";
+ break;
+
+ case TEX_SKIRT:
+ param_name[0] = 921; //"skirt_red";
+ param_name[1] = 922; //"skirt_green";
+ param_name[2] = 923; //"skirt_blue";
+ break;
+
+ case TEX_HEAD_TATTOO:
+ case TEX_LOWER_TATTOO:
+ case TEX_UPPER_TATTOO:
+ param_name[0] = 1071; //"tattoo_red";
+ param_name[1] = 1072; //"tattoo_green";
+ param_name[2] = 1073; //"tattoo_blue";
+ break;
+ case TEX_HEAD_UNIVERSAL_TATTOO:
+ case TEX_UPPER_UNIVERSAL_TATTOO:
+ case TEX_LOWER_UNIVERSAL_TATTOO:
+ case TEX_SKIRT_TATTOO:
+ case TEX_HAIR_TATTOO:
+ case TEX_EYES_TATTOO:
+ case TEX_LEFT_ARM_TATTOO:
+ case TEX_LEFT_LEG_TATTOO:
+ case TEX_AUX1_TATTOO:
+ case TEX_AUX2_TATTOO:
+ case TEX_AUX3_TATTOO:
+ param_name[0] = 1238; //"tattoo_universal_red";
+ param_name[1] = 1239; //"tattoo_universal_green";
+ param_name[2] = 1240; //"tattoo_universal_blue";
+ break;
+
+ default:
+ llassert(0);
+ return false;
+ }
+
+ return true;
+}
+
+void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
+{
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ setVisualParamWeight( param_name[0], new_color.mV[VX]);
+ setVisualParamWeight( param_name[1], new_color.mV[VY]);
+ setVisualParamWeight( param_name[2], new_color.mV[VZ]);
+ }
+}
+
+LLColor4 LLAvatarAppearance::getClothesColor( ETextureIndex te )
+{
+ LLColor4 color;
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ color.mV[VX] = getVisualParamWeight( param_name[0] );
+ color.mV[VY] = getVisualParamWeight( param_name[1] );
+ color.mV[VZ] = getVisualParamWeight( param_name[2] );
+ }
+ return color;
+}
+
+// static
+LLColor4 LLAvatarAppearance::getDummyColor()
+{
+ return DUMMY_COLOR;
+}
+
+LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) const
+{
+ if (color_name=="skin_color" && mTexSkinColor)
+ {
+ return mTexSkinColor->getColor();
+ }
+ else if(color_name=="hair_color" && mTexHairColor)
+ {
+ return mTexHairColor->getColor();
+ }
+ if(color_name=="eye_color" && mTexEyeColor)
+ {
+ return mTexEyeColor->getColor();
+ }
+ else
+ {
+// return LLColor4( .5f, .5f, .5f, .5f );
+ return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color
+ }
+}
+
+// Unlike most wearable functions, this works for both self and other.
+// virtual
+bool LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
+{
+ return mWearableData->getWearableCount(type) > 0;
+}
+
+LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const
+{
+ /* switch(index)
+ case TEX_HEAD_BAKED:
+ case TEX_HEAD_BODYPAINT:
+ return mHeadLayerSet; */
+ return mBakedTextureDatas[baked_index].mTexLayerSet;
+}
+
+//-----------------------------------------------------------------------------
+// allocateCollisionVolumes()
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::allocateCollisionVolumes( U32 num )
+{
+ if (mNumCollisionVolumes !=num)
+ {
+ delete_and_clear_array(mCollisionVolumes);
+ mNumCollisionVolumes = 0;
+
+ mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
+ if (!mCollisionVolumes)
+ {
+ LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
+ return false;
+ }
+
+ mNumCollisionVolumes = num;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarBoneInfo::parseXml()
+//-----------------------------------------------------------------------------
+bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
+{
+ if (node->hasName("bone"))
+ {
+ mIsJoint = true;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ LL_WARNS() << "Bone without name" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases");
+ node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required.
+ }
+ else if (node->hasName("collision_volume"))
+ {
+ mIsJoint = false;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ mName = "Collision Volume";
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Invalid node " << node->getName() << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+ if (!node->getFastAttributeVector3(pos_string, mPos))
+ {
+ LL_WARNS() << "Bone without position" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
+ if (!node->getFastAttributeVector3(rot_string, mRot))
+ {
+ LL_WARNS() << "Bone without rotation" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!node->getFastAttributeVector3(scale_string, mScale))
+ {
+ LL_WARNS() << "Bone without scale" << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end");
+ if (!node->getFastAttributeVector3(end_string, mEnd))
+ {
+ LL_WARNS() << "Bone without end " << mName << LL_ENDL;
+ mEnd = LLVector3(0.0f, 0.0f, 0.0f);
+ }
+
+ static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support");
+ if (!node->getFastAttributeString(support_string,mSupport))
+ {
+ LL_WARNS() << "Bone without support " << mName << LL_ENDL;
+ mSupport = "base";
+ }
+
+ if (mIsJoint)
+ {
+ static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
+ if (!node->getFastAttributeVector3(pivot_string, mPivot))
+ {
+ LL_WARNS() << "Bone without pivot" << LL_ENDL;
+ return false;
+ }
+ }
+
+ // parse children
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo;
+ if (!child_info->parseXml(child))
+ {
+ delete child_info;
+ return false;
+ }
+ mChildren.push_back(child_info);
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarSkeletonInfo::parseXml()
+//-----------------------------------------------------------------------------
+bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
+{
+ static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
+ if (!node->getFastAttributeS32(num_bones_string, mNumBones))
+ {
+ LL_WARNS() << "Couldn't find number of bones." << LL_ENDL;
+ return false;
+ }
+
+ static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
+ node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
+
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLAvatarBoneInfo *info = new LLAvatarBoneInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ LL_WARNS() << "Error parsing bone in skeleton file" << LL_ENDL;
+ return false;
+ }
+ mBoneInfoList.push_back(info);
+ }
+ return true;
+}
+
+//Make aliases for joint and push to map.
+void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
+{
+ if (! bone_info->mIsJoint )
+ {
+ return;
+ }
+
+ std::string bone_name = bone_info->mName;
+ mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias.
+
+ std::string aliases = bone_info->mAliases;
+
+ boost::char_separator<char> sep(" ");
+ boost::tokenizer<boost::char_separator<char> > tok(aliases, sep);
+ for(const std::string& i : tok)
+ {
+ if ( mJointAliasMap.find(i) != mJointAliasMap.end() )
+ {
+ LL_WARNS() << "avatar skeleton: Joint alias \"" << i << "\" remapped from " << mJointAliasMap[i] << " to " << bone_name << LL_ENDL;
+ }
+ mJointAliasMap[i] = bone_name;
+ }
+
+ for (LLAvatarBoneInfo* bone : bone_info->mChildren)
+ {
+ makeJointAliases(bone);
+ }
+}
+
+const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases ()
+{
+ LLAvatarAppearance::joint_alias_map_t alias_map;
+ if (mJointAliasMap.empty())
+ {
+
+ for (LLAvatarBoneInfo* bone_info : sAvatarSkeletonInfo->mBoneInfoList)
+ {
+ //LLAvatarBoneInfo *bone_info = *iter;
+ makeJointAliases(bone_info);
+ }
+
+ for (LLAvatarXmlInfo::LLAvatarAttachmentInfo* info : sAvatarXmlInfo->mAttachmentInfoList)
+ {
+ std::string bone_name = info->mName;
+
+ // Also accept the name with spaces substituted with
+ // underscores. This gives a mechanism for referencing such joints
+ // in daes, which don't allow spaces.
+ std::string sub_space_to_underscore = bone_name;
+ LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_');
+ if (sub_space_to_underscore != bone_name)
+ {
+ mJointAliasMap[sub_space_to_underscore] = bone_name;
+ }
+ }
+ }
+
+ return mJointAliasMap;
+}
+
+
+//-----------------------------------------------------------------------------
+// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* node = root->getChildByName( "skeleton" );
+ if( !node )
+ {
+ LL_WARNS() << "avatar file: missing <skeleton>" << LL_ENDL;
+ return false;
+ }
+
+ LLXmlTreeNode* child;
+
+ // SKELETON DISTORTIONS
+ for (child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_skeleton"))
+ {
+ if (child->getChildByName("param_morph"))
+ {
+ LL_WARNS() << "Can't specify morph param in skeleton definition." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unknown param type." << LL_ENDL;
+ }
+ return false;
+ }
+
+ LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return false;
+ }
+
+ mSkeletalDistortionInfoList.push_back(info);
+ }
+
+ // ATTACHMENT POINTS
+ for (child = node->getChildByName( "attachment_point" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!child->getFastAttributeString(name_string, info->mName))
+ {
+ LL_WARNS() << "No name supplied for attachment point." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
+ if (!child->getFastAttributeString(joint_string, info->mJointName))
+ {
+ LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
+ if (child->getFastAttributeVector3(position_string, info->mPosition))
+ {
+ info->mHasPosition = true;
+ }
+
+ static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
+ if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
+ {
+ info->mHasRotation = true;
+ }
+ static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
+ if (child->getFastAttributeS32(group_string, info->mGroup))
+ {
+ if (info->mGroup == -1)
+ info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
+ }
+
+ static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+ if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
+ {
+ LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
+ child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
+
+ static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
+ child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
+
+ static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
+ child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
+
+ mAttachmentInfoList.push_back(info);
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
+ node;
+ node = root->getNextNamedChild())
+ {
+ LLAvatarMeshInfo *info = new LLAvatarMeshInfo;
+
+ // attribute: type
+ static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
+ if( !node->getFastAttributeString( type_string, info->mType ) )
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
+ if (!node->getFastAttributeS32( lod_string, info->mLOD ))
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
+ {
+ LL_WARNS() << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << LL_ENDL;
+ delete info;
+ return false; // Ignore this element
+ }
+
+ static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
+ node->getFastAttributeString( reference_string, info->mReferenceMeshName );
+
+ // attribute: min_pixel_area
+ static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
+ static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
+ if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
+ {
+ F32 min_pixel_area = 0.1f;
+ if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
+ {
+ // this is square root of pixel area (sensible to use linear space in defining lods)
+ min_pixel_area = min_pixel_area * min_pixel_area;
+ }
+ info->mMinPixelArea = min_pixel_area;
+ }
+
+ // Parse visual params for this node only if we haven't already
+ for (LLXmlTreeNode* child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_morph"))
+ {
+ if (child->getChildByName("param_skeleton"))
+ {
+ LL_WARNS() << "Can't specify skeleton param in a mesh definition." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Unknown param type." << LL_ENDL;
+ }
+ return false;
+ }
+
+ LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
+ if (!morphinfo->parseXml(child))
+ {
+ delete morphinfo;
+ delete info;
+ return false;
+ }
+ bool shared = false;
+ static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
+ child->getFastAttributeBOOL(shared_string, shared);
+
+ info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
+ }
+
+ mMeshInfoList.push_back(info);
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlColorNodes(): parses <global_color> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
+ color_node;
+ color_node = root->getNextNamedChild())
+ {
+ std::string global_color_name;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (color_node->getFastAttributeString( name_string, global_color_name ) )
+ {
+ if( global_color_name == "skin_color" )
+ {
+ if (mTexSkinColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of skin_color" << LL_ENDL;
+ return false;
+ }
+ mTexSkinColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexSkinColorInfo->parseXml( color_node ) )
+ {
+ delete_and_clear(mTexSkinColorInfo);
+ LL_WARNS() << "avatar file: mTexSkinColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else if( global_color_name == "hair_color" )
+ {
+ if (mTexHairColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of hair_color" << LL_ENDL;
+ return false;
+ }
+ mTexHairColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexHairColorInfo->parseXml( color_node ) )
+ {
+ delete_and_clear(mTexHairColorInfo);
+ LL_WARNS() << "avatar file: mTexHairColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ else if( global_color_name == "eye_color" )
+ {
+ if (mTexEyeColorInfo)
+ {
+ LL_WARNS() << "avatar file: multiple instances of eye_color" << LL_ENDL;
+ return false;
+ }
+ mTexEyeColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexEyeColorInfo->parseXml( color_node ) )
+ {
+ LL_WARNS() << "avatar file: mTexEyeColor->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
+ layer_node;
+ layer_node = root->getNextNamedChild())
+ {
+ LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
+ if( layer_info->parseXml( layer_node ) )
+ {
+ mLayerInfoList.push_back(layer_info);
+ }
+ else
+ {
+ delete layer_info;
+ LL_WARNS() << "avatar file: layer_set->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
+ if( driver )
+ {
+ for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
+ grand_child;
+ grand_child = driver->getNextNamedChild())
+ {
+ if( grand_child->getChildByName( "param_driver" ) )
+ {
+ LLDriverParamInfo* driver_info = new LLDriverParamInfo();
+ if( driver_info->parseXml( grand_child ) )
+ {
+ mDriverInfoList.push_back(driver_info);
+ }
+ else
+ {
+ delete driver_info;
+ LL_WARNS() << "avatar file: driver_param->parseXml() failed" << LL_ENDL;
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+bool LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
+ if( !masks )
+ {
+ return false;
+ }
+
+ for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
+ grand_child;
+ grand_child = masks->getNextNamedChild())
+ {
+ LLAvatarMorphInfo* info = new LLAvatarMorphInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
+ if (!grand_child->getFastAttributeString(name_string, info->mName))
+ {
+ LL_WARNS() << "No name supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
+ if (!grand_child->getFastAttributeString(region_string, info->mRegion))
+ {
+ LL_WARNS() << "No region supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
+ if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
+ {
+ LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL;
+ delete info;
+ return false;
+ }
+
+ // optional parameter. don't throw a warning if not present.
+ static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
+ grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
+
+ mMorphMaskInfoList.push_back(info);
+ }
+
+ return true;
+}
+
+//virtual
+LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer) :
+ mMorphTarget(morph_target),
+ mInvert(invert),
+ mLayer(layer)
+{
+ LLPolyMorphTarget *target = dynamic_cast<LLPolyMorphTarget*>(morph_target);
+ if (target)
+ {
+ target->addPendingMorphMask();
+ }
+}
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index dd16a27a3c..29221cde15 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -1,469 +1,471 @@
-/**
- * @file llavatarappearance.h
- * @brief Declaration 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$
- */
-
-#ifndef LL_AVATAR_APPEARANCE_H
-#define LL_AVATAR_APPEARANCE_H
-
-#include "llcharacter.h"
-#include "llavatarappearancedefines.h"
-#include "llavatarjointmesh.h"
-#include "lldriverparam.h"
-#include "lltexlayer.h"
-#include "llviewervisualparam.h"
-#include "llxmltree.h"
-
-class LLTexLayerSet;
-class LLTexGlobalColor;
-class LLTexGlobalColorInfo;
-class LLWearableData;
-class LLAvatarBoneInfo;
-class LLAvatarSkeletonInfo;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLAvatarAppearance
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLAvatarAppearance : public LLCharacter
-{
- LOG_CLASS(LLAvatarAppearance);
-
-protected:
- struct LLAvatarXmlInfo;
-
-/********************************************************************************
- ** **
- ** INITIALIZATION
- **/
-private:
- // Hide default constructor.
- LLAvatarAppearance() {}
-
-public:
- LLAvatarAppearance(LLWearableData* wearable_data);
- virtual ~LLAvatarAppearance();
-
- static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members
- static void initClass();
- static void cleanupClass(); // Cleanup data that's only init'd once per class.
- virtual void initInstance(); // Called after construction to initialize the instance.
- S32 mInitFlags;
- virtual bool loadSkeletonNode();
- bool loadMeshNodes();
- bool loadLayersets();
-
-
-/** Initialization
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** INHERITED
- **/
-
- //--------------------------------------------------------------------
- // LLCharacter interface and related
- //--------------------------------------------------------------------
-public:
- /*virtual*/ LLJoint* getCharacterJoint(U32 num);
-
- /*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
- /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
- /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id);
- /*virtual*/ S32 getCollisionVolumeID(std::string &name);
- /*virtual*/ LLPolyMesh* getHeadMesh();
- /*virtual*/ LLPolyMesh* getUpperBodyMesh();
-
-/** Inherited
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** STATE
- **/
-public:
- virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
- virtual bool isValid() const;
- virtual bool isUsingLocalAppearance() const = 0;
- virtual bool isEditingAppearance() const = 0;
-
- bool isBuilt() const { return mIsBuilt; }
-
-
-/** State
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** SKELETON
- **/
-
-protected:
- virtual LLAvatarJoint* createAvatarJoint() = 0;
- virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0;
- virtual LLAvatarJointMesh* createAvatarJointMesh() = 0;
- void makeJointAliases(LLAvatarBoneInfo *bone_info);
-
-
-public:
- F32 getPelvisToFoot() const { return mPelvisToFoot; }
- /*virtual*/ LLJoint* getRootJoint() { return mRoot; }
-
- LLVector3 mHeadOffset; // current head position
- LLAvatarJoint *mRoot;
-
- typedef std::map<std::string, LLJoint*> joint_map_t;
- joint_map_t mJointMap;
-
- typedef std::map<std::string, LLVector3> joint_state_map_t;
- joint_state_map_t mLastBodySizeState;
- joint_state_map_t mCurrBodySizeState;
- void compareJointStateMaps(joint_state_map_t& last_state,
- joint_state_map_t& curr_state);
- void computeBodySize();
-
-public:
- typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
- const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
- typedef std::map<std::string, std::string> joint_alias_map_t;
- const joint_alias_map_t& getJointAliases();
-
-
-protected:
- static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
- virtual void buildCharacter();
- virtual bool loadAvatar();
-
- bool setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
- bool allocateCharacterJoints(U32 num);
- bool buildSkeleton(const LLAvatarSkeletonInfo *info);
-
- void clearSkeleton();
- bool mIsBuilt; // state of deferred character building
- avatar_joint_list_t mSkeleton;
- LLVector3OverrideMap mPelvisFixups;
- joint_alias_map_t mJointAliasMap;
-
- //--------------------------------------------------------------------
- // Pelvis height adjustment members.
- //--------------------------------------------------------------------
-public:
- void addPelvisFixup( F32 fixup, const LLUUID& mesh_id );
- void removePelvisFixup( const LLUUID& mesh_id );
- bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const;
- bool hasPelvisFixup( F32& fixup ) const;
-
- LLVector3 mBodySize;
- LLVector3 mAvatarOffset;
-protected:
- F32 mPelvisToFoot;
-
- //--------------------------------------------------------------------
- // Cached pointers to well known joints
- //--------------------------------------------------------------------
-public:
- LLJoint* mPelvisp;
- LLJoint* mTorsop;
- LLJoint* mChestp;
- LLJoint* mNeckp;
- LLJoint* mHeadp;
- LLJoint* mSkullp;
- LLJoint* mEyeLeftp;
- LLJoint* mEyeRightp;
- LLJoint* mHipLeftp;
- LLJoint* mHipRightp;
- LLJoint* mKneeLeftp;
- LLJoint* mKneeRightp;
- LLJoint* mAnkleLeftp;
- LLJoint* mAnkleRightp;
- LLJoint* mFootLeftp;
- LLJoint* mFootRightp;
- LLJoint* mWristLeftp;
- LLJoint* mWristRightp;
-
- //--------------------------------------------------------------------
- // XML parse tree
- //--------------------------------------------------------------------
-protected:
- static LLAvatarSkeletonInfo* sAvatarSkeletonInfo;
- static LLAvatarXmlInfo* sAvatarXmlInfo;
-
-
-/** Skeleton
- ** **
- *******************************************************************************/
-
-
-/********************************************************************************
- ** **
- ** RENDERING
- **/
-public:
- bool mIsDummy; // for special views and animated object controllers; local to viewer
-
- //--------------------------------------------------------------------
- // Morph masks
- //--------------------------------------------------------------------
-public:
- void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer);
- virtual void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0;
-
-/** Rendering
- ** **
- *******************************************************************************/
-
- //--------------------------------------------------------------------
- // Composites
- //--------------------------------------------------------------------
-public:
- virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
-
-/********************************************************************************
- ** **
- ** MESHES
- **/
-
-public:
- virtual void updateMeshTextures() = 0;
- virtual void dirtyMesh() = 0; // Dirty the avatar mesh
- static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; }
-protected:
- virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
-
-protected:
- typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
- polymesh_map_t mPolyMeshes;
- avatar_joint_list_t mMeshLOD;
-
- // mesh entries and backed textures
- static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary;
-
-/** Meshes
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** APPEARANCE
- **/
-
- //--------------------------------------------------------------------
- // Clothing colors (convenience functions to access visual parameters)
- //--------------------------------------------------------------------
-public:
- void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
- LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
- static bool teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
-
- //--------------------------------------------------------------------
- // Global colors
- //--------------------------------------------------------------------
-public:
- LLColor4 getGlobalColor(const std::string& color_name ) const;
- virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
-protected:
- LLTexGlobalColor* mTexSkinColor;
- LLTexGlobalColor* mTexHairColor;
- LLTexGlobalColor* mTexEyeColor;
-
- //--------------------------------------------------------------------
- // Visibility
- //--------------------------------------------------------------------
-public:
- static LLColor4 getDummyColor();
-/** Appearance
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** WEARABLES
- **/
-
-public:
- LLWearableData* getWearableData() { return mWearableData; }
- const LLWearableData* getWearableData() const { return mWearableData; }
- virtual bool isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0;
- virtual bool isWearingWearableType(LLWearableType::EType type ) const;
-
-private:
- LLWearableData* mWearableData;
-
-/********************************************************************************
- ** **
- ** BAKED TEXTURES
- **/
-public:
- LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
-
-protected:
- virtual LLTexLayerSet* createTexLayerSet() = 0;
-
-protected:
- class LLMaskedMorph;
- typedef std::deque<LLMaskedMorph *> morph_list_t;
- struct BakedTextureData
- {
- LLUUID mLastTextureID;
- LLTexLayerSet* mTexLayerSet; // Only exists for self
- bool mIsLoaded;
- bool mIsUsed;
- LLAvatarAppearanceDefines::ETextureIndex mTextureIndex;
- U32 mMaskTexName;
- // Stores pointers to the joint meshes that this baked texture deals with
- avatar_joint_mesh_list_t mJointMeshes;
- morph_list_t mMaskedMorphs;
- };
- typedef std::vector<BakedTextureData> bakedtexturedata_vec_t;
- bakedtexturedata_vec_t mBakedTextureDatas;
-
-/********************************************************************************
- ** **
- ** PHYSICS
- **/
-
- //--------------------------------------------------------------------
- // Collision volumes
- //--------------------------------------------------------------------
-public:
- S32 mNumBones;
- S32 mNumCollisionVolumes;
- LLAvatarJointCollisionVolume* mCollisionVolumes;
-protected:
- bool allocateCollisionVolumes(U32 num);
-
-/** Physics
- ** **
- *******************************************************************************/
-
-/********************************************************************************
- ** **
- ** SUPPORT CLASSES
- **/
-
- struct LLAvatarXmlInfo
- {
- LLAvatarXmlInfo();
- ~LLAvatarXmlInfo();
-
- bool parseXmlSkeletonNode(LLXmlTreeNode* root);
- bool parseXmlMeshNodes(LLXmlTreeNode* root);
- bool parseXmlColorNodes(LLXmlTreeNode* root);
- bool parseXmlLayerNodes(LLXmlTreeNode* root);
- bool parseXmlDriverNodes(LLXmlTreeNode* root);
- bool parseXmlMorphNodes(LLXmlTreeNode* root);
-
- struct LLAvatarMeshInfo
- {
- typedef std::pair<LLViewerVisualParamInfo*,bool> morph_info_pair_t; // LLPolyMorphTargetInfo stored here
- typedef std::vector<morph_info_pair_t> morph_info_list_t;
-
- LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
- ~LLAvatarMeshInfo()
- {
- for (morph_info_list_t::value_type& pair : mPolyMorphTargetInfoList)
- {
- delete pair.first;
- }
- mPolyMorphTargetInfoList.clear();
- }
-
- std::string mType;
- S32 mLOD;
- std::string mMeshFileName;
- std::string mReferenceMeshName;
- F32 mMinPixelArea;
- morph_info_list_t mPolyMorphTargetInfoList;
- };
- typedef std::vector<LLAvatarMeshInfo*> mesh_info_list_t;
- mesh_info_list_t mMeshInfoList;
-
- typedef std::vector<LLViewerVisualParamInfo*> skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here
- skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
-
- struct LLAvatarAttachmentInfo
- {
- LLAvatarAttachmentInfo()
- : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(false),
- mIsHUDAttachment(false), mHasPosition(false), mHasRotation(false) {}
- std::string mName;
- std::string mJointName;
- LLVector3 mPosition;
- LLVector3 mRotationEuler;
- S32 mGroup;
- S32 mAttachmentID;
- S32 mPieMenuSlice;
- bool mVisibleFirstPerson;
- bool mIsHUDAttachment;
- bool mHasPosition;
- bool mHasRotation;
- };
- typedef std::vector<LLAvatarAttachmentInfo*> attachment_info_list_t;
- attachment_info_list_t mAttachmentInfoList;
-
- LLTexGlobalColorInfo *mTexSkinColorInfo;
- LLTexGlobalColorInfo *mTexHairColorInfo;
- LLTexGlobalColorInfo *mTexEyeColorInfo;
-
- typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
- layer_info_list_t mLayerInfoList;
-
- typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
- driver_info_list_t mDriverInfoList;
-
- struct LLAvatarMorphInfo
- {
- LLAvatarMorphInfo()
- : mInvert(false) {}
- std::string mName;
- std::string mRegion;
- std::string mLayer;
- bool mInvert;
- };
-
- typedef std::vector<LLAvatarMorphInfo*> morph_info_list_t;
- morph_info_list_t mMorphMaskInfoList;
- };
-
-
- class LLMaskedMorph
- {
- public:
- LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer);
-
- LLVisualParam *mMorphTarget;
- bool mInvert;
- std::string mLayer;
- };
-/** Support Classes
- ** **
- *******************************************************************************/
-};
-
-#endif // LL_AVATAR_APPEARANCE_H
+/**
+ * @file llavatarappearance.h
+ * @brief Declaration 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$
+ */
+
+#ifndef LL_AVATAR_APPEARANCE_H
+#define LL_AVATAR_APPEARANCE_H
+
+#include "llcharacter.h"
+#include "llavatarappearancedefines.h"
+#include "llavatarjointmesh.h"
+#include "lldriverparam.h"
+#include "lltexlayer.h"
+#include "llviewervisualparam.h"
+#include "llxmltree.h"
+
+class LLTexLayerSet;
+class LLTexGlobalColor;
+class LLTexGlobalColorInfo;
+class LLWearableData;
+class LLAvatarBoneInfo;
+class LLAvatarSkeletonInfo;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLAvatarAppearance
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLAvatarAppearance : public LLCharacter
+{
+ LOG_CLASS(LLAvatarAppearance);
+
+protected:
+ struct LLAvatarXmlInfo;
+
+/********************************************************************************
+ ** **
+ ** INITIALIZATION
+ **/
+private:
+ // Hide default constructor.
+ LLAvatarAppearance() {}
+
+public:
+ LLAvatarAppearance(LLWearableData* wearable_data);
+ virtual ~LLAvatarAppearance();
+
+ static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members
+ static void initClass();
+ static void cleanupClass(); // Cleanup data that's only init'd once per class.
+ virtual void initInstance(); // Called after construction to initialize the instance.
+ S32 mInitFlags;
+ virtual bool loadSkeletonNode();
+ bool loadMeshNodes();
+ bool loadLayersets();
+
+
+/** Initialization
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** INHERITED
+ **/
+
+ //--------------------------------------------------------------------
+ // LLCharacter interface and related
+ //--------------------------------------------------------------------
+public:
+ /*virtual*/ LLJoint* getCharacterJoint(U32 num);
+
+ /*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
+ /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
+ /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id);
+ /*virtual*/ S32 getCollisionVolumeID(std::string &name);
+ /*virtual*/ LLPolyMesh* getHeadMesh();
+ /*virtual*/ LLPolyMesh* getUpperBodyMesh();
+
+/** Inherited
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** STATE
+ **/
+public:
+ virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
+ virtual bool isValid() const;
+ virtual bool isUsingLocalAppearance() const = 0;
+ virtual bool isEditingAppearance() const = 0;
+
+ bool isBuilt() const { return mIsBuilt; }
+
+
+/** State
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** SKELETON
+ **/
+
+protected:
+ virtual LLAvatarJoint* createAvatarJoint() = 0;
+ virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0;
+ virtual LLAvatarJointMesh* createAvatarJointMesh() = 0;
+ void makeJointAliases(LLAvatarBoneInfo *bone_info);
+
+
+public:
+ F32 getPelvisToFoot() const { return mPelvisToFoot; }
+ /*virtual*/ LLJoint* getRootJoint() { return mRoot; }
+
+ LLVector3 mHeadOffset; // current head position
+ LLAvatarJoint *mRoot;
+
+ typedef std::map<std::string, LLJoint*> joint_map_t;
+ joint_map_t mJointMap;
+
+ typedef std::map<std::string, LLVector3> joint_state_map_t;
+ joint_state_map_t mLastBodySizeState;
+ joint_state_map_t mCurrBodySizeState;
+ void compareJointStateMaps(joint_state_map_t& last_state,
+ joint_state_map_t& curr_state);
+ void computeBodySize();
+ F32 computeBodyHeight();
+ F32 computePelvisToFoot();
+
+public:
+ typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
+ const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
+ typedef std::map<std::string, std::string> joint_alias_map_t;
+ const joint_alias_map_t& getJointAliases();
+
+
+protected:
+ static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
+ virtual void buildCharacter();
+ virtual bool loadAvatar();
+
+ bool setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
+ bool allocateCharacterJoints(U32 num);
+ bool buildSkeleton(const LLAvatarSkeletonInfo *info);
+
+ void clearSkeleton();
+ bool mIsBuilt; // state of deferred character building
+ avatar_joint_list_t mSkeleton;
+ LLVector3OverrideMap mPelvisFixups;
+ joint_alias_map_t mJointAliasMap;
+
+ //--------------------------------------------------------------------
+ // Pelvis height adjustment members.
+ //--------------------------------------------------------------------
+public:
+ void addPelvisFixup( F32 fixup, const LLUUID& mesh_id );
+ void removePelvisFixup( const LLUUID& mesh_id );
+ bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const;
+ bool hasPelvisFixup( F32& fixup ) const;
+
+ LLVector3 mBodySize;
+ LLVector3 mAvatarOffset;
+protected:
+ F32 mPelvisToFoot;
+
+ //--------------------------------------------------------------------
+ // Cached pointers to well known joints
+ //--------------------------------------------------------------------
+public:
+ LLJoint* mPelvisp;
+ LLJoint* mTorsop;
+ LLJoint* mChestp;
+ LLJoint* mNeckp;
+ LLJoint* mHeadp;
+ LLJoint* mSkullp;
+ LLJoint* mEyeLeftp;
+ LLJoint* mEyeRightp;
+ LLJoint* mHipLeftp;
+ LLJoint* mHipRightp;
+ LLJoint* mKneeLeftp;
+ LLJoint* mKneeRightp;
+ LLJoint* mAnkleLeftp;
+ LLJoint* mAnkleRightp;
+ LLJoint* mFootLeftp;
+ LLJoint* mFootRightp;
+ LLJoint* mWristLeftp;
+ LLJoint* mWristRightp;
+
+ //--------------------------------------------------------------------
+ // XML parse tree
+ //--------------------------------------------------------------------
+protected:
+ static LLAvatarSkeletonInfo* sAvatarSkeletonInfo;
+ static LLAvatarXmlInfo* sAvatarXmlInfo;
+
+
+/** Skeleton
+ ** **
+ *******************************************************************************/
+
+
+/********************************************************************************
+ ** **
+ ** RENDERING
+ **/
+public:
+ bool mIsDummy; // for special views and animated object controllers; local to viewer
+
+ //--------------------------------------------------------------------
+ // Morph masks
+ //--------------------------------------------------------------------
+public:
+ void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer);
+ virtual void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0;
+
+/** Rendering
+ ** **
+ *******************************************************************************/
+
+ //--------------------------------------------------------------------
+ // Composites
+ //--------------------------------------------------------------------
+public:
+ virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
+
+/********************************************************************************
+ ** **
+ ** MESHES
+ **/
+
+public:
+ virtual void updateMeshTextures() = 0;
+ virtual void dirtyMesh() = 0; // Dirty the avatar mesh
+ static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; }
+protected:
+ virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
+
+protected:
+ typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
+ polymesh_map_t mPolyMeshes;
+ avatar_joint_list_t mMeshLOD;
+
+ // mesh entries and backed textures
+ static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary;
+
+/** Meshes
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** APPEARANCE
+ **/
+
+ //--------------------------------------------------------------------
+ // Clothing colors (convenience functions to access visual parameters)
+ //--------------------------------------------------------------------
+public:
+ void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
+ LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
+ static bool teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
+
+ //--------------------------------------------------------------------
+ // Global colors
+ //--------------------------------------------------------------------
+public:
+ LLColor4 getGlobalColor(const std::string& color_name ) const;
+ virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
+protected:
+ LLTexGlobalColor* mTexSkinColor;
+ LLTexGlobalColor* mTexHairColor;
+ LLTexGlobalColor* mTexEyeColor;
+
+ //--------------------------------------------------------------------
+ // Visibility
+ //--------------------------------------------------------------------
+public:
+ static LLColor4 getDummyColor();
+/** Appearance
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** WEARABLES
+ **/
+
+public:
+ LLWearableData* getWearableData() { return mWearableData; }
+ const LLWearableData* getWearableData() const { return mWearableData; }
+ virtual bool isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0;
+ virtual bool isWearingWearableType(LLWearableType::EType type ) const;
+
+private:
+ LLWearableData* mWearableData;
+
+/********************************************************************************
+ ** **
+ ** BAKED TEXTURES
+ **/
+public:
+ LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
+
+protected:
+ virtual LLTexLayerSet* createTexLayerSet() = 0;
+
+protected:
+ class LLMaskedMorph;
+ typedef std::deque<LLMaskedMorph *> morph_list_t;
+ struct BakedTextureData
+ {
+ LLUUID mLastTextureID;
+ LLTexLayerSet* mTexLayerSet; // Only exists for self
+ bool mIsLoaded;
+ bool mIsUsed;
+ LLAvatarAppearanceDefines::ETextureIndex mTextureIndex;
+ U32 mMaskTexName;
+ // Stores pointers to the joint meshes that this baked texture deals with
+ avatar_joint_mesh_list_t mJointMeshes;
+ morph_list_t mMaskedMorphs;
+ };
+ typedef std::vector<BakedTextureData> bakedtexturedata_vec_t;
+ bakedtexturedata_vec_t mBakedTextureDatas;
+
+/********************************************************************************
+ ** **
+ ** PHYSICS
+ **/
+
+ //--------------------------------------------------------------------
+ // Collision volumes
+ //--------------------------------------------------------------------
+public:
+ S32 mNumBones;
+ S32 mNumCollisionVolumes;
+ LLAvatarJointCollisionVolume* mCollisionVolumes;
+protected:
+ bool allocateCollisionVolumes(U32 num);
+
+/** Physics
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** SUPPORT CLASSES
+ **/
+
+ struct LLAvatarXmlInfo
+ {
+ LLAvatarXmlInfo();
+ ~LLAvatarXmlInfo();
+
+ bool parseXmlSkeletonNode(LLXmlTreeNode* root);
+ bool parseXmlMeshNodes(LLXmlTreeNode* root);
+ bool parseXmlColorNodes(LLXmlTreeNode* root);
+ bool parseXmlLayerNodes(LLXmlTreeNode* root);
+ bool parseXmlDriverNodes(LLXmlTreeNode* root);
+ bool parseXmlMorphNodes(LLXmlTreeNode* root);
+
+ struct LLAvatarMeshInfo
+ {
+ typedef std::pair<LLViewerVisualParamInfo*,bool> morph_info_pair_t; // LLPolyMorphTargetInfo stored here
+ typedef std::vector<morph_info_pair_t> morph_info_list_t;
+
+ LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
+ ~LLAvatarMeshInfo()
+ {
+ for (morph_info_list_t::value_type& pair : mPolyMorphTargetInfoList)
+ {
+ delete pair.first;
+ }
+ mPolyMorphTargetInfoList.clear();
+ }
+
+ std::string mType;
+ S32 mLOD;
+ std::string mMeshFileName;
+ std::string mReferenceMeshName;
+ F32 mMinPixelArea;
+ morph_info_list_t mPolyMorphTargetInfoList;
+ };
+ typedef std::vector<LLAvatarMeshInfo*> mesh_info_list_t;
+ mesh_info_list_t mMeshInfoList;
+
+ typedef std::vector<LLViewerVisualParamInfo*> skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here
+ skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
+
+ struct LLAvatarAttachmentInfo
+ {
+ LLAvatarAttachmentInfo()
+ : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(false),
+ mIsHUDAttachment(false), mHasPosition(false), mHasRotation(false) {}
+ std::string mName;
+ std::string mJointName;
+ LLVector3 mPosition;
+ LLVector3 mRotationEuler;
+ S32 mGroup;
+ S32 mAttachmentID;
+ S32 mPieMenuSlice;
+ bool mVisibleFirstPerson;
+ bool mIsHUDAttachment;
+ bool mHasPosition;
+ bool mHasRotation;
+ };
+ typedef std::vector<LLAvatarAttachmentInfo*> attachment_info_list_t;
+ attachment_info_list_t mAttachmentInfoList;
+
+ LLTexGlobalColorInfo *mTexSkinColorInfo;
+ LLTexGlobalColorInfo *mTexHairColorInfo;
+ LLTexGlobalColorInfo *mTexEyeColorInfo;
+
+ typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
+ layer_info_list_t mLayerInfoList;
+
+ typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
+ driver_info_list_t mDriverInfoList;
+
+ struct LLAvatarMorphInfo
+ {
+ LLAvatarMorphInfo()
+ : mInvert(false) {}
+ std::string mName;
+ std::string mRegion;
+ std::string mLayer;
+ bool mInvert;
+ };
+
+ typedef std::vector<LLAvatarMorphInfo*> morph_info_list_t;
+ morph_info_list_t mMorphMaskInfoList;
+ };
+
+
+ class LLMaskedMorph
+ {
+ public:
+ LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer);
+
+ LLVisualParam *mMorphTarget;
+ bool mInvert;
+ std::string mLayer;
+ };
+/** Support Classes
+ ** **
+ *******************************************************************************/
+};
+
+#endif // LL_AVATAR_APPEARANCE_H
diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp
index 7af1c37824..1fd30d023d 100644
--- a/indra/llappearance/llavatarappearancedefines.cpp
+++ b/indra/llappearance/llavatarappearancedefines.cpp
@@ -1,413 +1,413 @@
-/**
- * @file llavatarappearancedefines.cpp
- * @brief Implementation of LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llavatarappearancedefines.h"
-#include "indra_constants.h"
-
-const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024;
-const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024;
-
-using namespace LLAvatarAppearanceDefines;
-
-/*********************************************************************************
- * Edit this function to add/remove/change textures and mesh definitions for avatars.
- */
-
-LLAvatarAppearanceDictionary::Textures::Textures()
-{
- addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
- addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", true, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT));
- addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", true, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS));
- addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", true, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES));
- addEntry(TEX_HAIR, new TextureEntry("hair_grain", true, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR));
- addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
- addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
- addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", true, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES));
- addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", true, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS));
- addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
- addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
- addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", true, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES));
- addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT));
- addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS));
- addEntry(TEX_SKIRT, new TextureEntry("skirt", true, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT));
-
- addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
- addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
- addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
- addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
- addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
-
- addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
- addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
- addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
-
- addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new TextureEntry("head_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new TextureEntry("upper_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new TextureEntry("lower_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_SKIRT_TATTOO, new TextureEntry("skirt_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_HAIR_TATTOO, new TextureEntry("hair_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_EYES_TATTOO, new TextureEntry("eyes_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_LEFT_ARM_TATTOO, new TextureEntry("leftarm_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_LEFT_LEG_TATTOO, new TextureEntry("leftleg_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_AUX1_TATTOO, new TextureEntry("aux1_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_AUX2_TATTOO, new TextureEntry("aux2_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
- addEntry(TEX_AUX3_TATTOO, new TextureEntry("aux3_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
-
-
- addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", false, BAKED_HEAD, "head"));
- addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", false, BAKED_UPPER, "upper"));
- addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", false, BAKED_LOWER, "lower"));
- addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", false, BAKED_EYES, "eyes"));
- addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", false, BAKED_HAIR, "hair"));
- addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", false, BAKED_SKIRT, "skirt"));
- addEntry(TEX_LEFT_ARM_BAKED, new TextureEntry("leftarm-baked", false, BAKED_LEFT_ARM, "leftarm"));
- addEntry(TEX_LEFT_LEG_BAKED, new TextureEntry("leftleg-baked", false, BAKED_LEFT_LEG, "leftleg"));
- addEntry(TEX_AUX1_BAKED, new TextureEntry("aux1-baked", false, BAKED_AUX1, "aux1"));
- addEntry(TEX_AUX2_BAKED, new TextureEntry("aux2-baked", false, BAKED_AUX2, "aux2"));
- addEntry(TEX_AUX3_BAKED, new TextureEntry("aux3-baked", false, BAKED_AUX3, "aux3"));
-}
-
-LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
-{
- // Baked textures
- addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
- "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff",
- 4, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, TEX_HEAD_UNIVERSAL_TATTOO,
- 6, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED,
- "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4",
- 8, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
- TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, TEX_UPPER_UNIVERSAL_TATTOO,
- 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED,
- "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d",
- 9, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
- TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, TEX_LOWER_UNIVERSAL_TATTOO,
- 10, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED,
- "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788",
- 3, TEX_EYES_IRIS, TEX_EYES_TATTOO, TEX_EYES_ALPHA,
- 3, LLWearableType::WT_EYES, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
-
- addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED,
- "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63",
- 2, TEX_SKIRT, TEX_SKIRT_TATTOO,
- 2, LLWearableType::WT_SKIRT, LLWearableType::WT_UNIVERSAL ));
-
- addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED,
- "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61",
- 3, TEX_HAIR, TEX_HAIR_TATTOO, TEX_HAIR_ALPHA,
- 3, LLWearableType::WT_HAIR, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
-
- addEntry(BAKED_LEFT_ARM, new BakedEntry(TEX_LEFT_ARM_BAKED,
- "leftarm", "9f39febf-22d7-0087-79d1-e9e8c6c9ed19",
- 1, TEX_LEFT_ARM_TATTOO,
- 1, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_LEFT_LEG, new BakedEntry(TEX_LEFT_LEG_BAKED,
- "leftleg", "054a7a58-8ed5-6386-0add-3b636fb28b78",
- 1, TEX_LEFT_LEG_TATTOO,
- 1, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_AUX1, new BakedEntry(TEX_AUX1_BAKED,
- "aux1", "790c11be-b25c-c17e-b4d2-6a4ad786b752",
- 1, TEX_AUX1_TATTOO,
- 1, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_AUX2, new BakedEntry(TEX_AUX2_BAKED,
- "aux2", "d78c478f-48c7-5928-5864-8d99fb1f521e",
- 1, TEX_AUX2_TATTOO,
- 1, LLWearableType::WT_UNIVERSAL));
-
- addEntry(BAKED_AUX3, new BakedEntry(TEX_AUX3_BAKED,
- "aux3", "6a95dd53-edd9-aac8-f6d3-27ed99f3c3eb",
- 1, TEX_AUX3_TATTOO,
- 1, LLWearableType::WT_UNIVERSAL));
-}
-
-LLAvatarAppearanceDictionary::MeshEntries::MeshEntries()
-{
- // MeshEntries
- addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4));
- addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5));
- addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently
- addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1));
- addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2));
- addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3));
- addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3));
- addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5));
-}
-
-/*
- *
- *********************************************************************************/
-
-LLAvatarAppearanceDictionary::LLAvatarAppearanceDictionary()
-{
- createAssociations();
-}
-
-//virtual
-LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary()
-{
-}
-
-// Baked textures are composites of textures; for each such composited texture,
-// map it to the baked texture.
-void LLAvatarAppearanceDictionary::createAssociations()
-{
- for (BakedTextures::value_type& baked_pair : mBakedTextures)
- {
- const EBakedTextureIndex baked_index = baked_pair.first;
- const BakedEntry *dict = baked_pair.second;
-
- // For each texture that this baked texture index affects, associate those textures
- // with this baked texture index.
- for (const ETextureIndex local_texture_index : dict->mLocalTextures)
- {
- mTextures[local_texture_index]->mIsUsedByBakedTexture = true;
- mTextures[local_texture_index]->mBakedTextureIndex = baked_index;
- }
- }
-
-}
-
-LLAvatarAppearanceDictionary::TextureEntry::TextureEntry(const std::string &name,
- bool is_local_texture,
- EBakedTextureIndex baked_texture_index,
- const std::string &default_image_name,
- LLWearableType::EType wearable_type) :
- LLDictionaryEntry(name),
- mIsLocalTexture(is_local_texture),
- mIsBakedTexture(!is_local_texture),
- mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES),
- mBakedTextureIndex(baked_texture_index),
- mDefaultImageName(default_image_name),
- mWearableType(wearable_type)
-{
-}
-
-LLAvatarAppearanceDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index,
- const std::string &name,
- U8 level,
- LLJointPickName pick) :
- LLDictionaryEntry(name),
- mBakedID(baked_index),
- mLOD(level),
- mPickName(pick)
-{
-}
-LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
- const std::string &name,
- const std::string &hash_name,
- U32 num_local_textures,
- ... ) :
- LLDictionaryEntry(name),
- mWearablesHashID(LLUUID(hash_name)),
- mTextureIndex(tex_index)
-{
- va_list argp;
-
- va_start(argp, num_local_textures);
-
- // Read in local textures
- for (U8 i=0; i < num_local_textures; i++)
- {
- ETextureIndex t = (ETextureIndex)va_arg(argp,int);
- mLocalTextures.push_back(t);
- }
-
- // Read in number of wearables
- const U32 num_wearables = (U32)va_arg(argp,int);
- // Read in wearables
- for (U8 i=0; i < num_wearables; i++)
- {
- LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
- mWearables.push_back(t);
- }
-}
-
-ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) const
-{
- return getBakedTexture(index)->mTextureIndex;
-}
-
-EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name)
-{
- U8 index = 0;
- while (index < BAKED_NUM_INDICES)
- {
- const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
- if (be && be->mName.compare(name) == 0)
- {
- // baked texture found
- return (EBakedTextureIndex) index;
- }
- index++;
- }
- // baked texture could not be found
- return BAKED_NUM_INDICES;
-}
-
-EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name)
-{
- U8 index = 0;
- while (index < BAKED_NUM_INDICES)
- {
- const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
- if (be)
- {
- const TextureEntry *te = getTexture(be->mTextureIndex);
- if (te && te->mDefaultImageName.compare(name) == 0)
- {
- // baked texture found
- return (EBakedTextureIndex) index;
- }
- }
- index++;
- }
- // baked texture could not be found
- return BAKED_NUM_INDICES;
-}
-
-LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) const
-{
- return getTexture(index)->mWearableType;
-}
-
-// static
-bool LLAvatarAppearanceDictionary::isBakedImageId(const LLUUID& id)
-{
- if ((id == IMG_USE_BAKED_EYES) || (id == IMG_USE_BAKED_HAIR) || (id == IMG_USE_BAKED_HEAD) || (id == IMG_USE_BAKED_LOWER) || (id == IMG_USE_BAKED_SKIRT) || (id == IMG_USE_BAKED_UPPER)
- || (id == IMG_USE_BAKED_LEFTARM) || (id == IMG_USE_BAKED_LEFTLEG) || (id == IMG_USE_BAKED_AUX1) || (id == IMG_USE_BAKED_AUX2) || (id == IMG_USE_BAKED_AUX3) )
- {
- return true;
- }
-
- return false;
-}
-
-// static
-EBakedTextureIndex LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(const LLUUID& id)
-{
- if (id == IMG_USE_BAKED_EYES)
- {
- return BAKED_EYES;
- }
- else if (id == IMG_USE_BAKED_HAIR)
- {
- return BAKED_HAIR;
- }
- else if (id == IMG_USE_BAKED_HEAD)
- {
- return BAKED_HEAD;
- }
- else if (id == IMG_USE_BAKED_LOWER)
- {
- return BAKED_LOWER;
- }
- else if (id == IMG_USE_BAKED_SKIRT)
- {
- return BAKED_SKIRT;
- }
- else if (id == IMG_USE_BAKED_UPPER)
- {
- return BAKED_UPPER;
- }
- else if (id == IMG_USE_BAKED_LEFTARM)
- {
- return BAKED_LEFT_ARM;
- }
- else if (id == IMG_USE_BAKED_LEFTLEG)
- {
- return BAKED_LEFT_LEG;
- }
- else if (id == IMG_USE_BAKED_AUX1)
- {
- return BAKED_AUX1;
- }
- else if (id == IMG_USE_BAKED_AUX2)
- {
- return BAKED_AUX2;
- }
- else if (id == IMG_USE_BAKED_AUX3)
- {
- return BAKED_AUX3;
- }
-
- return BAKED_NUM_INDICES;
-}
-
-//static
-LLUUID LLAvatarAppearanceDictionary::localTextureIndexToMagicId(ETextureIndex t)
-{
- LLUUID id = LLUUID::null;
-
- switch (t)
- {
- case LLAvatarAppearanceDefines::TEX_HEAD_BAKED:
- id = IMG_USE_BAKED_HEAD;
- break;
- case LLAvatarAppearanceDefines::TEX_UPPER_BAKED:
- id = IMG_USE_BAKED_UPPER;
- break;
- case LLAvatarAppearanceDefines::TEX_LOWER_BAKED:
- id = IMG_USE_BAKED_LOWER;
- break;
- case LLAvatarAppearanceDefines::TEX_EYES_BAKED:
- id = IMG_USE_BAKED_EYES;
- break;
- case LLAvatarAppearanceDefines::TEX_SKIRT_BAKED:
- id = IMG_USE_BAKED_SKIRT;
- break;
- case LLAvatarAppearanceDefines::TEX_HAIR_BAKED:
- id = IMG_USE_BAKED_HAIR;
- break;
- case LLAvatarAppearanceDefines::TEX_LEFT_ARM_BAKED:
- id = IMG_USE_BAKED_LEFTARM;
- break;
- case LLAvatarAppearanceDefines::TEX_LEFT_LEG_BAKED:
- id = IMG_USE_BAKED_LEFTLEG;
- break;
- case LLAvatarAppearanceDefines::TEX_AUX1_BAKED:
- id = IMG_USE_BAKED_AUX1;
- break;
- case LLAvatarAppearanceDefines::TEX_AUX2_BAKED:
- id = IMG_USE_BAKED_AUX2;
- break;
- case LLAvatarAppearanceDefines::TEX_AUX3_BAKED:
- id = IMG_USE_BAKED_AUX3;
- break;
- default:
- break;
- }
-
- return id;
-}
+/**
+ * @file llavatarappearancedefines.cpp
+ * @brief Implementation of LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llavatarappearancedefines.h"
+#include "indra_constants.h"
+
+const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024;
+const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024;
+
+using namespace LLAvatarAppearanceDefines;
+
+/*********************************************************************************
+ * Edit this function to add/remove/change textures and mesh definitions for avatars.
+ */
+
+LLAvatarAppearanceDictionary::Textures::Textures()
+{
+ addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", true, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT));
+ addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", true, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS));
+ addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", true, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES));
+ addEntry(TEX_HAIR, new TextureEntry("hair_grain", true, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR));
+ addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", true, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES));
+ addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", true, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS));
+ addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
+ addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
+ addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", true, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES));
+ addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT));
+ addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS));
+ addEntry(TEX_SKIRT, new TextureEntry("skirt", true, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT));
+
+ addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+
+ addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+ addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+ addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+
+ addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new TextureEntry("head_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new TextureEntry("upper_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new TextureEntry("lower_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_SKIRT_TATTOO, new TextureEntry("skirt_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_HAIR_TATTOO, new TextureEntry("hair_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_EYES_TATTOO, new TextureEntry("eyes_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LEFT_ARM_TATTOO, new TextureEntry("leftarm_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LEFT_LEG_TATTOO, new TextureEntry("leftleg_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX1_TATTOO, new TextureEntry("aux1_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX2_TATTOO, new TextureEntry("aux2_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX3_TATTOO, new TextureEntry("aux3_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+
+
+ addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", false, BAKED_HEAD, "head"));
+ addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", false, BAKED_UPPER, "upper"));
+ addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", false, BAKED_LOWER, "lower"));
+ addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", false, BAKED_EYES, "eyes"));
+ addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", false, BAKED_HAIR, "hair"));
+ addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", false, BAKED_SKIRT, "skirt"));
+ addEntry(TEX_LEFT_ARM_BAKED, new TextureEntry("leftarm-baked", false, BAKED_LEFT_ARM, "leftarm"));
+ addEntry(TEX_LEFT_LEG_BAKED, new TextureEntry("leftleg-baked", false, BAKED_LEFT_LEG, "leftleg"));
+ addEntry(TEX_AUX1_BAKED, new TextureEntry("aux1-baked", false, BAKED_AUX1, "aux1"));
+ addEntry(TEX_AUX2_BAKED, new TextureEntry("aux2-baked", false, BAKED_AUX2, "aux2"));
+ addEntry(TEX_AUX3_BAKED, new TextureEntry("aux3-baked", false, BAKED_AUX3, "aux3"));
+}
+
+LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
+{
+ // Baked textures
+ addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
+ "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff",
+ 4, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, TEX_HEAD_UNIVERSAL_TATTOO,
+ 6, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED,
+ "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4",
+ 8, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
+ TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, TEX_UPPER_UNIVERSAL_TATTOO,
+ 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED,
+ "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d",
+ 9, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
+ TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, TEX_LOWER_UNIVERSAL_TATTOO,
+ 10, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED,
+ "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788",
+ 3, TEX_EYES_IRIS, TEX_EYES_TATTOO, TEX_EYES_ALPHA,
+ 3, LLWearableType::WT_EYES, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
+
+ addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED,
+ "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63",
+ 2, TEX_SKIRT, TEX_SKIRT_TATTOO,
+ 2, LLWearableType::WT_SKIRT, LLWearableType::WT_UNIVERSAL ));
+
+ addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED,
+ "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61",
+ 3, TEX_HAIR, TEX_HAIR_TATTOO, TEX_HAIR_ALPHA,
+ 3, LLWearableType::WT_HAIR, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
+
+ addEntry(BAKED_LEFT_ARM, new BakedEntry(TEX_LEFT_ARM_BAKED,
+ "leftarm", "9f39febf-22d7-0087-79d1-e9e8c6c9ed19",
+ 1, TEX_LEFT_ARM_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_LEFT_LEG, new BakedEntry(TEX_LEFT_LEG_BAKED,
+ "leftleg", "054a7a58-8ed5-6386-0add-3b636fb28b78",
+ 1, TEX_LEFT_LEG_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX1, new BakedEntry(TEX_AUX1_BAKED,
+ "aux1", "790c11be-b25c-c17e-b4d2-6a4ad786b752",
+ 1, TEX_AUX1_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX2, new BakedEntry(TEX_AUX2_BAKED,
+ "aux2", "d78c478f-48c7-5928-5864-8d99fb1f521e",
+ 1, TEX_AUX2_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX3, new BakedEntry(TEX_AUX3_BAKED,
+ "aux3", "6a95dd53-edd9-aac8-f6d3-27ed99f3c3eb",
+ 1, TEX_AUX3_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+}
+
+LLAvatarAppearanceDictionary::MeshEntries::MeshEntries()
+{
+ // MeshEntries
+ addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4));
+ addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5));
+ addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently
+ addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1));
+ addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2));
+ addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3));
+ addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3));
+ addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5));
+}
+
+/*
+ *
+ *********************************************************************************/
+
+LLAvatarAppearanceDictionary::LLAvatarAppearanceDictionary()
+{
+ createAssociations();
+}
+
+//virtual
+LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary()
+{
+}
+
+// Baked textures are composites of textures; for each such composited texture,
+// map it to the baked texture.
+void LLAvatarAppearanceDictionary::createAssociations()
+{
+ for (BakedTextures::value_type& baked_pair : mBakedTextures)
+ {
+ const EBakedTextureIndex baked_index = baked_pair.first;
+ const BakedEntry *dict = baked_pair.second;
+
+ // For each texture that this baked texture index affects, associate those textures
+ // with this baked texture index.
+ for (const ETextureIndex local_texture_index : dict->mLocalTextures)
+ {
+ mTextures[local_texture_index]->mIsUsedByBakedTexture = true;
+ mTextures[local_texture_index]->mBakedTextureIndex = baked_index;
+ }
+ }
+
+}
+
+LLAvatarAppearanceDictionary::TextureEntry::TextureEntry(const std::string &name,
+ bool is_local_texture,
+ EBakedTextureIndex baked_texture_index,
+ const std::string &default_image_name,
+ LLWearableType::EType wearable_type) :
+ LLDictionaryEntry(name),
+ mIsLocalTexture(is_local_texture),
+ mIsBakedTexture(!is_local_texture),
+ mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES),
+ mBakedTextureIndex(baked_texture_index),
+ mDefaultImageName(default_image_name),
+ mWearableType(wearable_type)
+{
+}
+
+LLAvatarAppearanceDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index,
+ const std::string &name,
+ U8 level,
+ LLJointPickName pick) :
+ LLDictionaryEntry(name),
+ mBakedID(baked_index),
+ mLOD(level),
+ mPickName(pick)
+{
+}
+LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
+ const std::string &name,
+ const std::string &hash_name,
+ U32 num_local_textures,
+ ... ) :
+ LLDictionaryEntry(name),
+ mWearablesHashID(LLUUID(hash_name)),
+ mTextureIndex(tex_index)
+{
+ va_list argp;
+
+ va_start(argp, num_local_textures);
+
+ // Read in local textures
+ for (U8 i=0; i < num_local_textures; i++)
+ {
+ ETextureIndex t = (ETextureIndex)va_arg(argp,int);
+ mLocalTextures.push_back(t);
+ }
+
+ // Read in number of wearables
+ const U32 num_wearables = (U32)va_arg(argp,int);
+ // Read in wearables
+ for (U8 i=0; i < num_wearables; i++)
+ {
+ LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
+ mWearables.push_back(t);
+ }
+}
+
+ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) const
+{
+ return getBakedTexture(index)->mTextureIndex;
+}
+
+EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name)
+{
+ U8 index = 0;
+ while (index < BAKED_NUM_INDICES)
+ {
+ const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
+ if (be && be->mName.compare(name) == 0)
+ {
+ // baked texture found
+ return (EBakedTextureIndex) index;
+ }
+ index++;
+ }
+ // baked texture could not be found
+ return BAKED_NUM_INDICES;
+}
+
+EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name)
+{
+ U8 index = 0;
+ while (index < BAKED_NUM_INDICES)
+ {
+ const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
+ if (be)
+ {
+ const TextureEntry *te = getTexture(be->mTextureIndex);
+ if (te && te->mDefaultImageName.compare(name) == 0)
+ {
+ // baked texture found
+ return (EBakedTextureIndex) index;
+ }
+ }
+ index++;
+ }
+ // baked texture could not be found
+ return BAKED_NUM_INDICES;
+}
+
+LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) const
+{
+ return getTexture(index)->mWearableType;
+}
+
+// static
+bool LLAvatarAppearanceDictionary::isBakedImageId(const LLUUID& id)
+{
+ if ((id == IMG_USE_BAKED_EYES) || (id == IMG_USE_BAKED_HAIR) || (id == IMG_USE_BAKED_HEAD) || (id == IMG_USE_BAKED_LOWER) || (id == IMG_USE_BAKED_SKIRT) || (id == IMG_USE_BAKED_UPPER)
+ || (id == IMG_USE_BAKED_LEFTARM) || (id == IMG_USE_BAKED_LEFTLEG) || (id == IMG_USE_BAKED_AUX1) || (id == IMG_USE_BAKED_AUX2) || (id == IMG_USE_BAKED_AUX3) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// static
+EBakedTextureIndex LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(const LLUUID& id)
+{
+ if (id == IMG_USE_BAKED_EYES)
+ {
+ return BAKED_EYES;
+ }
+ else if (id == IMG_USE_BAKED_HAIR)
+ {
+ return BAKED_HAIR;
+ }
+ else if (id == IMG_USE_BAKED_HEAD)
+ {
+ return BAKED_HEAD;
+ }
+ else if (id == IMG_USE_BAKED_LOWER)
+ {
+ return BAKED_LOWER;
+ }
+ else if (id == IMG_USE_BAKED_SKIRT)
+ {
+ return BAKED_SKIRT;
+ }
+ else if (id == IMG_USE_BAKED_UPPER)
+ {
+ return BAKED_UPPER;
+ }
+ else if (id == IMG_USE_BAKED_LEFTARM)
+ {
+ return BAKED_LEFT_ARM;
+ }
+ else if (id == IMG_USE_BAKED_LEFTLEG)
+ {
+ return BAKED_LEFT_LEG;
+ }
+ else if (id == IMG_USE_BAKED_AUX1)
+ {
+ return BAKED_AUX1;
+ }
+ else if (id == IMG_USE_BAKED_AUX2)
+ {
+ return BAKED_AUX2;
+ }
+ else if (id == IMG_USE_BAKED_AUX3)
+ {
+ return BAKED_AUX3;
+ }
+
+ return BAKED_NUM_INDICES;
+}
+
+//static
+LLUUID LLAvatarAppearanceDictionary::localTextureIndexToMagicId(ETextureIndex t)
+{
+ LLUUID id = LLUUID::null;
+
+ switch (t)
+ {
+ case LLAvatarAppearanceDefines::TEX_HEAD_BAKED:
+ id = IMG_USE_BAKED_HEAD;
+ break;
+ case LLAvatarAppearanceDefines::TEX_UPPER_BAKED:
+ id = IMG_USE_BAKED_UPPER;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LOWER_BAKED:
+ id = IMG_USE_BAKED_LOWER;
+ break;
+ case LLAvatarAppearanceDefines::TEX_EYES_BAKED:
+ id = IMG_USE_BAKED_EYES;
+ break;
+ case LLAvatarAppearanceDefines::TEX_SKIRT_BAKED:
+ id = IMG_USE_BAKED_SKIRT;
+ break;
+ case LLAvatarAppearanceDefines::TEX_HAIR_BAKED:
+ id = IMG_USE_BAKED_HAIR;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LEFT_ARM_BAKED:
+ id = IMG_USE_BAKED_LEFTARM;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LEFT_LEG_BAKED:
+ id = IMG_USE_BAKED_LEFTLEG;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX1_BAKED:
+ id = IMG_USE_BAKED_AUX1;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX2_BAKED:
+ id = IMG_USE_BAKED_AUX2;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX3_BAKED:
+ id = IMG_USE_BAKED_AUX3;
+ break;
+ default:
+ break;
+ }
+
+ return id;
+}
diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h
index 0bba3ddfcc..d87b87a939 100644
--- a/indra/llappearance/llavatarappearancedefines.h
+++ b/indra/llappearance/llavatarappearancedefines.h
@@ -1,255 +1,255 @@
-/**
- * @file llavatarappearancedefines.h
- * @brief Various LLAvatarAppearance related definitions
- * LLViewerObject
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_AVATARAPPEARANCE_DEFINES_H
-#define LL_AVATARAPPEARANCE_DEFINES_H
-
-#include <vector>
-#include "lljointpickname.h"
-#include "lldictionary.h"
-#include "llwearabletype.h"
-#include "lluuid.h"
-
-namespace LLAvatarAppearanceDefines
-{
-
-extern const S32 SCRATCH_TEX_WIDTH;
-extern const S32 SCRATCH_TEX_HEIGHT;
-
-static constexpr U32 AVATAR_HOVER = 11001;
-
-//--------------------------------------------------------------------
-// Enums
-//--------------------------------------------------------------------
-enum ETextureIndex
-{
- TEX_INVALID = -1,
- TEX_HEAD_BODYPAINT = 0,
- TEX_UPPER_SHIRT,
- TEX_LOWER_PANTS,
- TEX_EYES_IRIS,
- TEX_HAIR,
- TEX_UPPER_BODYPAINT,
- TEX_LOWER_BODYPAINT,
- TEX_LOWER_SHOES,
- TEX_HEAD_BAKED, // Pre-composited
- TEX_UPPER_BAKED, // Pre-composited
- TEX_LOWER_BAKED, // Pre-composited
- TEX_EYES_BAKED, // Pre-composited
- TEX_LOWER_SOCKS,
- TEX_UPPER_JACKET,
- TEX_LOWER_JACKET,
- TEX_UPPER_GLOVES,
- TEX_UPPER_UNDERSHIRT,
- TEX_LOWER_UNDERPANTS,
- TEX_SKIRT,
- TEX_SKIRT_BAKED, // Pre-composited
- TEX_HAIR_BAKED, // Pre-composited
- TEX_LOWER_ALPHA,
- TEX_UPPER_ALPHA,
- TEX_HEAD_ALPHA,
- TEX_EYES_ALPHA,
- TEX_HAIR_ALPHA,
- TEX_HEAD_TATTOO,
- TEX_UPPER_TATTOO,
- TEX_LOWER_TATTOO,
- TEX_HEAD_UNIVERSAL_TATTOO,
- TEX_UPPER_UNIVERSAL_TATTOO,
- TEX_LOWER_UNIVERSAL_TATTOO,
- TEX_SKIRT_TATTOO,
- TEX_HAIR_TATTOO,
- TEX_EYES_TATTOO,
- TEX_LEFT_ARM_TATTOO,
- TEX_LEFT_LEG_TATTOO,
- TEX_AUX1_TATTOO,
- TEX_AUX2_TATTOO,
- TEX_AUX3_TATTOO,
- TEX_LEFT_ARM_BAKED, // Pre-composited
- TEX_LEFT_LEG_BAKED, // Pre-composited
- TEX_AUX1_BAKED, // Pre-composited
- TEX_AUX2_BAKED, // Pre-composited
- TEX_AUX3_BAKED, // Pre-composited
- TEX_NUM_INDICES
-};
-
-enum EBakedTextureIndex
-{
- BAKED_HEAD = 0,
- BAKED_UPPER,
- BAKED_LOWER,
- BAKED_EYES,
- BAKED_SKIRT,
- BAKED_HAIR,
- BAKED_LEFT_ARM,
- BAKED_LEFT_LEG,
- BAKED_AUX1,
- BAKED_AUX2,
- BAKED_AUX3,
- BAKED_NUM_INDICES
-};
-
-// Reference IDs for each mesh. Used as indices for vector of joints
-enum EMeshIndex
-{
- MESH_ID_HAIR = 0,
- MESH_ID_HEAD,
- MESH_ID_EYELASH,
- MESH_ID_UPPER_BODY,
- MESH_ID_LOWER_BODY,
- MESH_ID_EYEBALL_LEFT,
- MESH_ID_EYEBALL_RIGHT,
- MESH_ID_SKIRT,
- MESH_ID_NUM_INDICES
-};
-
-//--------------------------------------------------------------------
-// Vector Types
-//--------------------------------------------------------------------
-typedef std::vector<ETextureIndex> texture_vec_t;
-typedef std::vector<EBakedTextureIndex> bakedtexture_vec_t;
-typedef std::vector<EMeshIndex> mesh_vec_t;
-typedef std::vector<LLWearableType::EType> wearables_vec_t;
-
-//------------------------------------------------------------------------
-// LLAvatarAppearanceDictionary
-//
-// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e.
-// information that is common to all avatars.
-//
-// This holds const data - it is initialized once and the contents never change after that.
-//------------------------------------------------------------------------
-class LLAvatarAppearanceDictionary
-{
- //--------------------------------------------------------------------
- // Constructors and Destructors
- //--------------------------------------------------------------------
-public:
- LLAvatarAppearanceDictionary();
- ~LLAvatarAppearanceDictionary();
-private:
- void createAssociations();
-
- //--------------------------------------------------------------------
- // Local and baked textures
- //--------------------------------------------------------------------
-public:
- struct TextureEntry : public LLDictionaryEntry
- {
- TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml
- bool is_local_texture,
- EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
- const std::string& default_image_name = "",
- LLWearableType::EType wearable_type = LLWearableType::WT_INVALID);
- const std::string mDefaultImageName;
- const LLWearableType::EType mWearableType;
- // It's either a local texture xor baked
- bool mIsLocalTexture;
- bool mIsBakedTexture;
- // If it's a local texture, it may be used by a baked texture
- bool mIsUsedByBakedTexture;
- EBakedTextureIndex mBakedTextureIndex;
- };
-
- struct Textures : public LLDictionary<ETextureIndex, TextureEntry>
- {
- Textures();
- } mTextures;
- const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); }
- const Textures& getTextures() const { return mTextures; }
-
- //--------------------------------------------------------------------
- // Meshes
- //--------------------------------------------------------------------
-public:
- struct MeshEntry : public LLDictionaryEntry
- {
- MeshEntry(EBakedTextureIndex baked_index,
- const std::string &name, // names of mesh types as they are used in avatar_lad.xml
- U8 level,
- LLJointPickName pick);
- // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml
- // Otherwise meshes will be unable to be found, or levels of detail will be ignored
- const U8 mLOD;
- const EBakedTextureIndex mBakedID;
- const LLJointPickName mPickName;
- };
-
- struct MeshEntries : public LLDictionary<EMeshIndex, MeshEntry>
- {
- MeshEntries();
- } mMeshEntries;
- const MeshEntry* getMeshEntry(EMeshIndex index) const { return mMeshEntries.lookup(index); }
- const MeshEntries& getMeshEntries() const { return mMeshEntries; }
-
- //--------------------------------------------------------------------
- // Baked Textures
- //--------------------------------------------------------------------
-public:
- struct BakedEntry : public LLDictionaryEntry
- {
- BakedEntry(ETextureIndex tex_index,
- const std::string &name, // unused, but necessary for templating.
- const std::string &hash_name,
- U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list
- // Local Textures
- const ETextureIndex mTextureIndex;
- texture_vec_t mLocalTextures;
- // Wearables
- const LLUUID mWearablesHashID;
- wearables_vec_t mWearables;
- };
-
- struct BakedTextures: public LLDictionary<EBakedTextureIndex, BakedEntry>
- {
- BakedTextures();
- } mBakedTextures;
- const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); }
- const BakedTextures& getBakedTextures() const { return mBakedTextures; }
-
- //--------------------------------------------------------------------
- // Convenience Functions
- //--------------------------------------------------------------------
-public:
- // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED
- ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t) const;
-
- // find a baked texture index based on its name
- EBakedTextureIndex findBakedByRegionName(std::string name);
- EBakedTextureIndex findBakedByImageName(std::string name);
-
- // Given a texture entry, determine which wearable type owns it.
- LLWearableType::EType getTEWearableType(ETextureIndex index) const;
-
- static bool isBakedImageId(const LLUUID& id);
- static EBakedTextureIndex assetIdToBakedTextureIndex(const LLUUID& id);
- static LLUUID localTextureIndexToMagicId(ETextureIndex t);
-
-}; // End LLAvatarAppearanceDictionary
-
-} // End namespace LLAvatarAppearanceDefines
-
-#endif //LL_AVATARAPPEARANCE_DEFINES_H
+/**
+ * @file llavatarappearancedefines.h
+ * @brief Various LLAvatarAppearance related definitions
+ * LLViewerObject
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_AVATARAPPEARANCE_DEFINES_H
+#define LL_AVATARAPPEARANCE_DEFINES_H
+
+#include <vector>
+#include "lljointpickname.h"
+#include "lldictionary.h"
+#include "llwearabletype.h"
+#include "lluuid.h"
+
+namespace LLAvatarAppearanceDefines
+{
+
+extern const S32 SCRATCH_TEX_WIDTH;
+extern const S32 SCRATCH_TEX_HEIGHT;
+
+static constexpr U32 AVATAR_HOVER = 11001;
+
+//--------------------------------------------------------------------
+// Enums
+//--------------------------------------------------------------------
+enum ETextureIndex
+{
+ TEX_INVALID = -1,
+ TEX_HEAD_BODYPAINT = 0,
+ TEX_UPPER_SHIRT,
+ TEX_LOWER_PANTS,
+ TEX_EYES_IRIS,
+ TEX_HAIR,
+ TEX_UPPER_BODYPAINT,
+ TEX_LOWER_BODYPAINT,
+ TEX_LOWER_SHOES,
+ TEX_HEAD_BAKED, // Pre-composited
+ TEX_UPPER_BAKED, // Pre-composited
+ TEX_LOWER_BAKED, // Pre-composited
+ TEX_EYES_BAKED, // Pre-composited
+ TEX_LOWER_SOCKS,
+ TEX_UPPER_JACKET,
+ TEX_LOWER_JACKET,
+ TEX_UPPER_GLOVES,
+ TEX_UPPER_UNDERSHIRT,
+ TEX_LOWER_UNDERPANTS,
+ TEX_SKIRT,
+ TEX_SKIRT_BAKED, // Pre-composited
+ TEX_HAIR_BAKED, // Pre-composited
+ TEX_LOWER_ALPHA,
+ TEX_UPPER_ALPHA,
+ TEX_HEAD_ALPHA,
+ TEX_EYES_ALPHA,
+ TEX_HAIR_ALPHA,
+ TEX_HEAD_TATTOO,
+ TEX_UPPER_TATTOO,
+ TEX_LOWER_TATTOO,
+ TEX_HEAD_UNIVERSAL_TATTOO,
+ TEX_UPPER_UNIVERSAL_TATTOO,
+ TEX_LOWER_UNIVERSAL_TATTOO,
+ TEX_SKIRT_TATTOO,
+ TEX_HAIR_TATTOO,
+ TEX_EYES_TATTOO,
+ TEX_LEFT_ARM_TATTOO,
+ TEX_LEFT_LEG_TATTOO,
+ TEX_AUX1_TATTOO,
+ TEX_AUX2_TATTOO,
+ TEX_AUX3_TATTOO,
+ TEX_LEFT_ARM_BAKED, // Pre-composited
+ TEX_LEFT_LEG_BAKED, // Pre-composited
+ TEX_AUX1_BAKED, // Pre-composited
+ TEX_AUX2_BAKED, // Pre-composited
+ TEX_AUX3_BAKED, // Pre-composited
+ TEX_NUM_INDICES
+};
+
+enum EBakedTextureIndex
+{
+ BAKED_HEAD = 0,
+ BAKED_UPPER,
+ BAKED_LOWER,
+ BAKED_EYES,
+ BAKED_SKIRT,
+ BAKED_HAIR,
+ BAKED_LEFT_ARM,
+ BAKED_LEFT_LEG,
+ BAKED_AUX1,
+ BAKED_AUX2,
+ BAKED_AUX3,
+ BAKED_NUM_INDICES
+};
+
+// Reference IDs for each mesh. Used as indices for vector of joints
+enum EMeshIndex
+{
+ MESH_ID_HAIR = 0,
+ MESH_ID_HEAD,
+ MESH_ID_EYELASH,
+ MESH_ID_UPPER_BODY,
+ MESH_ID_LOWER_BODY,
+ MESH_ID_EYEBALL_LEFT,
+ MESH_ID_EYEBALL_RIGHT,
+ MESH_ID_SKIRT,
+ MESH_ID_NUM_INDICES
+};
+
+//--------------------------------------------------------------------
+// Vector Types
+//--------------------------------------------------------------------
+typedef std::vector<ETextureIndex> texture_vec_t;
+typedef std::vector<EBakedTextureIndex> bakedtexture_vec_t;
+typedef std::vector<EMeshIndex> mesh_vec_t;
+typedef std::vector<LLWearableType::EType> wearables_vec_t;
+
+//------------------------------------------------------------------------
+// LLAvatarAppearanceDictionary
+//
+// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e.
+// information that is common to all avatars.
+//
+// This holds const data - it is initialized once and the contents never change after that.
+//------------------------------------------------------------------------
+class LLAvatarAppearanceDictionary
+{
+ //--------------------------------------------------------------------
+ // Constructors and Destructors
+ //--------------------------------------------------------------------
+public:
+ LLAvatarAppearanceDictionary();
+ ~LLAvatarAppearanceDictionary();
+private:
+ void createAssociations();
+
+ //--------------------------------------------------------------------
+ // Local and baked textures
+ //--------------------------------------------------------------------
+public:
+ struct TextureEntry : public LLDictionaryEntry
+ {
+ TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml
+ bool is_local_texture,
+ EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
+ const std::string& default_image_name = "",
+ LLWearableType::EType wearable_type = LLWearableType::WT_INVALID);
+ const std::string mDefaultImageName;
+ const LLWearableType::EType mWearableType;
+ // It's either a local texture xor baked
+ bool mIsLocalTexture;
+ bool mIsBakedTexture;
+ // If it's a local texture, it may be used by a baked texture
+ bool mIsUsedByBakedTexture;
+ EBakedTextureIndex mBakedTextureIndex;
+ };
+
+ struct Textures : public LLDictionary<ETextureIndex, TextureEntry>
+ {
+ Textures();
+ } mTextures;
+ const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); }
+ const Textures& getTextures() const { return mTextures; }
+
+ //--------------------------------------------------------------------
+ // Meshes
+ //--------------------------------------------------------------------
+public:
+ struct MeshEntry : public LLDictionaryEntry
+ {
+ MeshEntry(EBakedTextureIndex baked_index,
+ const std::string &name, // names of mesh types as they are used in avatar_lad.xml
+ U8 level,
+ LLJointPickName pick);
+ // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml
+ // Otherwise meshes will be unable to be found, or levels of detail will be ignored
+ const U8 mLOD;
+ const EBakedTextureIndex mBakedID;
+ const LLJointPickName mPickName;
+ };
+
+ struct MeshEntries : public LLDictionary<EMeshIndex, MeshEntry>
+ {
+ MeshEntries();
+ } mMeshEntries;
+ const MeshEntry* getMeshEntry(EMeshIndex index) const { return mMeshEntries.lookup(index); }
+ const MeshEntries& getMeshEntries() const { return mMeshEntries; }
+
+ //--------------------------------------------------------------------
+ // Baked Textures
+ //--------------------------------------------------------------------
+public:
+ struct BakedEntry : public LLDictionaryEntry
+ {
+ BakedEntry(ETextureIndex tex_index,
+ const std::string &name, // unused, but necessary for templating.
+ const std::string &hash_name,
+ U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list
+ // Local Textures
+ const ETextureIndex mTextureIndex;
+ texture_vec_t mLocalTextures;
+ // Wearables
+ const LLUUID mWearablesHashID;
+ wearables_vec_t mWearables;
+ };
+
+ struct BakedTextures: public LLDictionary<EBakedTextureIndex, BakedEntry>
+ {
+ BakedTextures();
+ } mBakedTextures;
+ const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); }
+ const BakedTextures& getBakedTextures() const { return mBakedTextures; }
+
+ //--------------------------------------------------------------------
+ // Convenience Functions
+ //--------------------------------------------------------------------
+public:
+ // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED
+ ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t) const;
+
+ // find a baked texture index based on its name
+ EBakedTextureIndex findBakedByRegionName(std::string name);
+ EBakedTextureIndex findBakedByImageName(std::string name);
+
+ // Given a texture entry, determine which wearable type owns it.
+ LLWearableType::EType getTEWearableType(ETextureIndex index) const;
+
+ static bool isBakedImageId(const LLUUID& id);
+ static EBakedTextureIndex assetIdToBakedTextureIndex(const LLUUID& id);
+ static LLUUID localTextureIndexToMagicId(ETextureIndex t);
+
+}; // End LLAvatarAppearanceDictionary
+
+} // End namespace LLAvatarAppearanceDefines
+
+#endif //LL_AVATARAPPEARANCE_DEFINES_H
diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp
index 579381958c..a3bbcf1ad3 100644
--- a/indra/llappearance/llavatarjoint.cpp
+++ b/indra/llappearance/llavatarjoint.cpp
@@ -1,316 +1,316 @@
-/**
- * @file llavatarjoint.cpp
- * @brief Implementation of LLAvatarJoint class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "llavatarjoint.h"
-
-#include "llgl.h"
-#include "llrender.h"
-#include "llmath.h"
-#include "llglheaders.h"
-#include "llavatarappearance.h"
-
-const F32 DEFAULT_AVATAR_JOINT_LOD = 0.0f;
-
-//-----------------------------------------------------------------------------
-// Static Data
-//-----------------------------------------------------------------------------
-bool LLAvatarJoint::sDisableLOD = false;
-
-//-----------------------------------------------------------------------------
-// LLAvatarJoint()
-// Class Constructors
-//-----------------------------------------------------------------------------
-LLAvatarJoint::LLAvatarJoint() :
- LLJoint()
-{
- init();
-}
-
-LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
- LLJoint(joint_num)
-{
- init();
-}
-
-LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
- LLJoint(name, parent)
-{
- init();
-}
-
-void LLAvatarJoint::init()
-{
- mValid = false;
- mComponents = SC_JOINT | SC_BONE | SC_AXES;
- mMinPixelArea = DEFAULT_AVATAR_JOINT_LOD;
- mPickName = PN_DEFAULT;
- mVisible = true;
- mMeshID = 0;
- mIsTransparent = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLAvatarJoint()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLAvatarJoint::~LLAvatarJoint()
-{
-}
-
-
-//--------------------------------------------------------------------
-// setValid()
-//--------------------------------------------------------------------
-void LLAvatarJoint::setValid( bool valid, bool recursive )
-{
- //----------------------------------------------------------------
- // set visibility for this joint
- //----------------------------------------------------------------
- mValid = valid;
-
- //----------------------------------------------------------------
- // set visibility for children
- //----------------------------------------------------------------
- if (recursive)
- {
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->setValid(valid, true);
- }
- }
-
-}
-
-//--------------------------------------------------------------------
-// setSkeletonComponents()
-//--------------------------------------------------------------------
-void LLAvatarJoint::setSkeletonComponents( U32 comp, bool recursive )
-{
- mComponents = comp;
- if (recursive)
- {
- for (auto child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->setSkeletonComponents(comp, recursive);
- }
- }
-}
-
-void LLAvatarJoint::setVisible(bool visible, bool recursive)
-{
- mVisible = visible;
-
- if (recursive)
- {
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->setVisible(visible, recursive);
- }
- }
-}
-
-void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
-{
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
- }
-}
-
-void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind, bool terse_update)
-{
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
- }
-}
-
-void LLAvatarJoint::updateJointGeometry()
-{
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->updateJointGeometry();
- }
-}
-
-
-bool LLAvatarJoint::updateLOD(F32 pixel_area, bool activate)
-{
- bool lod_changed = false;
- bool found_lod = false;
-
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- F32 jointLOD = joint->getLOD();
-
- if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
- {
- // we've already found a joint to enable, so enable the rest as alternatives
- lod_changed |= joint->updateLOD(pixel_area, true);
- }
- else
- {
- if (pixel_area >= jointLOD || sDisableLOD)
- {
- lod_changed |= joint->updateLOD(pixel_area, true);
- found_lod = true;
- }
- else
- {
- lod_changed |= joint->updateLOD(pixel_area, false);
- }
- }
- }
- return lod_changed;
-}
-
-void LLAvatarJoint::dump()
-{
- for (LLJoint* child : mChildren)
- {
- LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
- joint->dump();
- }
-}
-
-
-void LLAvatarJoint::setMeshesToChildren()
-{
- removeAllChildren();
- for (LLAvatarJointMesh* mesh : mMeshParts)
- {
- addChild(mesh);
- }
-}
-//-----------------------------------------------------------------------------
-// LLAvatarJointCollisionVolume()
-//-----------------------------------------------------------------------------
-
-LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume()
-{
- mUpdateXform = false;
-}
-
-/*virtual*/
-U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, bool first_pass, bool is_dummy )
-{
- LL_ERRS() << "Cannot call render() on LLAvatarJointCollisionVolume" << LL_ENDL;
- return 0;
-}
-
-LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset)
-{
- mUpdateXform = true;
-
- LLVector3 result = offset;
- result.scaleVec(getScale());
- result.rotVec(getWorldRotation());
- result += getWorldPosition();
-
- return result;
-}
-
-void LLAvatarJointCollisionVolume::renderCollision()
-{
- updateWorldMatrix();
-
- gGL.pushMatrix();
- gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
-
- gGL.diffuseColor3f( 0.f, 0.f, 1.f );
-
- gGL.begin(LLRender::LINES);
-
- LLVector3 v[] =
- {
- LLVector3(1,0,0),
- LLVector3(-1,0,0),
- LLVector3(0,1,0),
- LLVector3(0,-1,0),
-
- LLVector3(0,0,-1),
- LLVector3(0,0,1),
- };
-
- //sides
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[2].mV);
-
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[3].mV);
-
- gGL.vertex3fv(v[1].mV);
- gGL.vertex3fv(v[2].mV);
-
- gGL.vertex3fv(v[1].mV);
- gGL.vertex3fv(v[3].mV);
-
-
- //top
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[4].mV);
-
- gGL.vertex3fv(v[1].mV);
- gGL.vertex3fv(v[4].mV);
-
- gGL.vertex3fv(v[2].mV);
- gGL.vertex3fv(v[4].mV);
-
- gGL.vertex3fv(v[3].mV);
- gGL.vertex3fv(v[4].mV);
-
-
- //bottom
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[5].mV);
-
- gGL.vertex3fv(v[1].mV);
- gGL.vertex3fv(v[5].mV);
-
- gGL.vertex3fv(v[2].mV);
- gGL.vertex3fv(v[5].mV);
-
- gGL.vertex3fv(v[3].mV);
- gGL.vertex3fv(v[5].mV);
-
- gGL.end();
-
- gGL.popMatrix();
-}
-
-
-// End
+/**
+ * @file llavatarjoint.cpp
+ * @brief Implementation of LLAvatarJoint class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llavatarjoint.h"
+
+#include "llgl.h"
+#include "llrender.h"
+#include "llmath.h"
+#include "llglheaders.h"
+#include "llavatarappearance.h"
+
+const F32 DEFAULT_AVATAR_JOINT_LOD = 0.0f;
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+bool LLAvatarJoint::sDisableLOD = false;
+
+//-----------------------------------------------------------------------------
+// LLAvatarJoint()
+// Class Constructors
+//-----------------------------------------------------------------------------
+LLAvatarJoint::LLAvatarJoint() :
+ LLJoint()
+{
+ init();
+}
+
+LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
+ LLJoint(joint_num)
+{
+ init();
+}
+
+LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
+ LLJoint(name, parent)
+{
+ init();
+}
+
+void LLAvatarJoint::init()
+{
+ mValid = false;
+ mComponents = SC_JOINT | SC_BONE | SC_AXES;
+ mMinPixelArea = DEFAULT_AVATAR_JOINT_LOD;
+ mPickName = PN_DEFAULT;
+ mVisible = true;
+ mMeshID = 0;
+ mIsTransparent = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLAvatarJoint()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLAvatarJoint::~LLAvatarJoint()
+{
+}
+
+
+//--------------------------------------------------------------------
+// setValid()
+//--------------------------------------------------------------------
+void LLAvatarJoint::setValid( bool valid, bool recursive )
+{
+ //----------------------------------------------------------------
+ // set visibility for this joint
+ //----------------------------------------------------------------
+ mValid = valid;
+
+ //----------------------------------------------------------------
+ // set visibility for children
+ //----------------------------------------------------------------
+ if (recursive)
+ {
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->setValid(valid, true);
+ }
+ }
+
+}
+
+//--------------------------------------------------------------------
+// setSkeletonComponents()
+//--------------------------------------------------------------------
+void LLAvatarJoint::setSkeletonComponents( U32 comp, bool recursive )
+{
+ mComponents = comp;
+ if (recursive)
+ {
+ for (auto child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->setSkeletonComponents(comp, recursive);
+ }
+ }
+}
+
+void LLAvatarJoint::setVisible(bool visible, bool recursive)
+{
+ mVisible = visible;
+
+ if (recursive)
+ {
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->setVisible(visible, recursive);
+ }
+ }
+}
+
+void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
+{
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
+ }
+}
+
+void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind, bool terse_update)
+{
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
+ }
+}
+
+void LLAvatarJoint::updateJointGeometry()
+{
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->updateJointGeometry();
+ }
+}
+
+
+bool LLAvatarJoint::updateLOD(F32 pixel_area, bool activate)
+{
+ bool lod_changed = false;
+ bool found_lod = false;
+
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ F32 jointLOD = joint->getLOD();
+
+ if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
+ {
+ // we've already found a joint to enable, so enable the rest as alternatives
+ lod_changed |= joint->updateLOD(pixel_area, true);
+ }
+ else
+ {
+ if (pixel_area >= jointLOD || sDisableLOD)
+ {
+ lod_changed |= joint->updateLOD(pixel_area, true);
+ found_lod = true;
+ }
+ else
+ {
+ lod_changed |= joint->updateLOD(pixel_area, false);
+ }
+ }
+ }
+ return lod_changed;
+}
+
+void LLAvatarJoint::dump()
+{
+ for (LLJoint* child : mChildren)
+ {
+ LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
+ joint->dump();
+ }
+}
+
+
+void LLAvatarJoint::setMeshesToChildren()
+{
+ removeAllChildren();
+ for (LLAvatarJointMesh* mesh : mMeshParts)
+ {
+ addChild(mesh);
+ }
+}
+//-----------------------------------------------------------------------------
+// LLAvatarJointCollisionVolume()
+//-----------------------------------------------------------------------------
+
+LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume()
+{
+ mUpdateXform = false;
+}
+
+/*virtual*/
+U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, bool first_pass, bool is_dummy )
+{
+ LL_ERRS() << "Cannot call render() on LLAvatarJointCollisionVolume" << LL_ENDL;
+ return 0;
+}
+
+LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset)
+{
+ mUpdateXform = true;
+
+ LLVector3 result = offset;
+ result.scaleVec(getScale());
+ result.rotVec(getWorldRotation());
+ result += getWorldPosition();
+
+ return result;
+}
+
+void LLAvatarJointCollisionVolume::renderCollision()
+{
+ updateWorldMatrix();
+
+ gGL.pushMatrix();
+ gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
+
+ gGL.diffuseColor3f( 0.f, 0.f, 1.f );
+
+ gGL.begin(LLRender::LINES);
+
+ LLVector3 v[] =
+ {
+ LLVector3(1,0,0),
+ LLVector3(-1,0,0),
+ LLVector3(0,1,0),
+ LLVector3(0,-1,0),
+
+ LLVector3(0,0,-1),
+ LLVector3(0,0,1),
+ };
+
+ //sides
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[2].mV);
+
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[3].mV);
+
+ gGL.vertex3fv(v[1].mV);
+ gGL.vertex3fv(v[2].mV);
+
+ gGL.vertex3fv(v[1].mV);
+ gGL.vertex3fv(v[3].mV);
+
+
+ //top
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[4].mV);
+
+ gGL.vertex3fv(v[1].mV);
+ gGL.vertex3fv(v[4].mV);
+
+ gGL.vertex3fv(v[2].mV);
+ gGL.vertex3fv(v[4].mV);
+
+ gGL.vertex3fv(v[3].mV);
+ gGL.vertex3fv(v[4].mV);
+
+
+ //bottom
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[5].mV);
+
+ gGL.vertex3fv(v[1].mV);
+ gGL.vertex3fv(v[5].mV);
+
+ gGL.vertex3fv(v[2].mV);
+ gGL.vertex3fv(v[5].mV);
+
+ gGL.vertex3fv(v[3].mV);
+ gGL.vertex3fv(v[5].mV);
+
+ gGL.end();
+
+ gGL.popMatrix();
+}
+
+
+// End
diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h
index 09269bbc3f..c3f181e4f8 100644
--- a/indra/llappearance/llavatarjoint.h
+++ b/indra/llappearance/llavatarjoint.h
@@ -1,140 +1,140 @@
-/**
- * @file llavatarjoint.h
- * @brief Implementation of LLAvatarJoint class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLAVATARJOINT_H
-#define LL_LLAVATARJOINT_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "lljoint.h"
-#include "lljointpickname.h"
-
-class LLFace;
-class LLAvatarJointMesh;
-
-extern const F32 DEFAULT_AVATAR_JOINT_LOD;
-
-//-----------------------------------------------------------------------------
-// class LLViewerJoint
-//-----------------------------------------------------------------------------
-class LLAvatarJoint :
- public LLJoint
-{
-public:
- LLAvatarJoint();
- LLAvatarJoint(S32 joint_num);
- // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
- LLAvatarJoint(const std::string &name, LLJoint *parent = NULL);
- virtual ~LLAvatarJoint();
-
- // Gets the validity of this joint
- bool getValid() { return mValid; }
-
- // Sets the validity of this joint
- virtual void setValid( bool valid, bool recursive=false );
-
- // Returns true if this object is transparent.
- // This is used to determine in which order to draw objects.
- virtual bool isTransparent() { return mIsTransparent; }
-
- // Returns true if this object should inherit scale modifiers from its immediate parent
- virtual bool inheritScale() { return false; }
-
- enum Components
- {
- SC_BONE = 1,
- SC_JOINT = 2,
- SC_AXES = 4
- };
-
- // Selects which skeleton components to draw
- void setSkeletonComponents( U32 comp, bool recursive = true );
-
- // Returns which skeleton components are enables for drawing
- U32 getSkeletonComponents() { return mComponents; }
-
- // Sets the level of detail for this node as a minimum
- // pixel area threshold. If the current pixel area for this
- // object is less than the specified threshold, the node is
- // not traversed. In addition, if a value is specified (not
- // default of 0.0), and the pixel area is larger than the
- // specified minimum, the node is rendered, but no other siblings
- // of this node under the same parent will be.
- F32 getLOD() { return mMinPixelArea; }
- void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; }
-
- void setPickName(LLJointPickName name) { mPickName = name; }
- LLJointPickName getPickName() { return mPickName; }
-
- void setVisible( bool visible, bool recursive );
-
- // Takes meshes in mMeshParts and sets each one as a child joint
- void setMeshesToChildren();
-
- // LLViewerJoint interface
- virtual U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false ) = 0;
- virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
- virtual void updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind = false, bool terse_update = false);
- virtual bool updateLOD(F32 pixel_area, bool activate);
- virtual void updateJointGeometry();
- virtual void dump();
-
-
-public:
- static bool sDisableLOD;
- avatar_joint_mesh_list_t mMeshParts; //LLViewerJointMesh*
- void setMeshID( S32 id ) {mMeshID = id;}
-
-protected:
- void init();
-
- bool mValid;
- bool mIsTransparent;
- U32 mComponents;
- F32 mMinPixelArea;
- LLJointPickName mPickName;
- bool mVisible;
- S32 mMeshID;
-};
-
-class LLAvatarJointCollisionVolume : public LLAvatarJoint
-{
-public:
- LLAvatarJointCollisionVolume();
- virtual ~LLAvatarJointCollisionVolume() {};
-
- /*virtual*/ bool inheritScale() { return true; }
- /*virtual*/ U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false );
-
- void renderCollision();
-
- LLVector3 getVolumePos(LLVector3 &offset);
-};
-
-#endif // LL_LLAVATARJOINT_H
-
-
+/**
+ * @file llavatarjoint.h
+ * @brief Implementation of LLAvatarJoint class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAVATARJOINT_H
+#define LL_LLAVATARJOINT_H
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "lljoint.h"
+#include "lljointpickname.h"
+
+class LLFace;
+class LLAvatarJointMesh;
+
+extern const F32 DEFAULT_AVATAR_JOINT_LOD;
+
+//-----------------------------------------------------------------------------
+// class LLViewerJoint
+//-----------------------------------------------------------------------------
+class LLAvatarJoint :
+ public LLJoint
+{
+public:
+ LLAvatarJoint();
+ LLAvatarJoint(S32 joint_num);
+ // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
+ LLAvatarJoint(const std::string &name, LLJoint *parent = NULL);
+ virtual ~LLAvatarJoint();
+
+ // Gets the validity of this joint
+ bool getValid() { return mValid; }
+
+ // Sets the validity of this joint
+ virtual void setValid( bool valid, bool recursive=false );
+
+ // Returns true if this object is transparent.
+ // This is used to determine in which order to draw objects.
+ virtual bool isTransparent() { return mIsTransparent; }
+
+ // Returns true if this object should inherit scale modifiers from its immediate parent
+ virtual bool inheritScale() { return false; }
+
+ enum Components
+ {
+ SC_BONE = 1,
+ SC_JOINT = 2,
+ SC_AXES = 4
+ };
+
+ // Selects which skeleton components to draw
+ void setSkeletonComponents( U32 comp, bool recursive = true );
+
+ // Returns which skeleton components are enables for drawing
+ U32 getSkeletonComponents() { return mComponents; }
+
+ // Sets the level of detail for this node as a minimum
+ // pixel area threshold. If the current pixel area for this
+ // object is less than the specified threshold, the node is
+ // not traversed. In addition, if a value is specified (not
+ // default of 0.0), and the pixel area is larger than the
+ // specified minimum, the node is rendered, but no other siblings
+ // of this node under the same parent will be.
+ F32 getLOD() { return mMinPixelArea; }
+ void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; }
+
+ void setPickName(LLJointPickName name) { mPickName = name; }
+ LLJointPickName getPickName() { return mPickName; }
+
+ void setVisible( bool visible, bool recursive );
+
+ // Takes meshes in mMeshParts and sets each one as a child joint
+ void setMeshesToChildren();
+
+ // LLViewerJoint interface
+ virtual U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false ) = 0;
+ virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
+ virtual void updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind = false, bool terse_update = false);
+ virtual bool updateLOD(F32 pixel_area, bool activate);
+ virtual void updateJointGeometry();
+ virtual void dump();
+
+
+public:
+ static bool sDisableLOD;
+ avatar_joint_mesh_list_t mMeshParts; //LLViewerJointMesh*
+ void setMeshID( S32 id ) {mMeshID = id;}
+
+protected:
+ void init();
+
+ bool mValid;
+ bool mIsTransparent;
+ U32 mComponents;
+ F32 mMinPixelArea;
+ LLJointPickName mPickName;
+ bool mVisible;
+ S32 mMeshID;
+};
+
+class LLAvatarJointCollisionVolume : public LLAvatarJoint
+{
+public:
+ LLAvatarJointCollisionVolume();
+ virtual ~LLAvatarJointCollisionVolume() {};
+
+ /*virtual*/ bool inheritScale() { return true; }
+ /*virtual*/ U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false );
+
+ void renderCollision();
+
+ LLVector3 getVolumePos(LLVector3 &offset);
+};
+
+#endif // LL_LLAVATARJOINT_H
+
+
diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp
index 9b2a1d9b4c..ebdb14fd42 100644
--- a/indra/llappearance/llavatarjointmesh.cpp
+++ b/indra/llappearance/llavatarjointmesh.cpp
@@ -1,390 +1,390 @@
-/**
- * @file LLAvatarJointMesh.cpp
- * @brief Implementation of LLAvatarJointMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-#include "llfasttimer.h"
-#include "llrender.h"
-
-#include "llavatarjointmesh.h"
-#include "llavatarappearance.h"
-#include "lltexlayer.h"
-#include "llmath.h"
-#include "v4math.h"
-#include "m3math.h"
-#include "m4math.h"
-#include "llmatrix4a.h"
-
-
-// Utility functions added with Bento to simplify handling of extra
-// spine joints, or other new joints internal to the original
-// skeleton, and unknown to the system avatar.
-
-//-----------------------------------------------------------------------------
-// getBaseSkeletonAncestor()
-//-----------------------------------------------------------------------------
-LLAvatarJoint *getBaseSkeletonAncestor(LLAvatarJoint* joint)
-{
- LLJoint *ancestor = joint->getParent();
- while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE))
- {
- LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL;
- ancestor = ancestor->getParent();
- }
- return (LLAvatarJoint*) ancestor;
-}
-
-//-----------------------------------------------------------------------------
-// totalSkinOffset()
-//-----------------------------------------------------------------------------
-LLVector3 totalSkinOffset(LLAvatarJoint *joint)
-{
- LLVector3 totalOffset;
- while (joint)
- {
- if (joint->getSupport() == LLJoint::SUPPORT_BASE)
- {
- totalOffset += joint->getSkinOffset();
- }
- joint = (LLAvatarJoint*)joint->getParent();
- }
- return totalOffset;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh::LLSkinJoint
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLSkinJoint
-//-----------------------------------------------------------------------------
-LLSkinJoint::LLSkinJoint()
-{
- mJoint = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// ~LLSkinJoint
-//-----------------------------------------------------------------------------
-LLSkinJoint::~LLSkinJoint()
-{
- mJoint = NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLSkinJoint::setupSkinJoint()
-//-----------------------------------------------------------------------------
-bool LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
-{
- // find the named joint
- mJoint = joint;
- if ( !mJoint )
- {
- LL_INFOS() << "Can't find joint" << LL_ENDL;
- }
-
- // compute the inverse root skin matrix
- mRootToJointSkinOffset = totalSkinOffset(joint);
- mRootToJointSkinOffset = -mRootToJointSkinOffset;
-
- //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
- mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(joint));
- mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-bool LLAvatarJointMesh::sPipelineRender = false;
-U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
-LLColor4 LLAvatarJointMesh::sClothingInnerColor;
-
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh()
-//-----------------------------------------------------------------------------
-LLAvatarJointMesh::LLAvatarJointMesh()
- :
- mTexture( NULL ),
- mLayerSet( NULL ),
- mTestImageName( 0 ),
- mFaceIndexCount(0)
-{
-
- mColor[0] = 1.0f;
- mColor[1] = 1.0f;
- mColor[2] = 1.0f;
- mColor[3] = 1.0f;
- mShiny = 0.0f;
- mCullBackFaces = true;
-
- mMesh = NULL;
-
- mNumSkinJoints = 0;
- mSkinJoints = NULL;
-
- mFace = NULL;
-
- mMeshID = 0;
- mUpdateXform = false;
-
- mValid = false;
-
- mIsTransparent = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLAvatarJointMesh()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLAvatarJointMesh::~LLAvatarJointMesh()
-{
- mMesh = NULL;
- mTexture = NULL;
- freeSkinData();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh::allocateSkinData()
-//-----------------------------------------------------------------------------
-bool LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints )
-{
- mSkinJoints = new LLSkinJoint[ numSkinJoints ];
- mNumSkinJoints = numSkinJoints;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh::freeSkinData()
-//-----------------------------------------------------------------------------
-void LLAvatarJointMesh::freeSkinData()
-{
- mNumSkinJoints = 0;
- delete [] mSkinJoints;
- mSkinJoints = NULL;
-}
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::getColor()
-//--------------------------------------------------------------------
-void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
-{
- *red = mColor[0];
- *green = mColor[1];
- *blue = mColor[2];
- *alpha = mColor[3];
-}
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::setColor()
-//--------------------------------------------------------------------
-void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
-{
- mColor[0] = red;
- mColor[1] = green;
- mColor[2] = blue;
- mColor[3] = alpha;
-}
-
-void LLAvatarJointMesh::setColor( const LLColor4& color )
-{
- mColor = color;
-}
-
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::getTexture()
-//--------------------------------------------------------------------
-//LLViewerTexture *LLAvatarJointMesh::getTexture()
-//{
-// return mTexture;
-//}
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::setTexture()
-//--------------------------------------------------------------------
-void LLAvatarJointMesh::setTexture( LLGLTexture *texture )
-{
- mTexture = texture;
-
- // texture and dynamic_texture are mutually exclusive
- if( texture )
- {
- mLayerSet = NULL;
- //texture->bindTexture(0);
- //texture->setClamp(true, true);
- }
-}
-
-
-bool LLAvatarJointMesh::hasGLTexture() const
-{
- return mTexture.notNull() && mTexture->hasGLTexture();
-}
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::setLayerSet()
-// Sets the shape texture (takes precedence over normal texture)
-//--------------------------------------------------------------------
-void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set )
-{
- mLayerSet = layer_set;
-
- // texture and dynamic_texture are mutually exclusive
- if( layer_set )
- {
- mTexture = NULL;
- }
-}
-
-bool LLAvatarJointMesh::hasComposite() const
-{
- return (mLayerSet && mLayerSet->hasComposite());
-}
-
-
-//--------------------------------------------------------------------
-// LLAvatarJointMesh::getMesh()
-//--------------------------------------------------------------------
-LLPolyMesh *LLAvatarJointMesh::getMesh()
-{
- return mMesh;
-}
-
-//-----------------------------------------------------------------------------
-// LLAvatarJointMesh::setMesh()
-//-----------------------------------------------------------------------------
-void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
-{
- // set the mesh pointer
- mMesh = mesh;
-
- // release any existing skin joints
- freeSkinData();
-
- if ( mMesh == NULL )
- {
- return;
- }
-
- // acquire the transform from the mesh object
- // SL-315
- setPosition( mMesh->getPosition() );
- setRotation( mMesh->getRotation() );
- setScale( mMesh->getScale() );
-
- // create skin joints if necessary
- if ( mMesh->hasWeights() && !mMesh->isLOD())
- {
- U32 numJointNames = mMesh->getNumJointNames();
-
- allocateSkinData( numJointNames );
- std::string *jointNames = mMesh->getJointNames();
-
- U32 jn;
- for (jn = 0; jn < numJointNames; jn++)
- {
- //LL_INFOS() << "Setting up joint " << jointNames[jn] << LL_ENDL;
- LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
- mSkinJoints[jn].setupSkinJoint( joint );
- }
- }
-
- // setup joint array
- if (!mMesh->isLOD())
- {
- setupJoint((LLAvatarJoint*)getRoot());
- LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
- }
-
-}
-
-//-----------------------------------------------------------------------------
-// setupJoint()
-//-----------------------------------------------------------------------------
-void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
-{
- U32 sj;
-
- for (sj=0; sj<mNumSkinJoints; sj++)
- {
- LLSkinJoint &js = mSkinJoints[sj];
-
- if (js.mJoint != current_joint)
- {
- continue;
- }
-
- // we've found a skinjoint for this joint..
- LL_DEBUGS("Avatar") << "Mesh: " << getName() << " joint " << current_joint->getName() << " matches skinjoint " << sj << LL_ENDL;
-
- // is the last joint in the array our parent?
-
- std::vector<LLJointRenderData*> &jrd = mMesh->mJointRenderData;
-
- // SL-287 - need to update this so the results are the same if
- // additional extended-skeleton joints lie between this joint
- // and the original parent.
- LLJoint *ancestor = getBaseSkeletonAncestor(current_joint);
- if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix())
- {
- // ...then just add ourselves
- LLAvatarJoint* jointp = js.mJoint;
- jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
- LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
- }
- // otherwise add our ancestor and ourselves
- else
- {
- jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL));
- LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL;
- jrd.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
- LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL;
- }
- }
-
- // depth-first traversal
- for (LLJoint* joint : current_joint->mChildren)
- {
- LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
- setupJoint(child_joint);
- }
-}
-
-
-// End
+/**
+ * @file LLAvatarJointMesh.cpp
+ * @brief Implementation of LLAvatarJointMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+#include "llfasttimer.h"
+#include "llrender.h"
+
+#include "llavatarjointmesh.h"
+#include "llavatarappearance.h"
+#include "lltexlayer.h"
+#include "llmath.h"
+#include "v4math.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "llmatrix4a.h"
+
+
+// Utility functions added with Bento to simplify handling of extra
+// spine joints, or other new joints internal to the original
+// skeleton, and unknown to the system avatar.
+
+//-----------------------------------------------------------------------------
+// getBaseSkeletonAncestor()
+//-----------------------------------------------------------------------------
+LLAvatarJoint *getBaseSkeletonAncestor(LLAvatarJoint* joint)
+{
+ LLJoint *ancestor = joint->getParent();
+ while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE))
+ {
+ LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL;
+ ancestor = ancestor->getParent();
+ }
+ return (LLAvatarJoint*) ancestor;
+}
+
+//-----------------------------------------------------------------------------
+// totalSkinOffset()
+//-----------------------------------------------------------------------------
+LLVector3 totalSkinOffset(LLAvatarJoint *joint)
+{
+ LLVector3 totalOffset;
+ while (joint)
+ {
+ if (joint->getSupport() == LLJoint::SUPPORT_BASE)
+ {
+ totalOffset += joint->getSkinOffset();
+ }
+ joint = (LLAvatarJoint*)joint->getParent();
+ }
+ return totalOffset;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::LLSkinJoint
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// LLSkinJoint
+//-----------------------------------------------------------------------------
+LLSkinJoint::LLSkinJoint()
+{
+ mJoint = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLSkinJoint
+//-----------------------------------------------------------------------------
+LLSkinJoint::~LLSkinJoint()
+{
+ mJoint = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLSkinJoint::setupSkinJoint()
+//-----------------------------------------------------------------------------
+bool LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
+{
+ // find the named joint
+ mJoint = joint;
+ if ( !mJoint )
+ {
+ LL_INFOS() << "Can't find joint" << LL_ENDL;
+ }
+
+ // compute the inverse root skin matrix
+ mRootToJointSkinOffset = totalSkinOffset(joint);
+ mRootToJointSkinOffset = -mRootToJointSkinOffset;
+
+ //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
+ mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(joint));
+ mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+bool LLAvatarJointMesh::sPipelineRender = false;
+U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
+LLColor4 LLAvatarJointMesh::sClothingInnerColor;
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh()
+//-----------------------------------------------------------------------------
+LLAvatarJointMesh::LLAvatarJointMesh()
+ :
+ mTexture( NULL ),
+ mLayerSet( NULL ),
+ mTestImageName( 0 ),
+ mFaceIndexCount(0)
+{
+
+ mColor[0] = 1.0f;
+ mColor[1] = 1.0f;
+ mColor[2] = 1.0f;
+ mColor[3] = 1.0f;
+ mShiny = 0.0f;
+ mCullBackFaces = true;
+
+ mMesh = NULL;
+
+ mNumSkinJoints = 0;
+ mSkinJoints = NULL;
+
+ mFace = NULL;
+
+ mMeshID = 0;
+ mUpdateXform = false;
+
+ mValid = false;
+
+ mIsTransparent = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLAvatarJointMesh()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLAvatarJointMesh::~LLAvatarJointMesh()
+{
+ mMesh = NULL;
+ mTexture = NULL;
+ freeSkinData();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::allocateSkinData()
+//-----------------------------------------------------------------------------
+bool LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints )
+{
+ mSkinJoints = new LLSkinJoint[ numSkinJoints ];
+ mNumSkinJoints = numSkinJoints;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::freeSkinData()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::freeSkinData()
+{
+ mNumSkinJoints = 0;
+ delete [] mSkinJoints;
+ mSkinJoints = NULL;
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getColor()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
+{
+ *red = mColor[0];
+ *green = mColor[1];
+ *blue = mColor[2];
+ *alpha = mColor[3];
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setColor()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
+{
+ mColor[0] = red;
+ mColor[1] = green;
+ mColor[2] = blue;
+ mColor[3] = alpha;
+}
+
+void LLAvatarJointMesh::setColor( const LLColor4& color )
+{
+ mColor = color;
+}
+
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getTexture()
+//--------------------------------------------------------------------
+//LLViewerTexture *LLAvatarJointMesh::getTexture()
+//{
+// return mTexture;
+//}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setTexture()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setTexture( LLGLTexture *texture )
+{
+ mTexture = texture;
+
+ // texture and dynamic_texture are mutually exclusive
+ if( texture )
+ {
+ mLayerSet = NULL;
+ //texture->bindTexture(0);
+ //texture->setClamp(true, true);
+ }
+}
+
+
+bool LLAvatarJointMesh::hasGLTexture() const
+{
+ return mTexture.notNull() && mTexture->hasGLTexture();
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setLayerSet()
+// Sets the shape texture (takes precedence over normal texture)
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set )
+{
+ mLayerSet = layer_set;
+
+ // texture and dynamic_texture are mutually exclusive
+ if( layer_set )
+ {
+ mTexture = NULL;
+ }
+}
+
+bool LLAvatarJointMesh::hasComposite() const
+{
+ return (mLayerSet && mLayerSet->hasComposite());
+}
+
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getMesh()
+//--------------------------------------------------------------------
+LLPolyMesh *LLAvatarJointMesh::getMesh()
+{
+ return mMesh;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::setMesh()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
+{
+ // set the mesh pointer
+ mMesh = mesh;
+
+ // release any existing skin joints
+ freeSkinData();
+
+ if ( mMesh == NULL )
+ {
+ return;
+ }
+
+ // acquire the transform from the mesh object
+ // SL-315
+ setPosition( mMesh->getPosition() );
+ setRotation( mMesh->getRotation() );
+ setScale( mMesh->getScale() );
+
+ // create skin joints if necessary
+ if ( mMesh->hasWeights() && !mMesh->isLOD())
+ {
+ U32 numJointNames = mMesh->getNumJointNames();
+
+ allocateSkinData( numJointNames );
+ std::string *jointNames = mMesh->getJointNames();
+
+ U32 jn;
+ for (jn = 0; jn < numJointNames; jn++)
+ {
+ //LL_INFOS() << "Setting up joint " << jointNames[jn] << LL_ENDL;
+ LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
+ mSkinJoints[jn].setupSkinJoint( joint );
+ }
+ }
+
+ // setup joint array
+ if (!mMesh->isLOD())
+ {
+ setupJoint((LLAvatarJoint*)getRoot());
+ LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// setupJoint()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
+{
+ U32 sj;
+
+ for (sj=0; sj<mNumSkinJoints; sj++)
+ {
+ LLSkinJoint &js = mSkinJoints[sj];
+
+ if (js.mJoint != current_joint)
+ {
+ continue;
+ }
+
+ // we've found a skinjoint for this joint..
+ LL_DEBUGS("Avatar") << "Mesh: " << getName() << " joint " << current_joint->getName() << " matches skinjoint " << sj << LL_ENDL;
+
+ // is the last joint in the array our parent?
+
+ std::vector<LLJointRenderData*> &jrd = mMesh->mJointRenderData;
+
+ // SL-287 - need to update this so the results are the same if
+ // additional extended-skeleton joints lie between this joint
+ // and the original parent.
+ LLJoint *ancestor = getBaseSkeletonAncestor(current_joint);
+ if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix())
+ {
+ // ...then just add ourselves
+ LLAvatarJoint* jointp = js.mJoint;
+ jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
+ LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
+ }
+ // otherwise add our ancestor and ourselves
+ else
+ {
+ jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL));
+ LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL;
+ jrd.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
+ LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL;
+ }
+ }
+
+ // depth-first traversal
+ for (LLJoint* joint : current_joint->mChildren)
+ {
+ LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
+ setupJoint(child_joint);
+ }
+}
+
+
+// End
diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h
index 0d815643e9..273ca4d52c 100644
--- a/indra/llappearance/llavatarjointmesh.h
+++ b/indra/llappearance/llavatarjointmesh.h
@@ -1,141 +1,141 @@
-/**
- * @file llavatarjointmesh.h
- * @brief Declaration of LLAvatarJointMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLAVATARJOINTMESH_H
-#define LL_LLAVATARJOINTMESH_H
-
-#include "llavatarjoint.h"
-#include "llgltexture.h"
-#include "llpolymesh.h"
-#include "v4color.h"
-
-class LLDrawable;
-class LLFace;
-class LLCharacter;
-class LLTexLayerSet;
-
-typedef enum e_avatar_render_pass
-{
- AVATAR_RENDER_PASS_SINGLE,
- AVATAR_RENDER_PASS_CLOTHING_INNER,
- AVATAR_RENDER_PASS_CLOTHING_OUTER
-} EAvatarRenderPass;
-
-class LLSkinJoint
-{
-public:
- LLSkinJoint();
- ~LLSkinJoint();
- bool setupSkinJoint( LLAvatarJoint *joint);
-
- LLAvatarJoint *mJoint;
- LLVector3 mRootToJointSkinOffset;
- LLVector3 mRootToParentJointSkinOffset;
-};
-
-//-----------------------------------------------------------------------------
-// class LLViewerJointMesh
-//-----------------------------------------------------------------------------
-class LLAvatarJointMesh : public virtual LLAvatarJoint
-{
-protected:
- LLColor4 mColor; // color value
-// LLColor4 mSpecular; // specular color (always white for now)
- F32 mShiny; // shiny value
- LLPointer<LLGLTexture> mTexture; // ptr to a global texture
- LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar
- U32 mTestImageName; // handle to a temporary texture for previewing uploads
- LLPolyMesh* mMesh; // ptr to a global polymesh
- bool mCullBackFaces; // true by default
- LLFace* mFace; // ptr to a face w/ AGP copy of mesh
-
- U32 mFaceIndexCount;
-
- U32 mNumSkinJoints;
- LLSkinJoint* mSkinJoints;
- S32 mMeshID;
-
-public:
- static bool sPipelineRender;
- //RN: this is here for testing purposes
- static U32 sClothingMaskImageName;
- static LLColor4 sClothingInnerColor;
-
-public:
- // Constructor
- LLAvatarJointMesh();
-
- // Destructor
- virtual ~LLAvatarJointMesh();
-
- // Gets the shape color
- void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
-
- // Sets the shape color
- void setColor( F32 red, F32 green, F32 blue, F32 alpha );
- void setColor( const LLColor4& color );
-
- // Sets the shininess
- void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
-
- // Sets the shape texture
- void setTexture( LLGLTexture *texture );
-
- bool hasGLTexture() const;
-
- void setTestTexture( U32 name ) { mTestImageName = name; }
-
- // Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
- void setLayerSet( LLTexLayerSet* layer_set );
-
- bool hasComposite() const;
-
- // Gets the poly mesh
- LLPolyMesh *getMesh();
-
- // Sets the poly mesh
- void setMesh( LLPolyMesh *mesh );
-
- // Sets up joint matrix data for rendering
- void setupJoint(LLAvatarJoint* current_joint);
-
- // Sets ID for picking
- void setMeshID( S32 id ) {mMeshID = id;}
-
- // Gets ID for picking
- S32 getMeshID() { return mMeshID; }
-
- void setIsTransparent(bool is_transparent) { mIsTransparent = is_transparent; }
-
-private:
- // Allocate skin data
- bool allocateSkinData( U32 numSkinJoints );
-
- // Free skin data
- void freeSkinData();
-};
-
-#endif // LL_LLAVATARJOINTMESH_H
+/**
+ * @file llavatarjointmesh.h
+ * @brief Declaration of LLAvatarJointMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAVATARJOINTMESH_H
+#define LL_LLAVATARJOINTMESH_H
+
+#include "llavatarjoint.h"
+#include "llgltexture.h"
+#include "llpolymesh.h"
+#include "v4color.h"
+
+class LLDrawable;
+class LLFace;
+class LLCharacter;
+class LLTexLayerSet;
+
+typedef enum e_avatar_render_pass
+{
+ AVATAR_RENDER_PASS_SINGLE,
+ AVATAR_RENDER_PASS_CLOTHING_INNER,
+ AVATAR_RENDER_PASS_CLOTHING_OUTER
+} EAvatarRenderPass;
+
+class LLSkinJoint
+{
+public:
+ LLSkinJoint();
+ ~LLSkinJoint();
+ bool setupSkinJoint( LLAvatarJoint *joint);
+
+ LLAvatarJoint *mJoint;
+ LLVector3 mRootToJointSkinOffset;
+ LLVector3 mRootToParentJointSkinOffset;
+};
+
+//-----------------------------------------------------------------------------
+// class LLViewerJointMesh
+//-----------------------------------------------------------------------------
+class LLAvatarJointMesh : public virtual LLAvatarJoint
+{
+protected:
+ LLColor4 mColor; // color value
+// LLColor4 mSpecular; // specular color (always white for now)
+ F32 mShiny; // shiny value
+ LLPointer<LLGLTexture> mTexture; // ptr to a global texture
+ LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar
+ U32 mTestImageName; // handle to a temporary texture for previewing uploads
+ LLPolyMesh* mMesh; // ptr to a global polymesh
+ bool mCullBackFaces; // true by default
+ LLFace* mFace; // ptr to a face w/ AGP copy of mesh
+
+ U32 mFaceIndexCount;
+
+ U32 mNumSkinJoints;
+ LLSkinJoint* mSkinJoints;
+ S32 mMeshID;
+
+public:
+ static bool sPipelineRender;
+ //RN: this is here for testing purposes
+ static U32 sClothingMaskImageName;
+ static LLColor4 sClothingInnerColor;
+
+public:
+ // Constructor
+ LLAvatarJointMesh();
+
+ // Destructor
+ virtual ~LLAvatarJointMesh();
+
+ // Gets the shape color
+ void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
+
+ // Sets the shape color
+ void setColor( F32 red, F32 green, F32 blue, F32 alpha );
+ void setColor( const LLColor4& color );
+
+ // Sets the shininess
+ void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
+
+ // Sets the shape texture
+ void setTexture( LLGLTexture *texture );
+
+ bool hasGLTexture() const;
+
+ void setTestTexture( U32 name ) { mTestImageName = name; }
+
+ // Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
+ void setLayerSet( LLTexLayerSet* layer_set );
+
+ bool hasComposite() const;
+
+ // Gets the poly mesh
+ LLPolyMesh *getMesh();
+
+ // Sets the poly mesh
+ void setMesh( LLPolyMesh *mesh );
+
+ // Sets up joint matrix data for rendering
+ void setupJoint(LLAvatarJoint* current_joint);
+
+ // Sets ID for picking
+ void setMeshID( S32 id ) {mMeshID = id;}
+
+ // Gets ID for picking
+ S32 getMeshID() { return mMeshID; }
+
+ void setIsTransparent(bool is_transparent) { mIsTransparent = is_transparent; }
+
+private:
+ // Allocate skin data
+ bool allocateSkinData( U32 numSkinJoints );
+
+ // Free skin data
+ void freeSkinData();
+};
+
+#endif // LL_LLAVATARJOINTMESH_H
diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
index e832176ae8..c8c50b90a6 100644
--- a/indra/llappearance/lldriverparam.cpp
+++ b/indra/llappearance/lldriverparam.cpp
@@ -1,622 +1,622 @@
-/**
- * @file lldriverparam.cpp
- * @brief A visual parameter that drives (controls) other visual parameters.
- *
- * $LicenseInfo:firstyear=2002&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 "lldriverparam.h"
-
-#include "llavatarappearance.h"
-#include "llwearable.h"
-#include "llwearabledata.h"
-
-//-----------------------------------------------------------------------------
-// LLDriverParamInfo
-//-----------------------------------------------------------------------------
-
-LLDriverParamInfo::LLDriverParamInfo() :
- mDriverParam(NULL)
-{
-}
-
-bool LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
-
- if( !LLViewerVisualParamInfo::parseXml( node ))
- return false;
-
- LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
- if( !param_driver_node )
- return false;
-
- for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
- child;
- child = param_driver_node->getNextNamedChild())
- {
- S32 driven_id;
- static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
- if( child->getFastAttributeS32( id_string, driven_id ) )
- {
- F32 min1 = mMinWeight;
- F32 max1 = mMaxWeight;
- F32 max2 = max1;
- F32 min2 = max1;
-
- // driven ________ //
- // ^ /| |\ //
- // | / | | \ //
- // | / | | \ //
- // | / | | \ //
- // | / | | \ //
- //-------|----|-------|----|-------> driver //
- // | min1 max1 max2 min2
-
- static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
- child->getFastAttributeF32( min1_string, min1 ); // optional
- static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
- child->getFastAttributeF32( max1_string, max1 ); // optional
- static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
- child->getFastAttributeF32( max2_string, max2 ); // optional
- static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
- child->getFastAttributeF32( min2_string, min2 ); // optional
-
- // Push these on the front of the deque, so that we can construct
- // them in order later (faster)
- mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
- }
- else
- {
- LL_ERRS() << "<driven> Unable to resolve driven parameter: " << driven_id << LL_ENDL;
- return false;
- }
- }
- return true;
-}
-
-//virtual
-void LLDriverParamInfo::toStream(std::ostream &out)
-{
- LLViewerVisualParamInfo::toStream(out);
- out << "driver" << "\t";
- out << mDrivenInfoList.size() << "\t";
- for (LLDrivenEntryInfo& driven : mDrivenInfoList)
- {
- out << driven.mDrivenID << "\t";
- }
-
- out << std::endl;
-
- // FIXME - this mDriverParam backlink makes no sense, because the
- // LLDriverParamInfos are static objects - there's only one copy
- // for each param type, so the backlink will just reference the
- // corresponding param in the most recently created
- // avatar. Apparently these toStream() methods are not currently
- // used anywhere, so it's not an urgent problem.
- LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL;
-
- if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
- mDriverParam->getAvatarAppearance()->isValid())
- {
- for (LLDrivenEntryInfo& driven : mDrivenInfoList)
- {
- LLViewerVisualParam *param =
- (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
- if (param)
- {
- param->getInfo()->toStream(out);
- if (param->getWearableType() != mWearableType)
- {
- if(param->getCrossWearable())
- {
- out << "cross-wearable" << "\t";
- }
- else
- {
- out << "ERROR!" << "\t";
- }
- }
- else
- {
- out << "valid" << "\t";
- }
- }
- else
- {
- LL_WARNS() << "could not get parameter " << driven.mDrivenID << " from avatar "
- << mDriverParam->getAvatarAppearance()
- << " for driver parameter " << getID() << LL_ENDL;
- }
- out << std::endl;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLDriverParam
-//-----------------------------------------------------------------------------
-
-LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */)
- : LLViewerVisualParam(),
- mDefaultVec(),
- mDriven(),
- mCurrentDistortionParam( NULL ),
- mAvatarAppearance(appearance),
- mWearablep(wearable)
-{
- llassert(mAvatarAppearance);
- llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
- mDefaultVec.clear();
-}
-
-LLDriverParam::LLDriverParam(const LLDriverParam& pOther)
- : LLViewerVisualParam(pOther),
- mDefaultVec(pOther.mDefaultVec),
- mDriven(pOther.mDriven),
- mCurrentDistortionParam(pOther.mCurrentDistortionParam),
- mAvatarAppearance(pOther.mAvatarAppearance),
- mWearablep(pOther.mWearablep)
-{
- llassert(mAvatarAppearance);
- llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
-}
-
-LLDriverParam::~LLDriverParam()
-{
-}
-
-bool LLDriverParam::setInfo(LLDriverParamInfo *info)
-{
- llassert(mInfo == NULL);
- if (info->mID < 0)
- return false;
- mInfo = info;
- mID = info->mID;
- info->mDriverParam = this;
-
- setWeight(getDefaultWeight());
-
- return true;
-}
-
-/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
-{
- llassert(wearable);
- return new LLDriverParam(*this);
-}
-
-void LLDriverParam::setWeight(F32 weight)
-{
- F32 min_weight = getMinWeight();
- F32 max_weight = getMaxWeight();
- if (mIsAnimating)
- {
- // allow overshoot when animating
- mCurWeight = weight;
- }
- else
- {
- mCurWeight = llclamp(weight, min_weight, max_weight);
- }
-
- // driven ________
- // ^ /| |\ ^
- // | / | | \ |
- // | / | | \ |
- // | / | | \ |
- // | / | | \ |
- //-------|----|-------|----|-------> driver
- // | min1 max1 max2 min2
-
- for(LLDrivenEntry& driven : mDriven)
- {
- LLDrivenEntry* drivenp = &driven;
- LLDrivenEntryInfo* info = drivenp->mInfo;
-
- F32 driven_weight = 0.f;
- F32 driven_min = drivenp->mParam->getMinWeight();
- F32 driven_max = drivenp->mParam->getMaxWeight();
-
- if (mIsAnimating)
- {
- // driven param doesn't interpolate (textures, for example)
- if (!drivenp->mParam->getAnimating())
- {
- continue;
- }
- if( mCurWeight < info->mMin1 )
- {
- if (info->mMin1 == min_weight)
- {
- if (info->mMin1 == info->mMax1)
- {
- driven_weight = driven_max;
- }
- else
- {
- //up slope extrapolation
- F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
- driven_weight = driven_min + t * (driven_max - driven_min);
- }
- }
- else
- {
- driven_weight = driven_min;
- }
-
- setDrivenWeight(drivenp,driven_weight);
- continue;
- }
- else
- if ( mCurWeight > info->mMin2 )
- {
- if (info->mMin2 == max_weight)
- {
- if (info->mMin2 == info->mMax2)
- {
- driven_weight = driven_max;
- }
- else
- {
- //down slope extrapolation
- F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
- driven_weight = driven_max + t * (driven_min - driven_max);
- }
- }
- else
- {
- driven_weight = driven_min;
- }
-
- setDrivenWeight(drivenp,driven_weight);
- continue;
- }
- }
-
- driven_weight = getDrivenWeight(drivenp, mCurWeight);
- setDrivenWeight(drivenp,driven_weight);
- }
-}
-
-F32 LLDriverParam::getTotalDistortion()
-{
- F32 sum = 0.f;
- for(LLDrivenEntry& driven : mDriven)
- {
- sum += driven.mParam->getTotalDistortion();
- }
-
- return sum;
-}
-
-const LLVector4a &LLDriverParam::getAvgDistortion()
-{
- // It's not actually correct to take the average of averages, but it good enough here.
- LLVector4a sum;
- sum.clear();
- S32 count = 0;
- for(LLDrivenEntry& driven : mDriven)
- {
- sum.add(driven.mParam->getAvgDistortion());
- count++;
- }
- sum.mul( 1.f/(F32)count);
-
- mDefaultVec = sum;
- return mDefaultVec;
-}
-
-F32 LLDriverParam::getMaxDistortion()
-{
- F32 max = 0.f;
- for(LLDrivenEntry& driven : mDriven)
- {
- F32 param_max = driven.mParam->getMaxDistortion();
- if( param_max > max )
- {
- max = param_max;
- }
- }
-
- return max;
-}
-
-
-LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
-{
- LLVector4a sum;
- sum.clear();
- for(LLDrivenEntry& driven : mDriven)
- {
- sum.add(driven.mParam->getVertexDistortion(index, poly_mesh));
- }
- return sum;
-}
-
-const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
-{
- mCurrentDistortionParam = NULL;
- const LLVector4a* v = NULL;
- for(LLDrivenEntry& driven : mDriven)
- {
- v = driven.mParam->getFirstDistortion(index, poly_mesh);
- if( v )
- {
- mCurrentDistortionParam = driven.mParam;
- break;
- }
- }
-
- return v;
-};
-
-const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
-{
- llassert( mCurrentDistortionParam );
- if( !mCurrentDistortionParam )
- {
- return NULL;
- }
-
- LLDrivenEntry* driven = NULL;
- entry_list_t::iterator iter;
-
- // Set mDriven iteration to the right point
- for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
- {
- driven = &(*iter);
- if( driven->mParam == mCurrentDistortionParam )
- {
- break;
- }
- }
-
- llassert(driven);
- if (!driven)
- {
- return NULL; // shouldn't happen, but...
- }
-
- // We're already in the middle of a param's distortions, so get the next one.
- const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh );
- if( (!v) && (iter != mDriven.end()) )
- {
- // This param is finished, so start the next param. It might not have any
- // distortions, though, so we have to loop to find the next param that does.
- for( iter++; iter != mDriven.end(); iter++ )
- {
- driven = &(*iter);
- v = driven->mParam->getFirstDistortion(index, poly_mesh);
- if( v )
- {
- mCurrentDistortionParam = driven->mParam;
- break;
- }
- }
- }
-
- return v;
-};
-
-S32 LLDriverParam::getDrivenParamsCount() const
-{
- return mDriven.size();
-}
-
-const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
-{
- if (0 > index || index >= mDriven.size())
- {
- return NULL;
- }
- return mDriven[index].mParam;
-}
-
-//-----------------------------------------------------------------------------
-// setAnimationTarget()
-//-----------------------------------------------------------------------------
-void LLDriverParam::setAnimationTarget( F32 target_value)
-{
- LLVisualParam::setAnimationTarget(target_value);
-
- for(LLDrivenEntry& driven : mDriven)
- {
- LLDrivenEntry* drivenp = &driven;
- F32 driven_weight = getDrivenWeight(drivenp, mTargetWeight);
-
- // this isn't normally necessary, as driver params handle interpolation of their driven params
- // but texture params need to know to assume their final value at beginning of interpolation
- drivenp->mParam->setAnimationTarget(driven_weight);
- }
-}
-
-//-----------------------------------------------------------------------------
-// stopAnimating()
-//-----------------------------------------------------------------------------
-void LLDriverParam::stopAnimating()
-{
- LLVisualParam::stopAnimating();
-
- for(LLDrivenEntry& driven : mDriven)
- {
- driven.mParam->setAnimating(false);
- }
-}
-
-/*virtual*/
-bool LLDriverParam::linkDrivenParams(visual_param_mapper mapper, bool only_cross_params)
-{
- bool success = true;
- for (LLDrivenEntryInfo& driven_info : getInfo()->mDrivenInfoList)
- {
- S32 driven_id = driven_info.mDrivenID;
-
- // check for already existing links. Do not overwrite.
- bool found = false;
- for (auto& driven : mDriven)
- {
- if (driven.mInfo->mDrivenID == driven_id)
- {
- found = true;
- }
- }
-
- if (!found)
- {
- LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
- if (param) param->setParamLocation(this->getParamLocation());
- bool push = param && (!only_cross_params || param->getCrossWearable());
- if (push)
- {
- mDriven.push_back(LLDrivenEntry( param, &driven_info ));
- }
- else
- {
- success = false;
- }
- }
- }
-
- return success;
-}
-
-void LLDriverParam::resetDrivenParams()
-{
- mDriven.clear();
- mDriven.reserve(getInfo()->mDrivenInfoList.size());
-}
-
-void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
-{
- bool needs_update = (getWearableType()==driven_type);
-
- // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
- for(LLDrivenEntry& driven : mDriven)
- {
- if (driven.mParam && driven.mParam->getCrossWearable() && driven.mParam->getWearableType() == driven_type)
- {
- needs_update = true;
- }
- }
-
-
- if (needs_update)
- {
- LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
-
- // If we've gotten here, we've added a new wearable of type "type"
- // Thus this wearable needs to get updates from the driver wearable.
- // The call to setVisualParamWeight seems redundant, but is necessary
- // as the number of driven wearables has changed since the last update. -Nyx
- LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
- if (wearable)
- {
- wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// getDrivenWeight()
-//-----------------------------------------------------------------------------
-F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
-{
- F32 min_weight = getMinWeight();
- F32 max_weight = getMaxWeight();
- const LLDrivenEntryInfo* info = driven->mInfo;
-
- F32 driven_weight = 0.f;
- F32 driven_min = driven->mParam->getMinWeight();
- F32 driven_max = driven->mParam->getMaxWeight();
-
- if( input_weight <= info->mMin1 )
- {
- if( info->mMin1 == info->mMax1 &&
- info->mMin1 <= min_weight)
- {
- driven_weight = driven_max;
- }
- else
- {
- driven_weight = driven_min;
- }
- }
- else
- if( input_weight <= info->mMax1 )
- {
- F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
- driven_weight = driven_min + t * (driven_max - driven_min);
- }
- else
- if( input_weight <= info->mMax2 )
- {
- driven_weight = driven_max;
- }
- else
- if( input_weight <= info->mMin2 )
- {
- F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
- driven_weight = driven_max + t * (driven_min - driven_max);
- }
- else
- {
- if (info->mMax2 >= max_weight)
- {
- driven_weight = driven_max;
- }
- else
- {
- driven_weight = driven_min;
- }
- }
-
- return driven_weight;
-}
-
-void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
-{
- bool use_self = false;
- if(mWearablep &&
- mAvatarAppearance->isValid() &&
- driven->mParam->getCrossWearable())
- {
- LLWearable* wearable = mWearablep;
- if (mAvatarAppearance->getWearableData()->isOnTop(wearable))
- {
- use_self = true;
- }
- }
-
- if (use_self)
- {
- // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
- mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
- }
- else
- {
- driven->mParam->setWeight( driven_weight);
- }
-}
+/**
+ * @file lldriverparam.cpp
+ * @brief A visual parameter that drives (controls) other visual parameters.
+ *
+ * $LicenseInfo:firstyear=2002&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 "lldriverparam.h"
+
+#include "llavatarappearance.h"
+#include "llwearable.h"
+#include "llwearabledata.h"
+
+//-----------------------------------------------------------------------------
+// LLDriverParamInfo
+//-----------------------------------------------------------------------------
+
+LLDriverParamInfo::LLDriverParamInfo() :
+ mDriverParam(NULL)
+{
+}
+
+bool LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
+
+ if( !LLViewerVisualParamInfo::parseXml( node ))
+ return false;
+
+ LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
+ if( !param_driver_node )
+ return false;
+
+ for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
+ child;
+ child = param_driver_node->getNextNamedChild())
+ {
+ S32 driven_id;
+ static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+ if( child->getFastAttributeS32( id_string, driven_id ) )
+ {
+ F32 min1 = mMinWeight;
+ F32 max1 = mMaxWeight;
+ F32 max2 = max1;
+ F32 min2 = max1;
+
+ // driven ________ //
+ // ^ /| |\ //
+ // | / | | \ //
+ // | / | | \ //
+ // | / | | \ //
+ // | / | | \ //
+ //-------|----|-------|----|-------> driver //
+ // | min1 max1 max2 min2
+
+ static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
+ child->getFastAttributeF32( min1_string, min1 ); // optional
+ static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
+ child->getFastAttributeF32( max1_string, max1 ); // optional
+ static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
+ child->getFastAttributeF32( max2_string, max2 ); // optional
+ static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
+ child->getFastAttributeF32( min2_string, min2 ); // optional
+
+ // Push these on the front of the deque, so that we can construct
+ // them in order later (faster)
+ mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
+ }
+ else
+ {
+ LL_ERRS() << "<driven> Unable to resolve driven parameter: " << driven_id << LL_ENDL;
+ return false;
+ }
+ }
+ return true;
+}
+
+//virtual
+void LLDriverParamInfo::toStream(std::ostream &out)
+{
+ LLViewerVisualParamInfo::toStream(out);
+ out << "driver" << "\t";
+ out << mDrivenInfoList.size() << "\t";
+ for (LLDrivenEntryInfo& driven : mDrivenInfoList)
+ {
+ out << driven.mDrivenID << "\t";
+ }
+
+ out << std::endl;
+
+ // FIXME - this mDriverParam backlink makes no sense, because the
+ // LLDriverParamInfos are static objects - there's only one copy
+ // for each param type, so the backlink will just reference the
+ // corresponding param in the most recently created
+ // avatar. Apparently these toStream() methods are not currently
+ // used anywhere, so it's not an urgent problem.
+ LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL;
+
+ if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
+ mDriverParam->getAvatarAppearance()->isValid())
+ {
+ for (LLDrivenEntryInfo& driven : mDrivenInfoList)
+ {
+ LLViewerVisualParam *param =
+ (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
+ if (param)
+ {
+ param->getInfo()->toStream(out);
+ if (param->getWearableType() != mWearableType)
+ {
+ if(param->getCrossWearable())
+ {
+ out << "cross-wearable" << "\t";
+ }
+ else
+ {
+ out << "ERROR!" << "\t";
+ }
+ }
+ else
+ {
+ out << "valid" << "\t";
+ }
+ }
+ else
+ {
+ LL_WARNS() << "could not get parameter " << driven.mDrivenID << " from avatar "
+ << mDriverParam->getAvatarAppearance()
+ << " for driver parameter " << getID() << LL_ENDL;
+ }
+ out << std::endl;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLDriverParam
+//-----------------------------------------------------------------------------
+
+LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */)
+ : LLViewerVisualParam(),
+ mDefaultVec(),
+ mDriven(),
+ mCurrentDistortionParam( NULL ),
+ mAvatarAppearance(appearance),
+ mWearablep(wearable)
+{
+ llassert(mAvatarAppearance);
+ llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
+ mDefaultVec.clear();
+}
+
+LLDriverParam::LLDriverParam(const LLDriverParam& pOther)
+ : LLViewerVisualParam(pOther),
+ mDefaultVec(pOther.mDefaultVec),
+ mDriven(pOther.mDriven),
+ mCurrentDistortionParam(pOther.mCurrentDistortionParam),
+ mAvatarAppearance(pOther.mAvatarAppearance),
+ mWearablep(pOther.mWearablep)
+{
+ llassert(mAvatarAppearance);
+ llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
+}
+
+LLDriverParam::~LLDriverParam()
+{
+}
+
+bool LLDriverParam::setInfo(LLDriverParamInfo *info)
+{
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return false;
+ mInfo = info;
+ mID = info->mID;
+ info->mDriverParam = this;
+
+ setWeight(getDefaultWeight());
+
+ return true;
+}
+
+/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
+{
+ llassert(wearable);
+ return new LLDriverParam(*this);
+}
+
+void LLDriverParam::setWeight(F32 weight)
+{
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ if (mIsAnimating)
+ {
+ // allow overshoot when animating
+ mCurWeight = weight;
+ }
+ else
+ {
+ mCurWeight = llclamp(weight, min_weight, max_weight);
+ }
+
+ // driven ________
+ // ^ /| |\ ^
+ // | / | | \ |
+ // | / | | \ |
+ // | / | | \ |
+ // | / | | \ |
+ //-------|----|-------|----|-------> driver
+ // | min1 max1 max2 min2
+
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ LLDrivenEntry* drivenp = &driven;
+ LLDrivenEntryInfo* info = drivenp->mInfo;
+
+ F32 driven_weight = 0.f;
+ F32 driven_min = drivenp->mParam->getMinWeight();
+ F32 driven_max = drivenp->mParam->getMaxWeight();
+
+ if (mIsAnimating)
+ {
+ // driven param doesn't interpolate (textures, for example)
+ if (!drivenp->mParam->getAnimating())
+ {
+ continue;
+ }
+ if( mCurWeight < info->mMin1 )
+ {
+ if (info->mMin1 == min_weight)
+ {
+ if (info->mMin1 == info->mMax1)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ //up slope extrapolation
+ F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
+ driven_weight = driven_min + t * (driven_max - driven_min);
+ }
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+
+ setDrivenWeight(drivenp,driven_weight);
+ continue;
+ }
+ else
+ if ( mCurWeight > info->mMin2 )
+ {
+ if (info->mMin2 == max_weight)
+ {
+ if (info->mMin2 == info->mMax2)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ //down slope extrapolation
+ F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
+ driven_weight = driven_max + t * (driven_min - driven_max);
+ }
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+
+ setDrivenWeight(drivenp,driven_weight);
+ continue;
+ }
+ }
+
+ driven_weight = getDrivenWeight(drivenp, mCurWeight);
+ setDrivenWeight(drivenp,driven_weight);
+ }
+}
+
+F32 LLDriverParam::getTotalDistortion()
+{
+ F32 sum = 0.f;
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ sum += driven.mParam->getTotalDistortion();
+ }
+
+ return sum;
+}
+
+const LLVector4a &LLDriverParam::getAvgDistortion()
+{
+ // It's not actually correct to take the average of averages, but it good enough here.
+ LLVector4a sum;
+ sum.clear();
+ S32 count = 0;
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ sum.add(driven.mParam->getAvgDistortion());
+ count++;
+ }
+ sum.mul( 1.f/(F32)count);
+
+ mDefaultVec = sum;
+ return mDefaultVec;
+}
+
+F32 LLDriverParam::getMaxDistortion()
+{
+ F32 max = 0.f;
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ F32 param_max = driven.mParam->getMaxDistortion();
+ if( param_max > max )
+ {
+ max = param_max;
+ }
+ }
+
+ return max;
+}
+
+
+LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
+{
+ LLVector4a sum;
+ sum.clear();
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ sum.add(driven.mParam->getVertexDistortion(index, poly_mesh));
+ }
+ return sum;
+}
+
+const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ mCurrentDistortionParam = NULL;
+ const LLVector4a* v = NULL;
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ v = driven.mParam->getFirstDistortion(index, poly_mesh);
+ if( v )
+ {
+ mCurrentDistortionParam = driven.mParam;
+ break;
+ }
+ }
+
+ return v;
+};
+
+const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ llassert( mCurrentDistortionParam );
+ if( !mCurrentDistortionParam )
+ {
+ return NULL;
+ }
+
+ LLDrivenEntry* driven = NULL;
+ entry_list_t::iterator iter;
+
+ // Set mDriven iteration to the right point
+ for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ {
+ driven = &(*iter);
+ if( driven->mParam == mCurrentDistortionParam )
+ {
+ break;
+ }
+ }
+
+ llassert(driven);
+ if (!driven)
+ {
+ return NULL; // shouldn't happen, but...
+ }
+
+ // We're already in the middle of a param's distortions, so get the next one.
+ const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh );
+ if( (!v) && (iter != mDriven.end()) )
+ {
+ // This param is finished, so start the next param. It might not have any
+ // distortions, though, so we have to loop to find the next param that does.
+ for( iter++; iter != mDriven.end(); iter++ )
+ {
+ driven = &(*iter);
+ v = driven->mParam->getFirstDistortion(index, poly_mesh);
+ if( v )
+ {
+ mCurrentDistortionParam = driven->mParam;
+ break;
+ }
+ }
+ }
+
+ return v;
+};
+
+S32 LLDriverParam::getDrivenParamsCount() const
+{
+ return mDriven.size();
+}
+
+const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
+{
+ if (0 > index || index >= mDriven.size())
+ {
+ return NULL;
+ }
+ return mDriven[index].mParam;
+}
+
+//-----------------------------------------------------------------------------
+// setAnimationTarget()
+//-----------------------------------------------------------------------------
+void LLDriverParam::setAnimationTarget( F32 target_value)
+{
+ LLVisualParam::setAnimationTarget(target_value);
+
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ LLDrivenEntry* drivenp = &driven;
+ F32 driven_weight = getDrivenWeight(drivenp, mTargetWeight);
+
+ // this isn't normally necessary, as driver params handle interpolation of their driven params
+ // but texture params need to know to assume their final value at beginning of interpolation
+ drivenp->mParam->setAnimationTarget(driven_weight);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// stopAnimating()
+//-----------------------------------------------------------------------------
+void LLDriverParam::stopAnimating()
+{
+ LLVisualParam::stopAnimating();
+
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ driven.mParam->setAnimating(false);
+ }
+}
+
+/*virtual*/
+bool LLDriverParam::linkDrivenParams(visual_param_mapper mapper, bool only_cross_params)
+{
+ bool success = true;
+ for (LLDrivenEntryInfo& driven_info : getInfo()->mDrivenInfoList)
+ {
+ S32 driven_id = driven_info.mDrivenID;
+
+ // check for already existing links. Do not overwrite.
+ bool found = false;
+ for (auto& driven : mDriven)
+ {
+ if (driven.mInfo->mDrivenID == driven_id)
+ {
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
+ if (param) param->setParamLocation(this->getParamLocation());
+ bool push = param && (!only_cross_params || param->getCrossWearable());
+ if (push)
+ {
+ mDriven.push_back(LLDrivenEntry( param, &driven_info ));
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ }
+
+ return success;
+}
+
+void LLDriverParam::resetDrivenParams()
+{
+ mDriven.clear();
+ mDriven.reserve(getInfo()->mDrivenInfoList.size());
+}
+
+void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
+{
+ bool needs_update = (getWearableType()==driven_type);
+
+ // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
+ for(LLDrivenEntry& driven : mDriven)
+ {
+ if (driven.mParam && driven.mParam->getCrossWearable() && driven.mParam->getWearableType() == driven_type)
+ {
+ needs_update = true;
+ }
+ }
+
+
+ if (needs_update)
+ {
+ LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
+
+ // If we've gotten here, we've added a new wearable of type "type"
+ // Thus this wearable needs to get updates from the driver wearable.
+ // The call to setVisualParamWeight seems redundant, but is necessary
+ // as the number of driven wearables has changed since the last update. -Nyx
+ LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
+ if (wearable)
+ {
+ wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// getDrivenWeight()
+//-----------------------------------------------------------------------------
+F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
+{
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ const LLDrivenEntryInfo* info = driven->mInfo;
+
+ F32 driven_weight = 0.f;
+ F32 driven_min = driven->mParam->getMinWeight();
+ F32 driven_max = driven->mParam->getMaxWeight();
+
+ if( input_weight <= info->mMin1 )
+ {
+ if( info->mMin1 == info->mMax1 &&
+ info->mMin1 <= min_weight)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+ }
+ else
+ if( input_weight <= info->mMax1 )
+ {
+ F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
+ driven_weight = driven_min + t * (driven_max - driven_min);
+ }
+ else
+ if( input_weight <= info->mMax2 )
+ {
+ driven_weight = driven_max;
+ }
+ else
+ if( input_weight <= info->mMin2 )
+ {
+ F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
+ driven_weight = driven_max + t * (driven_min - driven_max);
+ }
+ else
+ {
+ if (info->mMax2 >= max_weight)
+ {
+ driven_weight = driven_max;
+ }
+ else
+ {
+ driven_weight = driven_min;
+ }
+ }
+
+ return driven_weight;
+}
+
+void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
+{
+ bool use_self = false;
+ if(mWearablep &&
+ mAvatarAppearance->isValid() &&
+ driven->mParam->getCrossWearable())
+ {
+ LLWearable* wearable = mWearablep;
+ if (mAvatarAppearance->getWearableData()->isOnTop(wearable))
+ {
+ use_self = true;
+ }
+ }
+
+ if (use_self)
+ {
+ // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
+ mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
+ }
+ else
+ {
+ driven->mParam->setWeight( driven_weight);
+ }
+}
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index 610cd8c5e5..52f088f2d2 100644
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -1,139 +1,139 @@
-/**
- * @file lldriverparam.h
- * @brief A visual parameter that drives (controls) other visual parameters.
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#ifndef LL_LLDRIVERPARAM_H
-#define LL_LLDRIVERPARAM_H
-
-#include "llviewervisualparam.h"
-#include "llwearabletype.h"
-#include <deque>
-
-class LLAvatarAppearance;
-class LLDriverParam;
-class LLWearable;
-
-//-----------------------------------------------------------------------------
-
-struct LLDrivenEntryInfo
-{
- LLDrivenEntryInfo( S32 id, F32 min1, F32 max1, F32 max2, F32 min2 )
- : mDrivenID( id ), mMin1( min1 ), mMax1( max1 ), mMax2( max2 ), mMin2( min2 ) {}
- S32 mDrivenID;
- F32 mMin1;
- F32 mMax1;
- F32 mMax2;
- F32 mMin2;
-};
-
-struct LLDrivenEntry
-{
- LLDrivenEntry( LLViewerVisualParam* param, LLDrivenEntryInfo *info )
- : mParam( param ), mInfo( info ) {}
- LLViewerVisualParam* mParam;
- LLDrivenEntryInfo* mInfo;
-};
-
-//-----------------------------------------------------------------------------
-
-class LLDriverParamInfo : public LLViewerVisualParamInfo
-{
- friend class LLDriverParam;
-public:
- LLDriverParamInfo();
- /*virtual*/ ~LLDriverParamInfo() {};
-
- /*virtual*/ bool parseXml(LLXmlTreeNode* node);
-
- /*virtual*/ void toStream(std::ostream &out);
-
-protected:
- typedef std::deque<LLDrivenEntryInfo> entry_info_list_t;
- entry_info_list_t mDrivenInfoList;
- LLDriverParam* mDriverParam; // backpointer
-};
-
-//-----------------------------------------------------------------------------
-
-class alignas(16) LLDriverParam : public LLViewerVisualParam
-{
- LL_ALIGN_NEW
-private:
- // Hide the default constructor. Force construction with LLAvatarAppearance.
- LLDriverParam() {}
-public:
- LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
- ~LLDriverParam();
-
- // Special: These functions are overridden by child classes
- LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
- // This sets mInfo and calls initialization functions
- bool setInfo(LLDriverParamInfo* info);
-
- LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
- const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
-
- void updateCrossDrivenParams(LLWearableType::EType driven_type);
-
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
- // LLVisualParam Virtual functions
- /*virtual*/ void apply(ESex sex) {} // apply is called separately for each driven param.
- /*virtual*/ void setWeight(F32 weight);
- /*virtual*/ void setAnimationTarget(F32 target_value);
- /*virtual*/ void stopAnimating();
- /*virtual*/ bool linkDrivenParams(visual_param_mapper mapper, bool only_cross_params);
- /*virtual*/ void resetDrivenParams();
-
- // LLViewerVisualParam Virtual functions
- /*virtual*/ F32 getTotalDistortion();
- /*virtual*/ const LLVector4a& getAvgDistortion();
- /*virtual*/ F32 getMaxDistortion();
- /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
- /*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
- /*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
-
- S32 getDrivenParamsCount() const;
- const LLViewerVisualParam* getDrivenParam(S32 index) const;
-
- typedef std::vector<LLDrivenEntry> entry_list_t;
- entry_list_t& getDrivenList() { return mDriven; }
- void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
-
-protected:
- LLDriverParam(const LLDriverParam& pOther);
- F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
- void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
-
-
- LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
- entry_list_t mDriven;
- LLViewerVisualParam* mCurrentDistortionParam;
- // Backlink only; don't make this an LLPointer.
- LLAvatarAppearance* mAvatarAppearance;
- LLWearable* mWearablep;
-};
-
-#endif // LL_LLDRIVERPARAM_H
+/**
+ * @file lldriverparam.h
+ * @brief A visual parameter that drives (controls) other visual parameters.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLDRIVERPARAM_H
+#define LL_LLDRIVERPARAM_H
+
+#include "llviewervisualparam.h"
+#include "llwearabletype.h"
+#include <deque>
+
+class LLAvatarAppearance;
+class LLDriverParam;
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+
+struct LLDrivenEntryInfo
+{
+ LLDrivenEntryInfo( S32 id, F32 min1, F32 max1, F32 max2, F32 min2 )
+ : mDrivenID( id ), mMin1( min1 ), mMax1( max1 ), mMax2( max2 ), mMin2( min2 ) {}
+ S32 mDrivenID;
+ F32 mMin1;
+ F32 mMax1;
+ F32 mMax2;
+ F32 mMin2;
+};
+
+struct LLDrivenEntry
+{
+ LLDrivenEntry( LLViewerVisualParam* param, LLDrivenEntryInfo *info )
+ : mParam( param ), mInfo( info ) {}
+ LLViewerVisualParam* mParam;
+ LLDrivenEntryInfo* mInfo;
+};
+
+//-----------------------------------------------------------------------------
+
+class LLDriverParamInfo : public LLViewerVisualParamInfo
+{
+ friend class LLDriverParam;
+public:
+ LLDriverParamInfo();
+ /*virtual*/ ~LLDriverParamInfo() {};
+
+ /*virtual*/ bool parseXml(LLXmlTreeNode* node);
+
+ /*virtual*/ void toStream(std::ostream &out);
+
+protected:
+ typedef std::deque<LLDrivenEntryInfo> entry_info_list_t;
+ entry_info_list_t mDrivenInfoList;
+ LLDriverParam* mDriverParam; // backpointer
+};
+
+//-----------------------------------------------------------------------------
+
+class alignas(16) LLDriverParam : public LLViewerVisualParam
+{
+ LL_ALIGN_NEW
+private:
+ // Hide the default constructor. Force construction with LLAvatarAppearance.
+ LLDriverParam() {}
+public:
+ LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
+ ~LLDriverParam();
+
+ // Special: These functions are overridden by child classes
+ LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
+ // This sets mInfo and calls initialization functions
+ bool setInfo(LLDriverParamInfo* info);
+
+ LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
+ const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+
+ void updateCrossDrivenParams(LLWearableType::EType driven_type);
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+ // LLVisualParam Virtual functions
+ /*virtual*/ void apply(ESex sex) {} // apply is called separately for each driven param.
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget(F32 target_value);
+ /*virtual*/ void stopAnimating();
+ /*virtual*/ bool linkDrivenParams(visual_param_mapper mapper, bool only_cross_params);
+ /*virtual*/ void resetDrivenParams();
+
+ // LLViewerVisualParam Virtual functions
+ /*virtual*/ F32 getTotalDistortion();
+ /*virtual*/ const LLVector4a& getAvgDistortion();
+ /*virtual*/ F32 getMaxDistortion();
+ /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
+ /*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
+ /*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
+
+ S32 getDrivenParamsCount() const;
+ const LLViewerVisualParam* getDrivenParam(S32 index) const;
+
+ typedef std::vector<LLDrivenEntry> entry_list_t;
+ entry_list_t& getDrivenList() { return mDriven; }
+ void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
+
+protected:
+ LLDriverParam(const LLDriverParam& pOther);
+ F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
+ void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
+
+
+ LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
+ entry_list_t mDriven;
+ LLViewerVisualParam* mCurrentDistortionParam;
+ // Backlink only; don't make this an LLPointer.
+ LLAvatarAppearance* mAvatarAppearance;
+ LLWearable* mWearablep;
+};
+
+#endif // LL_LLDRIVERPARAM_H
diff --git a/indra/llappearance/lljointpickname.h b/indra/llappearance/lljointpickname.h
index 1d41a761fc..93c827ac21 100644
--- a/indra/llappearance/lljointpickname.h
+++ b/indra/llappearance/lljointpickname.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file lljointpickname.h
* @brief Defines OpenGL seleciton stack names
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -35,13 +35,13 @@ class LLAvatarJointMesh;
// should be pushed/popped.
enum LLJointPickName
{
- PN_DEFAULT = -1,
- PN_0 = 0,
- PN_1 = 1,
- PN_2 = 2,
- PN_3 = 3,
- PN_4 = 4,
- PN_5 = 5
+ PN_DEFAULT = -1,
+ PN_0 = 0,
+ PN_1 = 1,
+ PN_2 = 2,
+ PN_3 = 3,
+ PN_4 = 4,
+ PN_5 = 5
};
typedef std::vector<LLAvatarJointMesh*> avatar_joint_mesh_list_t;
diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp
index 84c0fd8380..65464e7f65 100644
--- a/indra/llappearance/lllocaltextureobject.cpp
+++ b/indra/llappearance/lllocaltextureobject.cpp
@@ -1,212 +1,212 @@
-/**
- * @file lllocaltextureobject.cpp
- *
- * $LicenseInfo:firstyear=2009&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 "lllocaltextureobject.h"
-
-#include "llimage.h"
-#include "llrender.h"
-#include "lltexlayer.h"
-#include "llgltexture.h"
-#include "lluuid.h"
-#include "llwearable.h"
-
-
-LLLocalTextureObject::LLLocalTextureObject() :
- mIsBakedReady(false),
- mDiscard(MAX_DISCARD_LEVEL+1)
-{
- mImage = NULL;
-}
-
-LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) :
- mIsBakedReady(false),
- mDiscard(MAX_DISCARD_LEVEL+1)
-{
- mImage = image;
- gGL.getTexUnit(0)->bind(mImage);
- mID = id;
-}
-
-LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
- mImage(lto.mImage),
- mID(lto.mID),
- mIsBakedReady(lto.mIsBakedReady),
- mDiscard(lto.mDiscard)
-{
- U32 num_layers = lto.getNumTexLayers();
- mTexLayers.reserve(num_layers);
- for (U32 index = 0; index < num_layers; index++)
- {
- LLTexLayer* original_layer = lto.getTexLayer(index);
- if (!original_layer)
- {
- LL_ERRS() << "could not clone Local Texture Object: unable to extract texlayer!" << LL_ENDL;
- continue;
- }
-
- LLTexLayer* new_layer = new LLTexLayer(*original_layer);
- new_layer->setLTO(this);
- mTexLayers.push_back(new_layer);
- }
-}
-
-LLLocalTextureObject::~LLLocalTextureObject()
-{
- delete_and_clear(mTexLayers);
-}
-
-LLGLTexture* LLLocalTextureObject::getImage() const
-{
- return mImage;
-}
-
-LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
-{
- if (index >= getNumTexLayers())
- {
- return NULL;
- }
-
- return mTexLayers[index];
-}
-
-LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
-{
- for(LLTexLayer* layer : mTexLayers)
- {
- if (layer->getName().compare(name) == 0)
- {
- return layer;
- }
- }
-
- return NULL;
-}
-
-U32 LLLocalTextureObject::getNumTexLayers() const
-{
- return mTexLayers.size();
-}
-
-LLUUID LLLocalTextureObject::getID() const
-{
- return mID;
-}
-
-S32 LLLocalTextureObject::getDiscard() const
-{
- return mDiscard;
-}
-
-bool LLLocalTextureObject::getBakedReady() const
-{
- return mIsBakedReady;
-}
-
-void LLLocalTextureObject::setImage(LLGLTexture* new_image)
-{
- mImage = new_image;
-}
-
-bool LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index)
-{
- if (index >= getNumTexLayers() )
- {
- return false;
- }
-
- if (new_tex_layer == NULL)
- {
- return removeTexLayer(index);
- }
-
- LLTexLayer *layer = new LLTexLayer(*new_tex_layer);
- layer->setLTO(this);
-
- if (mTexLayers[index])
- {
- delete mTexLayers[index];
- }
- mTexLayers[index] = layer;
-
- return true;
-}
-
-bool LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable)
-{
- if (new_tex_layer == NULL)
- {
- return false;
- }
-
- LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable);
- layer->setLTO(this);
- mTexLayers.push_back(layer);
- return true;
-}
-
-bool LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable)
-{
- if (new_tex_layer == NULL)
- {
- return false;
- }
-
- LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable);
- layer->setLTO(this);
- mTexLayers.push_back(layer);
- return true;
-}
-
-bool LLLocalTextureObject::removeTexLayer(U32 index)
-{
- if (index >= getNumTexLayers())
- {
- return false;
- }
- tex_layer_vec_t::iterator iter = mTexLayers.begin();
- iter += index;
-
- delete *iter;
- mTexLayers.erase(iter);
- return true;
-}
-
-void LLLocalTextureObject::setID(LLUUID new_id)
-{
- mID = new_id;
-}
-
-void LLLocalTextureObject::setDiscard(S32 new_discard)
-{
- mDiscard = new_discard;
-}
-
-void LLLocalTextureObject::setBakedReady(bool ready)
-{
- mIsBakedReady = ready;
-}
+/**
+ * @file lllocaltextureobject.cpp
+ *
+ * $LicenseInfo:firstyear=2009&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 "lllocaltextureobject.h"
+
+#include "llimage.h"
+#include "llrender.h"
+#include "lltexlayer.h"
+#include "llgltexture.h"
+#include "lluuid.h"
+#include "llwearable.h"
+
+
+LLLocalTextureObject::LLLocalTextureObject() :
+ mIsBakedReady(false),
+ mDiscard(MAX_DISCARD_LEVEL+1)
+{
+ mImage = NULL;
+}
+
+LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) :
+ mIsBakedReady(false),
+ mDiscard(MAX_DISCARD_LEVEL+1)
+{
+ mImage = image;
+ gGL.getTexUnit(0)->bind(mImage);
+ mID = id;
+}
+
+LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
+ mImage(lto.mImage),
+ mID(lto.mID),
+ mIsBakedReady(lto.mIsBakedReady),
+ mDiscard(lto.mDiscard)
+{
+ U32 num_layers = lto.getNumTexLayers();
+ mTexLayers.reserve(num_layers);
+ for (U32 index = 0; index < num_layers; index++)
+ {
+ LLTexLayer* original_layer = lto.getTexLayer(index);
+ if (!original_layer)
+ {
+ LL_ERRS() << "could not clone Local Texture Object: unable to extract texlayer!" << LL_ENDL;
+ continue;
+ }
+
+ LLTexLayer* new_layer = new LLTexLayer(*original_layer);
+ new_layer->setLTO(this);
+ mTexLayers.push_back(new_layer);
+ }
+}
+
+LLLocalTextureObject::~LLLocalTextureObject()
+{
+ delete_and_clear(mTexLayers);
+}
+
+LLGLTexture* LLLocalTextureObject::getImage() const
+{
+ return mImage;
+}
+
+LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
+{
+ if (index >= getNumTexLayers())
+ {
+ return NULL;
+ }
+
+ return mTexLayers[index];
+}
+
+LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
+{
+ for(LLTexLayer* layer : mTexLayers)
+ {
+ if (layer->getName().compare(name) == 0)
+ {
+ return layer;
+ }
+ }
+
+ return NULL;
+}
+
+U32 LLLocalTextureObject::getNumTexLayers() const
+{
+ return mTexLayers.size();
+}
+
+LLUUID LLLocalTextureObject::getID() const
+{
+ return mID;
+}
+
+S32 LLLocalTextureObject::getDiscard() const
+{
+ return mDiscard;
+}
+
+bool LLLocalTextureObject::getBakedReady() const
+{
+ return mIsBakedReady;
+}
+
+void LLLocalTextureObject::setImage(LLGLTexture* new_image)
+{
+ mImage = new_image;
+}
+
+bool LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index)
+{
+ if (index >= getNumTexLayers() )
+ {
+ return false;
+ }
+
+ if (new_tex_layer == NULL)
+ {
+ return removeTexLayer(index);
+ }
+
+ LLTexLayer *layer = new LLTexLayer(*new_tex_layer);
+ layer->setLTO(this);
+
+ if (mTexLayers[index])
+ {
+ delete mTexLayers[index];
+ }
+ mTexLayers[index] = layer;
+
+ return true;
+}
+
+bool LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable)
+{
+ if (new_tex_layer == NULL)
+ {
+ return false;
+ }
+
+ LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable);
+ layer->setLTO(this);
+ mTexLayers.push_back(layer);
+ return true;
+}
+
+bool LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable)
+{
+ if (new_tex_layer == NULL)
+ {
+ return false;
+ }
+
+ LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable);
+ layer->setLTO(this);
+ mTexLayers.push_back(layer);
+ return true;
+}
+
+bool LLLocalTextureObject::removeTexLayer(U32 index)
+{
+ if (index >= getNumTexLayers())
+ {
+ return false;
+ }
+ tex_layer_vec_t::iterator iter = mTexLayers.begin();
+ iter += index;
+
+ delete *iter;
+ mTexLayers.erase(iter);
+ return true;
+}
+
+void LLLocalTextureObject::setID(LLUUID new_id)
+{
+ mID = new_id;
+}
+
+void LLLocalTextureObject::setDiscard(S32 new_discard)
+{
+ mDiscard = new_discard;
+}
+
+void LLLocalTextureObject::setBakedReady(bool ready)
+{
+ mIsBakedReady = ready;
+}
diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h
index a5118ffde3..8922ec414f 100644
--- a/indra/llappearance/lllocaltextureobject.h
+++ b/indra/llappearance/lllocaltextureobject.h
@@ -1,86 +1,86 @@
-/**
- * @file lllocaltextureobject.h
- * @brief LLLocalTextureObject class header file
- *
- * $LicenseInfo:firstyear=2009&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$
- */
-
-#ifndef LL_LOCALTEXTUREOBJECT_H
-#define LL_LOCALTEXTUREOBJECT_H
-
-#include <boost/shared_ptr.hpp>
-
-#include "llpointer.h"
-#include "llgltexture.h"
-
-class LLTexLayer;
-class LLTexLayerTemplate;
-class LLWearable;
-
-// Stores all relevant information for a single texture
-// assumed to have ownership of all objects referred to -
-// will delete objects when being replaced or if object is destroyed.
-class LLLocalTextureObject
-{
-public:
- LLLocalTextureObject();
- LLLocalTextureObject(LLGLTexture* image, const LLUUID& id);
- LLLocalTextureObject(const LLLocalTextureObject& lto);
- ~LLLocalTextureObject();
-
- LLGLTexture* getImage() const;
- LLTexLayer* getTexLayer(U32 index) const;
- LLTexLayer* getTexLayer(const std::string &name);
- U32 getNumTexLayers() const;
- LLUUID getID() const;
- S32 getDiscard() const;
- bool getBakedReady() const;
-
- void setImage(LLGLTexture* new_image);
- bool setTexLayer(LLTexLayer *new_tex_layer, U32 index);
- bool addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable);
- bool addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable);
- bool removeTexLayer(U32 index);
-
- void setID(LLUUID new_id);
- void setDiscard(S32 new_discard);
- void setBakedReady(bool ready);
-
-protected:
-
-private:
-
- LLPointer<LLGLTexture> mImage;
- // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer
- // using shared pointers here only for smart assignment & cleanup
- // do NOT create new shared pointers to these objects, or keep pointers to them around
- typedef std::vector<LLTexLayer*> tex_layer_vec_t;
- tex_layer_vec_t mTexLayers;
-
- LLUUID mID;
-
- bool mIsBakedReady;
- S32 mDiscard;
-};
-
- #endif // LL_LOCALTEXTUREOBJECT_H
-
+/**
+ * @file lllocaltextureobject.h
+ * @brief LLLocalTextureObject class header file
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#ifndef LL_LOCALTEXTUREOBJECT_H
+#define LL_LOCALTEXTUREOBJECT_H
+
+#include <boost/shared_ptr.hpp>
+
+#include "llpointer.h"
+#include "llgltexture.h"
+
+class LLTexLayer;
+class LLTexLayerTemplate;
+class LLWearable;
+
+// Stores all relevant information for a single texture
+// assumed to have ownership of all objects referred to -
+// will delete objects when being replaced or if object is destroyed.
+class LLLocalTextureObject
+{
+public:
+ LLLocalTextureObject();
+ LLLocalTextureObject(LLGLTexture* image, const LLUUID& id);
+ LLLocalTextureObject(const LLLocalTextureObject& lto);
+ ~LLLocalTextureObject();
+
+ LLGLTexture* getImage() const;
+ LLTexLayer* getTexLayer(U32 index) const;
+ LLTexLayer* getTexLayer(const std::string &name);
+ U32 getNumTexLayers() const;
+ LLUUID getID() const;
+ S32 getDiscard() const;
+ bool getBakedReady() const;
+
+ void setImage(LLGLTexture* new_image);
+ bool setTexLayer(LLTexLayer *new_tex_layer, U32 index);
+ bool addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable);
+ bool addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable);
+ bool removeTexLayer(U32 index);
+
+ void setID(LLUUID new_id);
+ void setDiscard(S32 new_discard);
+ void setBakedReady(bool ready);
+
+protected:
+
+private:
+
+ LLPointer<LLGLTexture> mImage;
+ // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer
+ // using shared pointers here only for smart assignment & cleanup
+ // do NOT create new shared pointers to these objects, or keep pointers to them around
+ typedef std::vector<LLTexLayer*> tex_layer_vec_t;
+ tex_layer_vec_t mTexLayers;
+
+ LLUUID mID;
+
+ bool mIsBakedReady;
+ S32 mDiscard;
+};
+
+ #endif // LL_LOCALTEXTUREOBJECT_H
+
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp
index e4e9e8d550..6c56b192ed 100644
--- a/indra/llappearance/llpolymesh.cpp
+++ b/indra/llappearance/llpolymesh.cpp
@@ -1,1040 +1,1040 @@
-/**
- * @file llpolymesh.cpp
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-#include "llpolymesh.h"
-#include "llfasttimer.h"
-#include "llmemory.h"
-
-//#include "llviewercontrol.h"
-#include "llxmltree.h"
-#include "llavatarappearance.h"
-#include "llwearable.h"
-#include "lldir.h"
-#include "llvolume.h"
-#include "llendianswizzle.h"
-
-
-#define HEADER_ASCII "Linden Mesh 1.0"
-#define HEADER_BINARY "Linden Binary Mesh 1.0"
-
-//extern LLControlGroup gSavedSettings; // read only
-
-LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
- const std::string &name);
-LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
- const LLVector3 &direction,
- const std::string &name);
-LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
- F32 scale,
- const std::string &name);
-
-//-----------------------------------------------------------------------------
-// Global table of loaded LLPolyMeshes
-//-----------------------------------------------------------------------------
-LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData()
-//-----------------------------------------------------------------------------
-LLPolyMeshSharedData::LLPolyMeshSharedData()
-{
- mNumVertices = 0;
- mBaseCoords = NULL;
- mBaseNormals = NULL;
- mBaseBinormals = NULL;
- mTexCoords = NULL;
- mDetailTexCoords = NULL;
- mWeights = NULL;
- mHasWeights = false;
- mHasDetailTexCoords = false;
-
- mNumFaces = 0;
- mFaces = NULL;
-
- mNumJointNames = 0;
- mJointNames = NULL;
-
- mTriangleIndices = NULL;
- mNumTriangleIndices = 0;
-
- mReferenceData = NULL;
-
- mLastIndexOffset = -1;
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMeshSharedData()
-//-----------------------------------------------------------------------------
-LLPolyMeshSharedData::~LLPolyMeshSharedData()
-{
- freeMeshData();
- for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
- mMorphData.clear();
-}
-
-//-----------------------------------------------------------------------------
-// setupLOD()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
-{
- mReferenceData = reference_data;
-
- if (reference_data)
- {
- mBaseCoords = reference_data->mBaseCoords;
- mBaseNormals = reference_data->mBaseNormals;
- mBaseBinormals = reference_data->mBaseBinormals;
- mTexCoords = reference_data->mTexCoords;
- mDetailTexCoords = reference_data->mDetailTexCoords;
- mWeights = reference_data->mWeights;
- mHasWeights = reference_data->mHasWeights;
- mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::freeMeshData()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::freeMeshData()
-{
- if (!mReferenceData)
- {
- mNumVertices = 0;
-
- ll_aligned_free_16(mBaseCoords);
- mBaseCoords = NULL;
-
- ll_aligned_free_16(mBaseNormals);
- mBaseNormals = NULL;
-
- ll_aligned_free_16(mBaseBinormals);
- mBaseBinormals = NULL;
-
- ll_aligned_free_16(mTexCoords);
- mTexCoords = NULL;
-
- ll_aligned_free_16(mDetailTexCoords);
- mDetailTexCoords = NULL;
-
- ll_aligned_free_16(mWeights);
- mWeights = NULL;
- }
-
- mNumFaces = 0;
- delete [] mFaces;
- mFaces = NULL;
-
- mNumJointNames = 0;
- delete [] mJointNames;
- mJointNames = NULL;
-
- delete [] mTriangleIndices;
- mTriangleIndices = NULL;
-
-// mVertFaceMap.deleteAllData();
-}
-
-// compare_int is used by the qsort function to sort the index array
-S32 compare_int(const void *a, const void *b);
-
-//-----------------------------------------------------------------------------
-// genIndices()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::genIndices(S32 index_offset)
-{
- if (index_offset == mLastIndexOffset)
- {
- return;
- }
-
- delete []mTriangleIndices;
- mTriangleIndices = new U32[mNumTriangleIndices];
-
- S32 cur_index = 0;
- for (S32 i = 0; i < mNumFaces; i++)
- {
- mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
- cur_index++;
- mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
- cur_index++;
- mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
- cur_index++;
- }
-
- mLastIndexOffset = index_offset;
-}
-
-//--------------------------------------------------------------------
-// LLPolyMeshSharedData::getNumKB()
-//--------------------------------------------------------------------
-U32 LLPolyMeshSharedData::getNumKB()
-{
- U32 num_kb = sizeof(LLPolyMesh);
-
- if (!isLOD())
- {
- num_kb += mNumVertices *
- ( sizeof(LLVector3) + // coords
- sizeof(LLVector3) + // normals
- sizeof(LLVector2) ); // texCoords
- }
-
- if (mHasDetailTexCoords && !isLOD())
- {
- num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords
- }
-
- if (mHasWeights && !isLOD())
- {
- num_kb += mNumVertices * sizeof(float); // weights
- }
-
- num_kb += mNumFaces * sizeof(LLPolyFace); // faces
-
- num_kb /= 1024;
- return num_kb;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateVertexData()
-//-----------------------------------------------------------------------------
-bool LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
-{
- U32 i;
- mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
- mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
- mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
- mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
- mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
- mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32));
- for (i = 0; i < numVertices; i++)
- {
- mBaseCoords[i].clear();
- mBaseNormals[i].clear();
- mBaseBinormals[i].clear();
- mTexCoords[i].clear();
- mWeights[i] = 0.f;
- }
- mNumVertices = numVertices;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateFaceData()
-//-----------------------------------------------------------------------------
-bool LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
-{
- mFaces = new LLPolyFace[ numFaces ];
- mNumFaces = numFaces;
- mNumTriangleIndices = mNumFaces * 3;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateJointNames()
-//-----------------------------------------------------------------------------
-bool LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
-{
- mJointNames = new std::string[ numJointNames ];
- mNumJointNames = numJointNames;
- return true;
-}
-
-//--------------------------------------------------------------------
-// LLPolyMeshSharedData::loadMesh()
-//--------------------------------------------------------------------
-bool LLPolyMeshSharedData::loadMesh( const std::string& fileName )
-{
- //-------------------------------------------------------------------------
- // Open the file
- //-------------------------------------------------------------------------
- if(fileName.empty())
- {
- LL_ERRS() << "Filename is Empty!" << LL_ENDL;
- return false;
- }
- LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
- if (!fp)
- {
- LL_ERRS() << "can't open: " << fileName << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // Read a chunk
- //-------------------------------------------------------------------------
- char header[128]; /*Flawfinder: ignore*/
- if (fread(header, sizeof(char), 128, fp) != 128)
- {
- LL_WARNS() << "Short read" << LL_ENDL;
- }
-
- //-------------------------------------------------------------------------
- // Check for proper binary header
- //-------------------------------------------------------------------------
- bool status = false;
- if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
- {
- LL_DEBUGS() << "Loading " << fileName << LL_ENDL;
-
- //----------------------------------------------------------------
- // File Header (seek past it)
- //----------------------------------------------------------------
- fseek(fp, 24, SEEK_SET);
-
- //----------------------------------------------------------------
- // HasWeights
- //----------------------------------------------------------------
- U8 hasWeights;
- size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL;
- return false;
- }
- if (!isLOD())
- {
- mHasWeights = hasWeights > 0;
- }
-
- //----------------------------------------------------------------
- // HasDetailTexCoords
- //----------------------------------------------------------------
- U8 hasDetailTexCoords;
- numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL;
- return false;
- }
-
- //----------------------------------------------------------------
- // Position
- //----------------------------------------------------------------
- LLVector3 position;
- numRead = fread(position.mV, sizeof(float), 3, fp);
- llendianswizzle(position.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read Position from " << fileName << LL_ENDL;
- return false;
- }
- setPosition( position );
-
- //----------------------------------------------------------------
- // Rotation
- //----------------------------------------------------------------
- LLVector3 rotationAngles;
- numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
- llendianswizzle(rotationAngles.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL;
- return false;
- }
-
- U8 rotationOrder;
- numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
-
- if (numRead != 1)
- {
- LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL;
- return false;
- }
-
- rotationOrder = 0;
-
- setRotation( mayaQ( rotationAngles.mV[0],
- rotationAngles.mV[1],
- rotationAngles.mV[2],
- (LLQuaternion::Order)rotationOrder ) );
-
- //----------------------------------------------------------------
- // Scale
- //----------------------------------------------------------------
- LLVector3 scale;
- numRead = fread(scale.mV, sizeof(float), 3, fp);
- llendianswizzle(scale.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL;
- return false;
- }
- setScale( scale );
-
- //-------------------------------------------------------------------------
- // Release any existing mesh geometry
- //-------------------------------------------------------------------------
- freeMeshData();
-
- U16 numVertices = 0;
-
- //----------------------------------------------------------------
- // NumVertices
- //----------------------------------------------------------------
- if (!isLOD())
- {
- numRead = fread(&numVertices, sizeof(U16), 1, fp);
- llendianswizzle(&numVertices, sizeof(U16), 1);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL;
- return false;
- }
-
- allocateVertexData( numVertices );
-
- for (U16 i = 0; i < numVertices; ++i)
- {
- //----------------------------------------------------------------
- // Coords
- //----------------------------------------------------------------
- numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
- llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- for (U16 i = 0; i < numVertices; ++i)
- {
- //----------------------------------------------------------------
- // Normals
- //----------------------------------------------------------------
- numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
- llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- for (U16 i = 0; i < numVertices; ++i)
- {
- //----------------------------------------------------------------
- // Binormals
- //----------------------------------------------------------------
- numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
- llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
- if (numRead != 3)
- {
- LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- //----------------------------------------------------------------
- // TexCoords
- //----------------------------------------------------------------
- numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL;
- return false;
- }
-
- //----------------------------------------------------------------
- // DetailTexCoords
- //----------------------------------------------------------------
- if (mHasDetailTexCoords)
- {
- numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL;
- return false;
- }
- }
-
- //----------------------------------------------------------------
- // Weights
- //----------------------------------------------------------------
- if (mHasWeights)
- {
- numRead = fread(mWeights, sizeof(float), numVertices, fp);
- llendianswizzle(mWeights, sizeof(float), numVertices);
- if (numRead != numVertices)
- {
- LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL;
- return false;
- }
- }
- }
-
- //----------------------------------------------------------------
- // NumFaces
- //----------------------------------------------------------------
- U16 numFaces;
- numRead = fread(&numFaces, sizeof(U16), 1, fp);
- llendianswizzle(&numFaces, sizeof(U16), 1);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL;
- return false;
- }
- allocateFaceData( numFaces );
-
-
- //----------------------------------------------------------------
- // Faces
- //----------------------------------------------------------------
- U32 i;
- U32 numTris = 0;
- for (i = 0; i < numFaces; i++)
- {
- S16 face[3];
- numRead = fread(face, sizeof(U16), 3, fp);
- llendianswizzle(face, sizeof(U16), 3);
- if (numRead != 3)
- {
- LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL;
- return false;
- }
- if (mReferenceData)
- {
- llassert(face[0] < mReferenceData->mNumVertices);
- llassert(face[1] < mReferenceData->mNumVertices);
- llassert(face[2] < mReferenceData->mNumVertices);
- }
-
- if (isLOD())
- {
- // store largest index in case of LODs
- for (S32 j = 0; j < 3; j++)
- {
- if (face[j] > mNumVertices - 1)
- {
- mNumVertices = face[j] + 1;
- }
- }
- }
- mFaces[i][0] = face[0];
- mFaces[i][1] = face[1];
- mFaces[i][2] = face[2];
-
-// S32 j;
-// for(j = 0; j < 3; j++)
-// {
-// std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
-// if (!face_list)
-// {
-// face_list = new std::vector<S32>;
-// mVertFaceMap.addData(face[j], face_list);
-// }
-// face_list->put(i);
-// }
-
- numTris++;
- }
-
- LL_DEBUGS() << "verts: " << numVertices
- << ", faces: " << numFaces
- << ", tris: " << numTris
- << LL_ENDL;
-
- //----------------------------------------------------------------
- // NumSkinJoints
- //----------------------------------------------------------------
- if (!isLOD())
- {
- U16 numSkinJoints = 0;
- if ( mHasWeights )
- {
- numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
- llendianswizzle(&numSkinJoints, sizeof(U16), 1);
- if (numRead != 1)
- {
- LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL;
- return false;
- }
- allocateJointNames( numSkinJoints );
- }
-
- //----------------------------------------------------------------
- // SkinJoints
- //----------------------------------------------------------------
- for (i=0; i < numSkinJoints; i++)
- {
- char jointName[64+1];
- numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
- jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
- if (numRead != 1)
- {
- LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL;
- return false;
- }
-
- std::string *jn = &mJointNames[i];
- *jn = jointName;
- }
-
- //-------------------------------------------------------------------------
- // look for morph section
- //-------------------------------------------------------------------------
- char morphName[64+1];
- morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
- while(fread(&morphName, sizeof(char), 64, fp) == 64)
- {
- if (!strcmp(morphName, "End Morphs"))
- {
- // we reached the end of the morphs
- break;
- }
- std::string morph_name(morphName);
- LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name);
-
- bool result = morph_data->loadBinary(fp, this);
-
- if (!result)
- {
- LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL;
- delete morph_data;
- continue;
- }
-
- mMorphData.insert(morph_data);
-
- if (!strcmp(morphName, "Breast_Female_Cleavage"))
- {
- mMorphData.insert(clone_morph_param_cleavage(morph_data,
- .75f,
- "Breast_Physics_LeftRight_Driven"));
- }
-
- if (!strcmp(morphName, "Breast_Female_Cleavage"))
- {
- mMorphData.insert(clone_morph_param_duplicate(morph_data,
- "Breast_Physics_InOut_Driven"));
- }
- if (!strcmp(morphName, "Breast_Gravity"))
- {
- mMorphData.insert(clone_morph_param_duplicate(morph_data,
- "Breast_Physics_UpDown_Driven"));
- }
-
- if (!strcmp(morphName, "Big_Belly_Torso"))
- {
- mMorphData.insert(clone_morph_param_direction(morph_data,
- LLVector3(0,0,0.05f),
- "Belly_Physics_Torso_UpDown_Driven"));
- }
-
- if (!strcmp(morphName, "Big_Belly_Legs"))
- {
- mMorphData.insert(clone_morph_param_direction(morph_data,
- LLVector3(0,0,0.05f),
- "Belly_Physics_Legs_UpDown_Driven"));
- }
-
- if (!strcmp(morphName, "skirt_belly"))
- {
- mMorphData.insert(clone_morph_param_direction(morph_data,
- LLVector3(0,0,0.05f),
- "Belly_Physics_Skirt_UpDown_Driven"));
- }
-
- if (!strcmp(morphName, "Small_Butt"))
- {
- mMorphData.insert(clone_morph_param_direction(morph_data,
- LLVector3(0,0,0.05f),
- "Butt_Physics_UpDown_Driven"));
- }
- if (!strcmp(morphName, "Small_Butt"))
- {
- mMorphData.insert(clone_morph_param_direction(morph_data,
- LLVector3(0,0.03f,0),
- "Butt_Physics_LeftRight_Driven"));
- }
- }
-
- S32 numRemaps;
- if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
- {
- llendianswizzle(&numRemaps, sizeof(S32), 1);
- for (S32 i = 0; i < numRemaps; i++)
- {
- S32 remapSrc;
- S32 remapDst;
- if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
- {
- LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL;
- break;
- }
- if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
- {
- LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL;
- break;
- }
- llendianswizzle(&remapSrc, sizeof(S32), 1);
- llendianswizzle(&remapDst, sizeof(S32), 1);
-
- mSharedVerts[remapSrc] = remapDst;
- }
- }
- }
-
- status = true;
- }
- else
- {
- LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL;
- status = false;
- }
-
- if (0 == mNumJointNames)
- {
- allocateJointNames(1);
- }
-
- fclose( fp );
-
- return status;
-}
-
-//-----------------------------------------------------------------------------
-// getSharedVert()
-//-----------------------------------------------------------------------------
-const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
-{
- if (mSharedVerts.count(vert) > 0)
- {
- return &mSharedVerts[vert];
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getUV()
-//-----------------------------------------------------------------------------
-const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
-{
- // TODO: convert all index variables to S32
- llassert((S32)index < mNumVertices);
-
- return mTexCoords[index];
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
-{
- llassert(shared_data);
-
- mSharedData = shared_data;
- mReferenceMesh = reference_mesh;
- mAvatarp = NULL;
- mVertexData = NULL;
-
- mCurVertexCount = 0;
- mFaceIndexCount = 0;
- mFaceIndexOffset = 0;
- mFaceVertexCount = 0;
- mFaceVertexOffset = 0;
-
- if (shared_data->isLOD() && reference_mesh)
- {
- mCoords = reference_mesh->mCoords;
- mNormals = reference_mesh->mNormals;
- mScaledNormals = reference_mesh->mScaledNormals;
- mBinormals = reference_mesh->mBinormals;
- mScaledBinormals = reference_mesh->mScaledBinormals;
- mTexCoords = reference_mesh->mTexCoords;
- mClothingWeights = reference_mesh->mClothingWeights;
- }
- else
- {
- // Allocate memory without initializing every vector
- // NOTE: This makes asusmptions about the size of LLVector[234]
- S32 nverts = mSharedData->mNumVertices;
- //make sure it's an even number of verts for alignment
- nverts += nverts%2;
- S32 nfloats = nverts * (
- 4 + //coords
- 4 + //normals
- 4 + //weights
- 2 + //coords
- 4 + //scaled normals
- 4 + //binormals
- 4); //scaled binormals
-
- //use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
- mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
- S32 offset = 0;
- mCoords = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- mNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- mClothingWeights = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
- mScaledNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- mBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- mScaledBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
- initializeForMorph();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh::~LLPolyMesh()
-{
- delete_and_clear(mJointRenderData);
- ll_aligned_free_16(mVertexData);
-}
-
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh::getMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
-{
- //-------------------------------------------------------------------------
- // search for an existing mesh by this name
- //-------------------------------------------------------------------------
- LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
- if (meshSharedData)
- {
-// LL_INFOS() << "Polymesh " << name << " found in global mesh table." << LL_ENDL;
- LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
- return poly_mesh;
- }
-
- //-------------------------------------------------------------------------
- // if not found, create a new one, add it to the list
- //-------------------------------------------------------------------------
- std::string full_path;
- full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
-
- LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
- if (reference_mesh)
- {
- mesh_data->setupLOD(reference_mesh->getSharedData());
- }
- if ( ! mesh_data->loadMesh( full_path ) )
- {
- delete mesh_data;
- return NULL;
- }
-
- LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
-
-// LL_INFOS() << "Polymesh " << name << " added to global mesh table." << LL_ENDL;
- sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
-
- return poly_mesh;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh::freeAllMeshes()
-//-----------------------------------------------------------------------------
-void LLPolyMesh::freeAllMeshes()
-{
- // delete each item in the global lists
- for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
- sGlobalSharedMeshList.clear();
-}
-
-LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
-{
- return mSharedData;
-}
-
-
-//--------------------------------------------------------------------
-// LLPolyMesh::dumpDiagInfo()
-//--------------------------------------------------------------------
-void LLPolyMesh::dumpDiagInfo()
-{
- // keep track of totals
- U32 total_verts = 0;
- U32 total_faces = 0;
- U32 total_kb = 0;
-
- std::string buf;
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- LL_INFOS() << " Global PolyMesh Table (DEBUG only)" << LL_ENDL;
- LL_INFOS() << " Verts Faces Mem(KB) Name" << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-
- // print each loaded mesh, and it's memory usage
- for(const LLPolyMeshSharedDataTable::value_type& mesh_pair : sGlobalSharedMeshList)
- {
- const std::string& mesh_name = mesh_pair.first;
- LLPolyMeshSharedData* mesh = mesh_pair.second;
-
- S32 num_verts = mesh->mNumVertices;
- S32 num_faces = mesh->mNumFaces;
- U32 num_kb = mesh->getNumKB();
-
- buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
- LL_INFOS() << buf << LL_ENDL;
-
- total_verts += num_verts;
- total_faces += num_faces;
- total_kb += num_kb;
- }
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
- LL_INFOS() << buf << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableCoords()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableCoords()
-{
- return mCoords;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableNormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableNormals()
-{
- return mNormals;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableBinormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableBinormals()
-{
- return mBinormals;
-}
-
-
-//-----------------------------------------------------------------------------
-// getWritableClothingWeights()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableClothingWeights()
-{
- return mClothingWeights;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableTexCoords()
-//-----------------------------------------------------------------------------
-LLVector2 *LLPolyMesh::getWritableTexCoords()
-{
- return mTexCoords;
-}
-
-//-----------------------------------------------------------------------------
-// getScaledNormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getScaledNormals()
-{
- return mScaledNormals;
-}
-
-//-----------------------------------------------------------------------------
-// getScaledBinormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getScaledBinormals()
-{
- return mScaledBinormals;
-}
-
-
-//-----------------------------------------------------------------------------
-// initializeForMorph()
-//-----------------------------------------------------------------------------
-void LLPolyMesh::initializeForMorph()
-{
- LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
- LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
- LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
- LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
- LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
- LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
-
- for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
- {
- mClothingWeights[i].clear();
- }
-}
-
-//-----------------------------------------------------------------------------
-// getMorphData()
-//-----------------------------------------------------------------------------
-LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
-{
- if (!mSharedData)
- return NULL;
- for (LLPolyMorphData* morph_data : mSharedData->mMorphData)
- {
- if (morph_data->getName() == morph_name)
- {
- return morph_data;
- }
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// removeMorphData()
-//-----------------------------------------------------------------------------
-// // erasing but not deleting seems bad, but fortunately we don't actually use this...
-// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
-// {
-// if (!mSharedData)
-// return;
-// mSharedData->mMorphData.erase(morph_target);
-// }
-
-//-----------------------------------------------------------------------------
-// deleteAllMorphData()
-//-----------------------------------------------------------------------------
-// void LLPolyMesh::deleteAllMorphData()
-// {
-// if (!mSharedData)
-// return;
-
-// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
-// mSharedData->mMorphData.clear();
-// }
-
-//-----------------------------------------------------------------------------
-// getWritableWeights()
-//-----------------------------------------------------------------------------
-F32* LLPolyMesh::getWritableWeights() const
-{
- return mSharedData->mWeights;
-}
-
-// End
+/**
+ * @file llpolymesh.cpp
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+#include "llpolymesh.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
+
+//#include "llviewercontrol.h"
+#include "llxmltree.h"
+#include "llavatarappearance.h"
+#include "llwearable.h"
+#include "lldir.h"
+#include "llvolume.h"
+#include "llendianswizzle.h"
+
+
+#define HEADER_ASCII "Linden Mesh 1.0"
+#define HEADER_BINARY "Linden Binary Mesh 1.0"
+
+//extern LLControlGroup gSavedSettings; // read only
+
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+ const std::string &name);
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+ const LLVector3 &direction,
+ const std::string &name);
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+ F32 scale,
+ const std::string &name);
+
+//-----------------------------------------------------------------------------
+// Global table of loaded LLPolyMeshes
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::LLPolyMeshSharedData()
+{
+ mNumVertices = 0;
+ mBaseCoords = NULL;
+ mBaseNormals = NULL;
+ mBaseBinormals = NULL;
+ mTexCoords = NULL;
+ mDetailTexCoords = NULL;
+ mWeights = NULL;
+ mHasWeights = false;
+ mHasDetailTexCoords = false;
+
+ mNumFaces = 0;
+ mFaces = NULL;
+
+ mNumJointNames = 0;
+ mJointNames = NULL;
+
+ mTriangleIndices = NULL;
+ mNumTriangleIndices = 0;
+
+ mReferenceData = NULL;
+
+ mLastIndexOffset = -1;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::~LLPolyMeshSharedData()
+{
+ freeMeshData();
+ for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
+ mMorphData.clear();
+}
+
+//-----------------------------------------------------------------------------
+// setupLOD()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
+{
+ mReferenceData = reference_data;
+
+ if (reference_data)
+ {
+ mBaseCoords = reference_data->mBaseCoords;
+ mBaseNormals = reference_data->mBaseNormals;
+ mBaseBinormals = reference_data->mBaseBinormals;
+ mTexCoords = reference_data->mTexCoords;
+ mDetailTexCoords = reference_data->mDetailTexCoords;
+ mWeights = reference_data->mWeights;
+ mHasWeights = reference_data->mHasWeights;
+ mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::freeMeshData()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::freeMeshData()
+{
+ if (!mReferenceData)
+ {
+ mNumVertices = 0;
+
+ ll_aligned_free_16(mBaseCoords);
+ mBaseCoords = NULL;
+
+ ll_aligned_free_16(mBaseNormals);
+ mBaseNormals = NULL;
+
+ ll_aligned_free_16(mBaseBinormals);
+ mBaseBinormals = NULL;
+
+ ll_aligned_free_16(mTexCoords);
+ mTexCoords = NULL;
+
+ ll_aligned_free_16(mDetailTexCoords);
+ mDetailTexCoords = NULL;
+
+ ll_aligned_free_16(mWeights);
+ mWeights = NULL;
+ }
+
+ mNumFaces = 0;
+ delete [] mFaces;
+ mFaces = NULL;
+
+ mNumJointNames = 0;
+ delete [] mJointNames;
+ mJointNames = NULL;
+
+ delete [] mTriangleIndices;
+ mTriangleIndices = NULL;
+
+// mVertFaceMap.deleteAllData();
+}
+
+// compare_int is used by the qsort function to sort the index array
+S32 compare_int(const void *a, const void *b);
+
+//-----------------------------------------------------------------------------
+// genIndices()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::genIndices(S32 index_offset)
+{
+ if (index_offset == mLastIndexOffset)
+ {
+ return;
+ }
+
+ delete []mTriangleIndices;
+ mTriangleIndices = new U32[mNumTriangleIndices];
+
+ S32 cur_index = 0;
+ for (S32 i = 0; i < mNumFaces; i++)
+ {
+ mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
+ cur_index++;
+ }
+
+ mLastIndexOffset = index_offset;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::getNumKB()
+//--------------------------------------------------------------------
+U32 LLPolyMeshSharedData::getNumKB()
+{
+ U32 num_kb = sizeof(LLPolyMesh);
+
+ if (!isLOD())
+ {
+ num_kb += mNumVertices *
+ ( sizeof(LLVector3) + // coords
+ sizeof(LLVector3) + // normals
+ sizeof(LLVector2) ); // texCoords
+ }
+
+ if (mHasDetailTexCoords && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords
+ }
+
+ if (mHasWeights && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(float); // weights
+ }
+
+ num_kb += mNumFaces * sizeof(LLPolyFace); // faces
+
+ num_kb /= 1024;
+ return num_kb;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateVertexData()
+//-----------------------------------------------------------------------------
+bool LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
+{
+ U32 i;
+ mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+ mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+ mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+ mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
+ mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
+ mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32));
+ for (i = 0; i < numVertices; i++)
+ {
+ mBaseCoords[i].clear();
+ mBaseNormals[i].clear();
+ mBaseBinormals[i].clear();
+ mTexCoords[i].clear();
+ mWeights[i] = 0.f;
+ }
+ mNumVertices = numVertices;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateFaceData()
+//-----------------------------------------------------------------------------
+bool LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
+{
+ mFaces = new LLPolyFace[ numFaces ];
+ mNumFaces = numFaces;
+ mNumTriangleIndices = mNumFaces * 3;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateJointNames()
+//-----------------------------------------------------------------------------
+bool LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
+{
+ mJointNames = new std::string[ numJointNames ];
+ mNumJointNames = numJointNames;
+ return true;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::loadMesh()
+//--------------------------------------------------------------------
+bool LLPolyMeshSharedData::loadMesh( const std::string& fileName )
+{
+ //-------------------------------------------------------------------------
+ // Open the file
+ //-------------------------------------------------------------------------
+ if(fileName.empty())
+ {
+ LL_ERRS() << "Filename is Empty!" << LL_ENDL;
+ return false;
+ }
+ LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
+ if (!fp)
+ {
+ LL_ERRS() << "can't open: " << fileName << LL_ENDL;
+ return false;
+ }
+
+ //-------------------------------------------------------------------------
+ // Read a chunk
+ //-------------------------------------------------------------------------
+ char header[128]; /*Flawfinder: ignore*/
+ if (fread(header, sizeof(char), 128, fp) != 128)
+ {
+ LL_WARNS() << "Short read" << LL_ENDL;
+ }
+
+ //-------------------------------------------------------------------------
+ // Check for proper binary header
+ //-------------------------------------------------------------------------
+ bool status = false;
+ if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
+ {
+ LL_DEBUGS() << "Loading " << fileName << LL_ENDL;
+
+ //----------------------------------------------------------------
+ // File Header (seek past it)
+ //----------------------------------------------------------------
+ fseek(fp, 24, SEEK_SET);
+
+ //----------------------------------------------------------------
+ // HasWeights
+ //----------------------------------------------------------------
+ U8 hasWeights;
+ size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL;
+ return false;
+ }
+ if (!isLOD())
+ {
+ mHasWeights = hasWeights > 0;
+ }
+
+ //----------------------------------------------------------------
+ // HasDetailTexCoords
+ //----------------------------------------------------------------
+ U8 hasDetailTexCoords;
+ numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ //----------------------------------------------------------------
+ // Position
+ //----------------------------------------------------------------
+ LLVector3 position;
+ numRead = fread(position.mV, sizeof(float), 3, fp);
+ llendianswizzle(position.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << "can't read Position from " << fileName << LL_ENDL;
+ return false;
+ }
+ setPosition( position );
+
+ //----------------------------------------------------------------
+ // Rotation
+ //----------------------------------------------------------------
+ LLVector3 rotationAngles;
+ numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
+ llendianswizzle(rotationAngles.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ U8 rotationOrder;
+ numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
+
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ rotationOrder = 0;
+
+ setRotation( mayaQ( rotationAngles.mV[0],
+ rotationAngles.mV[1],
+ rotationAngles.mV[2],
+ (LLQuaternion::Order)rotationOrder ) );
+
+ //----------------------------------------------------------------
+ // Scale
+ //----------------------------------------------------------------
+ LLVector3 scale;
+ numRead = fread(scale.mV, sizeof(float), 3, fp);
+ llendianswizzle(scale.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL;
+ return false;
+ }
+ setScale( scale );
+
+ //-------------------------------------------------------------------------
+ // Release any existing mesh geometry
+ //-------------------------------------------------------------------------
+ freeMeshData();
+
+ U16 numVertices = 0;
+
+ //----------------------------------------------------------------
+ // NumVertices
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ numRead = fread(&numVertices, sizeof(U16), 1, fp);
+ llendianswizzle(&numVertices, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ allocateVertexData( numVertices );
+
+ for (U16 i = 0; i < numVertices; ++i)
+ {
+ //----------------------------------------------------------------
+ // Coords
+ //----------------------------------------------------------------
+ numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
+ llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL;
+ return false;
+ }
+ }
+
+ for (U16 i = 0; i < numVertices; ++i)
+ {
+ //----------------------------------------------------------------
+ // Normals
+ //----------------------------------------------------------------
+ numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
+ llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL;
+ return false;
+ }
+ }
+
+ for (U16 i = 0; i < numVertices; ++i)
+ {
+ //----------------------------------------------------------------
+ // Binormals
+ //----------------------------------------------------------------
+ numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
+ llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL;
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------
+ // TexCoords
+ //----------------------------------------------------------------
+ numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ //----------------------------------------------------------------
+ // DetailTexCoords
+ //----------------------------------------------------------------
+ if (mHasDetailTexCoords)
+ {
+ numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL;
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------
+ // Weights
+ //----------------------------------------------------------------
+ if (mHasWeights)
+ {
+ numRead = fread(mWeights, sizeof(float), numVertices, fp);
+ llendianswizzle(mWeights, sizeof(float), numVertices);
+ if (numRead != numVertices)
+ {
+ LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL;
+ return false;
+ }
+ }
+ }
+
+ //----------------------------------------------------------------
+ // NumFaces
+ //----------------------------------------------------------------
+ U16 numFaces;
+ numRead = fread(&numFaces, sizeof(U16), 1, fp);
+ llendianswizzle(&numFaces, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL;
+ return false;
+ }
+ allocateFaceData( numFaces );
+
+
+ //----------------------------------------------------------------
+ // Faces
+ //----------------------------------------------------------------
+ U32 i;
+ U32 numTris = 0;
+ for (i = 0; i < numFaces; i++)
+ {
+ S16 face[3];
+ numRead = fread(face, sizeof(U16), 3, fp);
+ llendianswizzle(face, sizeof(U16), 3);
+ if (numRead != 3)
+ {
+ LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL;
+ return false;
+ }
+ if (mReferenceData)
+ {
+ llassert(face[0] < mReferenceData->mNumVertices);
+ llassert(face[1] < mReferenceData->mNumVertices);
+ llassert(face[2] < mReferenceData->mNumVertices);
+ }
+
+ if (isLOD())
+ {
+ // store largest index in case of LODs
+ for (S32 j = 0; j < 3; j++)
+ {
+ if (face[j] > mNumVertices - 1)
+ {
+ mNumVertices = face[j] + 1;
+ }
+ }
+ }
+ mFaces[i][0] = face[0];
+ mFaces[i][1] = face[1];
+ mFaces[i][2] = face[2];
+
+// S32 j;
+// for(j = 0; j < 3; j++)
+// {
+// std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
+// if (!face_list)
+// {
+// face_list = new std::vector<S32>;
+// mVertFaceMap.addData(face[j], face_list);
+// }
+// face_list->put(i);
+// }
+
+ numTris++;
+ }
+
+ LL_DEBUGS() << "verts: " << numVertices
+ << ", faces: " << numFaces
+ << ", tris: " << numTris
+ << LL_ENDL;
+
+ //----------------------------------------------------------------
+ // NumSkinJoints
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ U16 numSkinJoints = 0;
+ if ( mHasWeights )
+ {
+ numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
+ llendianswizzle(&numSkinJoints, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL;
+ return false;
+ }
+ allocateJointNames( numSkinJoints );
+ }
+
+ //----------------------------------------------------------------
+ // SkinJoints
+ //----------------------------------------------------------------
+ for (i=0; i < numSkinJoints; i++)
+ {
+ char jointName[64+1];
+ numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
+ jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
+ if (numRead != 1)
+ {
+ LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL;
+ return false;
+ }
+
+ std::string *jn = &mJointNames[i];
+ *jn = jointName;
+ }
+
+ //-------------------------------------------------------------------------
+ // look for morph section
+ //-------------------------------------------------------------------------
+ char morphName[64+1];
+ morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
+ while(fread(&morphName, sizeof(char), 64, fp) == 64)
+ {
+ if (!strcmp(morphName, "End Morphs"))
+ {
+ // we reached the end of the morphs
+ break;
+ }
+ std::string morph_name(morphName);
+ LLPolyMorphData* morph_data = new LLPolyMorphData(morph_name);
+
+ bool result = morph_data->loadBinary(fp, this);
+
+ if (!result)
+ {
+ LL_WARNS() << "Failure loading " << morph_name << " from " << fileName << LL_ENDL;
+ delete morph_data;
+ continue;
+ }
+
+ mMorphData.insert(morph_data);
+
+ if (!strcmp(morphName, "Breast_Female_Cleavage"))
+ {
+ mMorphData.insert(clone_morph_param_cleavage(morph_data,
+ .75f,
+ "Breast_Physics_LeftRight_Driven"));
+ }
+
+ if (!strcmp(morphName, "Breast_Female_Cleavage"))
+ {
+ mMorphData.insert(clone_morph_param_duplicate(morph_data,
+ "Breast_Physics_InOut_Driven"));
+ }
+ if (!strcmp(morphName, "Breast_Gravity"))
+ {
+ mMorphData.insert(clone_morph_param_duplicate(morph_data,
+ "Breast_Physics_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Big_Belly_Torso"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Torso_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Big_Belly_Legs"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Legs_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "skirt_belly"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Skirt_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Small_Butt"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Butt_Physics_UpDown_Driven"));
+ }
+ if (!strcmp(morphName, "Small_Butt"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0.03f,0),
+ "Butt_Physics_LeftRight_Driven"));
+ }
+ }
+
+ S32 numRemaps;
+ if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
+ {
+ llendianswizzle(&numRemaps, sizeof(S32), 1);
+ for (S32 i = 0; i < numRemaps; i++)
+ {
+ S32 remapSrc;
+ S32 remapDst;
+ if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
+ {
+ LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL;
+ break;
+ }
+ if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
+ {
+ LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL;
+ break;
+ }
+ llendianswizzle(&remapSrc, sizeof(S32), 1);
+ llendianswizzle(&remapDst, sizeof(S32), 1);
+
+ mSharedVerts[remapSrc] = remapDst;
+ }
+ }
+ }
+
+ status = true;
+ }
+ else
+ {
+ LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL;
+ status = false;
+ }
+
+ if (0 == mNumJointNames)
+ {
+ allocateJointNames(1);
+ }
+
+ fclose( fp );
+
+ return status;
+}
+
+//-----------------------------------------------------------------------------
+// getSharedVert()
+//-----------------------------------------------------------------------------
+const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
+{
+ if (mSharedVerts.count(vert) > 0)
+ {
+ return &mSharedVerts[vert];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getUV()
+//-----------------------------------------------------------------------------
+const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
+{
+ // TODO: convert all index variables to S32
+ llassert((S32)index < mNumVertices);
+
+ return mTexCoords[index];
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
+{
+ llassert(shared_data);
+
+ mSharedData = shared_data;
+ mReferenceMesh = reference_mesh;
+ mAvatarp = NULL;
+ mVertexData = NULL;
+
+ mCurVertexCount = 0;
+ mFaceIndexCount = 0;
+ mFaceIndexOffset = 0;
+ mFaceVertexCount = 0;
+ mFaceVertexOffset = 0;
+
+ if (shared_data->isLOD() && reference_mesh)
+ {
+ mCoords = reference_mesh->mCoords;
+ mNormals = reference_mesh->mNormals;
+ mScaledNormals = reference_mesh->mScaledNormals;
+ mBinormals = reference_mesh->mBinormals;
+ mScaledBinormals = reference_mesh->mScaledBinormals;
+ mTexCoords = reference_mesh->mTexCoords;
+ mClothingWeights = reference_mesh->mClothingWeights;
+ }
+ else
+ {
+ // Allocate memory without initializing every vector
+ // NOTE: This makes asusmptions about the size of LLVector[234]
+ S32 nverts = mSharedData->mNumVertices;
+ //make sure it's an even number of verts for alignment
+ nverts += nverts%2;
+ S32 nfloats = nverts * (
+ 4 + //coords
+ 4 + //normals
+ 4 + //weights
+ 2 + //coords
+ 4 + //scaled normals
+ 4 + //binormals
+ 4); //scaled binormals
+
+ //use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
+ mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
+ S32 offset = 0;
+ mCoords = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ mNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ mClothingWeights = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
+ mScaledNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ mBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ mScaledBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+ initializeForMorph();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::~LLPolyMesh()
+{
+ delete_and_clear(mJointRenderData);
+ ll_aligned_free_16(mVertexData);
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::getMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
+{
+ //-------------------------------------------------------------------------
+ // search for an existing mesh by this name
+ //-------------------------------------------------------------------------
+ LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
+ if (meshSharedData)
+ {
+// LL_INFOS() << "Polymesh " << name << " found in global mesh table." << LL_ENDL;
+ LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
+ return poly_mesh;
+ }
+
+ //-------------------------------------------------------------------------
+ // if not found, create a new one, add it to the list
+ //-------------------------------------------------------------------------
+ std::string full_path;
+ full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
+
+ LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
+ if (reference_mesh)
+ {
+ mesh_data->setupLOD(reference_mesh->getSharedData());
+ }
+ if ( ! mesh_data->loadMesh( full_path ) )
+ {
+ delete mesh_data;
+ return NULL;
+ }
+
+ LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
+
+// LL_INFOS() << "Polymesh " << name << " added to global mesh table." << LL_ENDL;
+ sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
+
+ return poly_mesh;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::freeAllMeshes()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::freeAllMeshes()
+{
+ // delete each item in the global lists
+ for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
+ sGlobalSharedMeshList.clear();
+}
+
+LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
+{
+ return mSharedData;
+}
+
+
+//--------------------------------------------------------------------
+// LLPolyMesh::dumpDiagInfo()
+//--------------------------------------------------------------------
+void LLPolyMesh::dumpDiagInfo()
+{
+ // keep track of totals
+ U32 total_verts = 0;
+ U32 total_faces = 0;
+ U32 total_kb = 0;
+
+ std::string buf;
+
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+ LL_INFOS() << " Global PolyMesh Table (DEBUG only)" << LL_ENDL;
+ LL_INFOS() << " Verts Faces Mem(KB) Name" << LL_ENDL;
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+
+ // print each loaded mesh, and it's memory usage
+ for(const LLPolyMeshSharedDataTable::value_type& mesh_pair : sGlobalSharedMeshList)
+ {
+ const std::string& mesh_name = mesh_pair.first;
+ LLPolyMeshSharedData* mesh = mesh_pair.second;
+
+ S32 num_verts = mesh->mNumVertices;
+ S32 num_faces = mesh->mNumFaces;
+ U32 num_kb = mesh->getNumKB();
+
+ buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
+ LL_INFOS() << buf << LL_ENDL;
+
+ total_verts += num_verts;
+ total_faces += num_faces;
+ total_kb += num_kb;
+ }
+
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+ buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
+ LL_INFOS() << buf << LL_ENDL;
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableCoords()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableCoords()
+{
+ return mCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableNormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableNormals()
+{
+ return mNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableBinormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableBinormals()
+{
+ return mBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// getWritableClothingWeights()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableClothingWeights()
+{
+ return mClothingWeights;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableTexCoords()
+//-----------------------------------------------------------------------------
+LLVector2 *LLPolyMesh::getWritableTexCoords()
+{
+ return mTexCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledNormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getScaledNormals()
+{
+ return mScaledNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledBinormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getScaledBinormals()
+{
+ return mScaledBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// initializeForMorph()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::initializeForMorph()
+{
+ LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
+
+ for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
+ {
+ mClothingWeights[i].clear();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
+{
+ if (!mSharedData)
+ return NULL;
+ for (LLPolyMorphData* morph_data : mSharedData->mMorphData)
+ {
+ if (morph_data->getName() == morph_name)
+ {
+ return morph_data;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// removeMorphData()
+//-----------------------------------------------------------------------------
+// // erasing but not deleting seems bad, but fortunately we don't actually use this...
+// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
+// {
+// if (!mSharedData)
+// return;
+// mSharedData->mMorphData.erase(morph_target);
+// }
+
+//-----------------------------------------------------------------------------
+// deleteAllMorphData()
+//-----------------------------------------------------------------------------
+// void LLPolyMesh::deleteAllMorphData()
+// {
+// if (!mSharedData)
+// return;
+
+// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
+// mSharedData->mMorphData.clear();
+// }
+
+//-----------------------------------------------------------------------------
+// getWritableWeights()
+//-----------------------------------------------------------------------------
+F32* LLPolyMesh::getWritableWeights() const
+{
+ return mSharedData->mWeights;
+}
+
+// End
diff --git a/indra/llappearance/llpolymesh.h b/indra/llappearance/llpolymesh.h
index e0822bf0e7..d3b349c987 100644
--- a/indra/llappearance/llpolymesh.h
+++ b/indra/llappearance/llpolymesh.h
@@ -1,368 +1,368 @@
-/**
- * @file llpolymesh.h
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPOLYMESHINTERFACE_H
-#define LL_LLPOLYMESHINTERFACE_H
-
-#include <string>
-#include <map>
-#include "llstl.h"
-
-#include "v3math.h"
-#include "v2math.h"
-#include "llquaternion.h"
-#include "llpolymorph.h"
-#include "lljoint.h"
-
-class LLSkinJoint;
-class LLAvatarAppearance;
-class LLWearable;
-
-//#define USE_STRIPS // Use tri-strips for rendering.
-
-//-----------------------------------------------------------------------------
-// LLPolyFace
-// A set of 4 vertex indices.
-// An LLPolyFace can represent either a triangle or quad.
-// If the last index is -1, it's a triangle.
-//-----------------------------------------------------------------------------
-typedef S32 LLPolyFace[3];
-
-//struct PrimitiveGroup;
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh
-// A polyhedra consisting of any number of triangles and quads.
-// All instances contain a set of faces, and optionally may include
-// faces grouped into named face sets.
-//-----------------------------------------------------------------------------
-class LLPolyMorphTarget;
-
-class LLPolyMeshSharedData
-{
- friend class LLPolyMesh;
-private:
- // transform data
- LLVector3 mPosition;
- LLQuaternion mRotation;
- LLVector3 mScale;
-
- // vertex data
- S32 mNumVertices;
- LLVector4a *mBaseCoords;
- LLVector4a *mBaseNormals;
- LLVector4a *mBaseBinormals;
- LLVector2 *mTexCoords;
- LLVector2 *mDetailTexCoords;
- F32 *mWeights;
-
- bool mHasWeights;
- bool mHasDetailTexCoords;
-
- // face data
- S32 mNumFaces;
- LLPolyFace *mFaces;
-
- // face set data
- U32 mNumJointNames;
- std::string* mJointNames;
-
- // morph targets
- typedef std::set<LLPolyMorphData*> morphdata_list_t;
- morphdata_list_t mMorphData;
-
- std::map<S32, S32> mSharedVerts;
-
- LLPolyMeshSharedData* mReferenceData;
- S32 mLastIndexOffset;
-
-public:
- // Temporarily...
- // Triangle indices
- U32 mNumTriangleIndices;
- U32 *mTriangleIndices;
-
-public:
- LLPolyMeshSharedData();
- ~LLPolyMeshSharedData();
-
-private:
- void setupLOD(LLPolyMeshSharedData* reference_data);
-
- // Frees all mesh memory resources
- void freeMeshData();
-
- void setPosition( const LLVector3 &pos ) { mPosition = pos; }
- void setRotation( const LLQuaternion &rot ) { mRotation = rot; }
- void setScale( const LLVector3 &scale ) { mScale = scale; }
-
- bool allocateVertexData( U32 numVertices );
-
- bool allocateFaceData( U32 numFaces );
-
- bool allocateJointNames( U32 numJointNames );
-
- // Retrieve the number of KB of memory used by this instance
- U32 getNumKB();
-
- // Load mesh data from file
- bool loadMesh( const std::string& fileName );
-
-public:
- void genIndices(S32 offset);
-
- const LLVector2 &getUVs(U32 index);
-
- const S32 *getSharedVert(S32 vert);
-
- bool isLOD() { return (mReferenceData != NULL); }
-};
-
-
-class LLJointRenderData
-{
-public:
- LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {}
- ~LLJointRenderData(){}
-
- const LLMatrix4* mWorldMatrix;
- LLSkinJoint* mSkinJoint;
-};
-
-
-class LLPolyMesh
-{
-public:
-
- // Constructor
- LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh);
-
- // Destructor
- ~LLPolyMesh();
-
- // Requests a mesh by name.
- // If the mesh already exists in the global mesh table, it is returned,
- // otherwise it is loaded from file, added to the table, and returned.
- static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL);
-
- // Frees all loaded meshes.
- // This should only be called once you know there are no outstanding
- // references to these objects. Generally, upon exit of the application.
- static void freeAllMeshes();
-
- //--------------------------------------------------------------------
- // Transform Data Access
- //--------------------------------------------------------------------
- // Get position
- const LLVector3 &getPosition() {
- llassert (mSharedData);
- return mSharedData->mPosition;
- }
-
- // Get rotation
- const LLQuaternion &getRotation() {
- llassert (mSharedData);
- return mSharedData->mRotation;
- }
-
- // Get scale
- const LLVector3 &getScale() {
- llassert (mSharedData);
- return mSharedData->mScale;
- }
-
- //--------------------------------------------------------------------
- // Vertex Data Access
- //--------------------------------------------------------------------
- // Get number of vertices
- U32 getNumVertices() {
- llassert (mSharedData);
- return mSharedData->mNumVertices;
- }
-
- // Returns whether or not the mesh has detail texture coords
- bool hasDetailTexCoords() {
- llassert (mSharedData);
- return mSharedData->mHasDetailTexCoords;
- }
-
- // Returns whether or not the mesh has vertex weights
- bool hasWeights() const{
- llassert (mSharedData);
- return mSharedData->mHasWeights;
- }
-
- // Get coords
- const LLVector4a *getCoords() const{
- return mCoords;
- }
-
- // non const version
- LLVector4a *getWritableCoords();
-
- // Get normals
- const LLVector4a *getNormals() const{
- return mNormals;
- }
-
- // Get normals
- const LLVector4a *getBinormals() const{
- return mBinormals;
- }
-
- // Get base mesh normals
- const LLVector4a *getBaseNormals() const{
- llassert(mSharedData);
- return mSharedData->mBaseNormals;
- }
-
- // Get base mesh normals
- const LLVector4a *getBaseBinormals() const{
- llassert(mSharedData);
- return mSharedData->mBaseBinormals;
- }
-
- // intermediate morphed normals and output normals
- LLVector4a *getWritableNormals();
- LLVector4a *getScaledNormals();
-
- LLVector4a *getWritableBinormals();
- LLVector4a *getScaledBinormals();
-
- // Get texCoords
- const LLVector2 *getTexCoords() const {
- return mTexCoords;
- }
-
- // non const version
- LLVector2 *getWritableTexCoords();
-
- // Get detailTexCoords
- const LLVector2 *getDetailTexCoords() const {
- llassert (mSharedData);
- return mSharedData->mDetailTexCoords;
- }
-
- // Get weights
- const F32 *getWeights() const {
- llassert (mSharedData);
- return mSharedData->mWeights;
- }
-
- F32 *getWritableWeights() const;
-
- LLVector4a *getWritableClothingWeights();
-
- const LLVector4a *getClothingWeights()
- {
- return mClothingWeights;
- }
-
- //--------------------------------------------------------------------
- // Face Data Access
- //--------------------------------------------------------------------
- // Get number of faces
- S32 getNumFaces() {
- llassert (mSharedData);
- return mSharedData->mNumFaces;
- }
-
- // Get faces
- LLPolyFace *getFaces() {
- llassert (mSharedData);
- return mSharedData->mFaces;
- }
-
- U32 getNumJointNames() {
- llassert (mSharedData);
- return mSharedData->mNumJointNames;
- }
-
- std::string *getJointNames() {
- llassert (mSharedData);
- return mSharedData->mJointNames;
- }
-
- LLPolyMorphData* getMorphData(const std::string& morph_name);
-// void removeMorphData(LLPolyMorphData *morph_target);
-// void deleteAllMorphData();
-
- LLPolyMeshSharedData *getSharedData() const;
- LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; }
-
- // Get indices
- U32* getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; }
-
- bool isLOD() { return mSharedData && mSharedData->isLOD(); }
-
- void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; }
- LLAvatarAppearance* getAvatar() { return mAvatarp; }
-
- std::vector<LLJointRenderData*> mJointRenderData;
-
- U32 mFaceVertexOffset;
- U32 mFaceVertexCount;
- U32 mFaceIndexOffset;
- U32 mFaceIndexCount;
- U32 mCurVertexCount;
-private:
- void initializeForMorph();
-
- // Dumps diagnostic information about the global mesh table
- static void dumpDiagInfo();
-
-protected:
- // mesh data shared across all instances of a given mesh
- LLPolyMeshSharedData *mSharedData;
- // Single array of floats for allocation / deletion
- F32 *mVertexData;
- // deformed vertices (resulting from application of morph targets)
- LLVector4a *mCoords;
- // deformed normals (resulting from application of morph targets)
- LLVector4a *mScaledNormals;
- // output normals (after normalization)
- LLVector4a *mNormals;
- // deformed binormals (resulting from application of morph targets)
- LLVector4a *mScaledBinormals;
- // output binormals (after normalization)
- LLVector4a *mBinormals;
- // weight values that mark verts as clothing/skin
- LLVector4a *mClothingWeights;
- // output texture coordinates
- LLVector2 *mTexCoords;
-
- LLPolyMesh *mReferenceMesh;
-
- // global mesh list
- typedef std::map<std::string, LLPolyMeshSharedData*> LLPolyMeshSharedDataTable;
- static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
-
- // Backlink only; don't make this an LLPointer.
- LLAvatarAppearance* mAvatarp;
-};
-
-#endif // LL_LLPOLYMESHINTERFACE_H
-
+/**
+ * @file llpolymesh.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYMESHINTERFACE_H
+#define LL_LLPOLYMESHINTERFACE_H
+
+#include <string>
+#include <map>
+#include "llstl.h"
+
+#include "v3math.h"
+#include "v2math.h"
+#include "llquaternion.h"
+#include "llpolymorph.h"
+#include "lljoint.h"
+
+class LLSkinJoint;
+class LLAvatarAppearance;
+class LLWearable;
+
+//#define USE_STRIPS // Use tri-strips for rendering.
+
+//-----------------------------------------------------------------------------
+// LLPolyFace
+// A set of 4 vertex indices.
+// An LLPolyFace can represent either a triangle or quad.
+// If the last index is -1, it's a triangle.
+//-----------------------------------------------------------------------------
+typedef S32 LLPolyFace[3];
+
+//struct PrimitiveGroup;
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh
+// A polyhedra consisting of any number of triangles and quads.
+// All instances contain a set of faces, and optionally may include
+// faces grouped into named face sets.
+//-----------------------------------------------------------------------------
+class LLPolyMorphTarget;
+
+class LLPolyMeshSharedData
+{
+ friend class LLPolyMesh;
+private:
+ // transform data
+ LLVector3 mPosition;
+ LLQuaternion mRotation;
+ LLVector3 mScale;
+
+ // vertex data
+ S32 mNumVertices;
+ LLVector4a *mBaseCoords;
+ LLVector4a *mBaseNormals;
+ LLVector4a *mBaseBinormals;
+ LLVector2 *mTexCoords;
+ LLVector2 *mDetailTexCoords;
+ F32 *mWeights;
+
+ bool mHasWeights;
+ bool mHasDetailTexCoords;
+
+ // face data
+ S32 mNumFaces;
+ LLPolyFace *mFaces;
+
+ // face set data
+ U32 mNumJointNames;
+ std::string* mJointNames;
+
+ // morph targets
+ typedef std::set<LLPolyMorphData*> morphdata_list_t;
+ morphdata_list_t mMorphData;
+
+ std::map<S32, S32> mSharedVerts;
+
+ LLPolyMeshSharedData* mReferenceData;
+ S32 mLastIndexOffset;
+
+public:
+ // Temporarily...
+ // Triangle indices
+ U32 mNumTriangleIndices;
+ U32 *mTriangleIndices;
+
+public:
+ LLPolyMeshSharedData();
+ ~LLPolyMeshSharedData();
+
+private:
+ void setupLOD(LLPolyMeshSharedData* reference_data);
+
+ // Frees all mesh memory resources
+ void freeMeshData();
+
+ void setPosition( const LLVector3 &pos ) { mPosition = pos; }
+ void setRotation( const LLQuaternion &rot ) { mRotation = rot; }
+ void setScale( const LLVector3 &scale ) { mScale = scale; }
+
+ bool allocateVertexData( U32 numVertices );
+
+ bool allocateFaceData( U32 numFaces );
+
+ bool allocateJointNames( U32 numJointNames );
+
+ // Retrieve the number of KB of memory used by this instance
+ U32 getNumKB();
+
+ // Load mesh data from file
+ bool loadMesh( const std::string& fileName );
+
+public:
+ void genIndices(S32 offset);
+
+ const LLVector2 &getUVs(U32 index);
+
+ const S32 *getSharedVert(S32 vert);
+
+ bool isLOD() { return (mReferenceData != NULL); }
+};
+
+
+class LLJointRenderData
+{
+public:
+ LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {}
+ ~LLJointRenderData(){}
+
+ const LLMatrix4* mWorldMatrix;
+ LLSkinJoint* mSkinJoint;
+};
+
+
+class LLPolyMesh
+{
+public:
+
+ // Constructor
+ LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh);
+
+ // Destructor
+ ~LLPolyMesh();
+
+ // Requests a mesh by name.
+ // If the mesh already exists in the global mesh table, it is returned,
+ // otherwise it is loaded from file, added to the table, and returned.
+ static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL);
+
+ // Frees all loaded meshes.
+ // This should only be called once you know there are no outstanding
+ // references to these objects. Generally, upon exit of the application.
+ static void freeAllMeshes();
+
+ //--------------------------------------------------------------------
+ // Transform Data Access
+ //--------------------------------------------------------------------
+ // Get position
+ const LLVector3 &getPosition() {
+ llassert (mSharedData);
+ return mSharedData->mPosition;
+ }
+
+ // Get rotation
+ const LLQuaternion &getRotation() {
+ llassert (mSharedData);
+ return mSharedData->mRotation;
+ }
+
+ // Get scale
+ const LLVector3 &getScale() {
+ llassert (mSharedData);
+ return mSharedData->mScale;
+ }
+
+ //--------------------------------------------------------------------
+ // Vertex Data Access
+ //--------------------------------------------------------------------
+ // Get number of vertices
+ U32 getNumVertices() {
+ llassert (mSharedData);
+ return mSharedData->mNumVertices;
+ }
+
+ // Returns whether or not the mesh has detail texture coords
+ bool hasDetailTexCoords() {
+ llassert (mSharedData);
+ return mSharedData->mHasDetailTexCoords;
+ }
+
+ // Returns whether or not the mesh has vertex weights
+ bool hasWeights() const{
+ llassert (mSharedData);
+ return mSharedData->mHasWeights;
+ }
+
+ // Get coords
+ const LLVector4a *getCoords() const{
+ return mCoords;
+ }
+
+ // non const version
+ LLVector4a *getWritableCoords();
+
+ // Get normals
+ const LLVector4a *getNormals() const{
+ return mNormals;
+ }
+
+ // Get normals
+ const LLVector4a *getBinormals() const{
+ return mBinormals;
+ }
+
+ // Get base mesh normals
+ const LLVector4a *getBaseNormals() const{
+ llassert(mSharedData);
+ return mSharedData->mBaseNormals;
+ }
+
+ // Get base mesh normals
+ const LLVector4a *getBaseBinormals() const{
+ llassert(mSharedData);
+ return mSharedData->mBaseBinormals;
+ }
+
+ // intermediate morphed normals and output normals
+ LLVector4a *getWritableNormals();
+ LLVector4a *getScaledNormals();
+
+ LLVector4a *getWritableBinormals();
+ LLVector4a *getScaledBinormals();
+
+ // Get texCoords
+ const LLVector2 *getTexCoords() const {
+ return mTexCoords;
+ }
+
+ // non const version
+ LLVector2 *getWritableTexCoords();
+
+ // Get detailTexCoords
+ const LLVector2 *getDetailTexCoords() const {
+ llassert (mSharedData);
+ return mSharedData->mDetailTexCoords;
+ }
+
+ // Get weights
+ const F32 *getWeights() const {
+ llassert (mSharedData);
+ return mSharedData->mWeights;
+ }
+
+ F32 *getWritableWeights() const;
+
+ LLVector4a *getWritableClothingWeights();
+
+ const LLVector4a *getClothingWeights()
+ {
+ return mClothingWeights;
+ }
+
+ //--------------------------------------------------------------------
+ // Face Data Access
+ //--------------------------------------------------------------------
+ // Get number of faces
+ S32 getNumFaces() {
+ llassert (mSharedData);
+ return mSharedData->mNumFaces;
+ }
+
+ // Get faces
+ LLPolyFace *getFaces() {
+ llassert (mSharedData);
+ return mSharedData->mFaces;
+ }
+
+ U32 getNumJointNames() {
+ llassert (mSharedData);
+ return mSharedData->mNumJointNames;
+ }
+
+ std::string *getJointNames() {
+ llassert (mSharedData);
+ return mSharedData->mJointNames;
+ }
+
+ LLPolyMorphData* getMorphData(const std::string& morph_name);
+// void removeMorphData(LLPolyMorphData *morph_target);
+// void deleteAllMorphData();
+
+ LLPolyMeshSharedData *getSharedData() const;
+ LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; }
+
+ // Get indices
+ U32* getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; }
+
+ bool isLOD() { return mSharedData && mSharedData->isLOD(); }
+
+ void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; }
+ LLAvatarAppearance* getAvatar() { return mAvatarp; }
+
+ std::vector<LLJointRenderData*> mJointRenderData;
+
+ U32 mFaceVertexOffset;
+ U32 mFaceVertexCount;
+ U32 mFaceIndexOffset;
+ U32 mFaceIndexCount;
+ U32 mCurVertexCount;
+private:
+ void initializeForMorph();
+
+ // Dumps diagnostic information about the global mesh table
+ static void dumpDiagInfo();
+
+protected:
+ // mesh data shared across all instances of a given mesh
+ LLPolyMeshSharedData *mSharedData;
+ // Single array of floats for allocation / deletion
+ F32 *mVertexData;
+ // deformed vertices (resulting from application of morph targets)
+ LLVector4a *mCoords;
+ // deformed normals (resulting from application of morph targets)
+ LLVector4a *mScaledNormals;
+ // output normals (after normalization)
+ LLVector4a *mNormals;
+ // deformed binormals (resulting from application of morph targets)
+ LLVector4a *mScaledBinormals;
+ // output binormals (after normalization)
+ LLVector4a *mBinormals;
+ // weight values that mark verts as clothing/skin
+ LLVector4a *mClothingWeights;
+ // output texture coordinates
+ LLVector2 *mTexCoords;
+
+ LLPolyMesh *mReferenceMesh;
+
+ // global mesh list
+ typedef std::map<std::string, LLPolyMeshSharedData*> LLPolyMeshSharedDataTable;
+ static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
+
+ // Backlink only; don't make this an LLPointer.
+ LLAvatarAppearance* mAvatarp;
+};
+
+#endif // LL_LLPOLYMESHINTERFACE_H
+
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index 4b94ed48b1..8665ac2433 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -1,844 +1,844 @@
-/**
- * @file llpolymorph.cpp
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-
-#include "llpolymorph.h"
-#include "llavatarappearance.h"
-#include "llavatarjoint.h"
-#include "llwearable.h"
-#include "llxmltree.h"
-#include "llendianswizzle.h"
-#include "llpolymesh.h"
-#include "llfasttimer.h"
-
-//#include "../tools/imdebug/imdebug.h"
-
-const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphData()
-//-----------------------------------------------------------------------------
-LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
- : mName(morph_name)
-{
- mNumIndices = 0;
- mCurrentIndex = 0;
- mTotalDistortion = 0.f;
- mAvgDistortion.clear();
- mMaxDistortion = 0.f;
- mVertexIndices = NULL;
- mCoords = NULL;
- mNormals = NULL;
- mBinormals = NULL;
- mTexCoords = NULL;
-
- mMesh = NULL;
-}
-
-LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
- mName(rhs.mName),
- mNumIndices(rhs.mNumIndices),
- mTotalDistortion(rhs.mTotalDistortion),
- mAvgDistortion(rhs.mAvgDistortion),
- mMaxDistortion(rhs.mMaxDistortion),
- mVertexIndices(NULL),
- mCoords(NULL),
- mNormals(NULL),
- mBinormals(NULL),
- mTexCoords(NULL)
-{
- const S32 numVertices = mNumIndices;
-
- U32 size = sizeof(LLVector4a)*numVertices;
-
- mCoords = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
- mNormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
- mBinormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
- mTexCoords = new LLVector2[numVertices];
- mVertexIndices = new U32[numVertices];
-
- for (S32 v=0; v < numVertices; v++)
- {
- mCoords[v] = rhs.mCoords[v];
- mNormals[v] = rhs.mNormals[v];
- mBinormals[v] = rhs.mBinormals[v];
- mTexCoords[v] = rhs.mTexCoords[v];
- mVertexIndices[v] = rhs.mVertexIndices[v];
- }
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMorphData()
-//-----------------------------------------------------------------------------
-LLPolyMorphData::~LLPolyMorphData()
-{
- freeData();
-}
-
-//-----------------------------------------------------------------------------
-// loadBinary()
-//-----------------------------------------------------------------------------
-bool LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
-{
- S32 numVertices;
- S32 numRead;
-
- numRead = fread(&numVertices, sizeof(S32), 1, fp);
- llendianswizzle(&numVertices, sizeof(S32), 1);
- if (numRead != 1)
- {
- LL_WARNS() << "Can't read number of morph target vertices" << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // free any existing data
- //-------------------------------------------------------------------------
- freeData();
-
- //-------------------------------------------------------------------------
- // allocate vertices
- //-------------------------------------------------------------------------
-
- U32 size = sizeof(LLVector4a)*numVertices;
-
- mCoords = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
- mNormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
- mBinormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
-
- mTexCoords = new LLVector2[numVertices];
- // Actually, we are allocating more space than we need for the skiplist
- mVertexIndices = new U32[numVertices];
- mNumIndices = 0;
- mTotalDistortion = 0.f;
- mMaxDistortion = 0.f;
- mAvgDistortion.clear();
- mMesh = mesh;
-
- //-------------------------------------------------------------------------
- // read vertices
- //-------------------------------------------------------------------------
- for(S32 v = 0; v < numVertices; v++)
- {
- numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
- llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
- if (numRead != 1)
- {
- LL_WARNS() << "Can't read morph target vertex number" << LL_ENDL;
- return false;
- }
-
- if (mVertexIndices[v] > 10000)
- {
- // Bad install? These are usually .llm files from 'character' fodler
- LL_WARNS() << "Bad morph index " << v << ": " << mVertexIndices[v] << LL_ENDL;
- return false;
- }
-
-
- numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
- llendianswizzle(&mCoords[v], sizeof(F32), 3);
- if (numRead != 3)
- {
- LL_WARNS() << "Can't read morph target vertex coordinates" << LL_ENDL;
- return false;
- }
-
- F32 magnitude = mCoords[v].getLength3().getF32();
-
- mTotalDistortion += magnitude;
- LLVector4a t;
- t.setAbs(mCoords[v]);
- mAvgDistortion.add(t);
-
- if (magnitude > mMaxDistortion)
- {
- mMaxDistortion = magnitude;
- }
-
- numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
- llendianswizzle(&mNormals[v], sizeof(F32), 3);
- if (numRead != 3)
- {
- LL_WARNS() << "Can't read morph target normal" << LL_ENDL;
- return false;
- }
-
- numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
- llendianswizzle(&mBinormals[v], sizeof(F32), 3);
- if (numRead != 3)
- {
- LL_WARNS() << "Can't read morph target binormal" << LL_ENDL;
- return false;
- }
-
-
- numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
- llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
- if (numRead != 2)
- {
- LL_WARNS() << "Can't read morph target uv" << LL_ENDL;
- return false;
- }
-
- mNumIndices++;
- }
-
- mAvgDistortion.mul(1.f/(F32)mNumIndices);
- mAvgDistortion.normalize3fast();
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// freeData()
-//-----------------------------------------------------------------------------
-void LLPolyMorphData::freeData()
-{
- if (mCoords != NULL)
- {
- ll_aligned_free_16(mCoords);
- mCoords = NULL;
- }
-
- if (mNormals != NULL)
- {
- ll_aligned_free_16(mNormals);
- mNormals = NULL;
- }
-
- if (mBinormals != NULL)
- {
- ll_aligned_free_16(mBinormals);
- mBinormals = NULL;
- }
-
- if (mTexCoords != NULL)
- {
- delete [] mTexCoords;
- mTexCoords = NULL;
- }
-
- if (mVertexIndices != NULL)
- {
- delete [] mVertexIndices;
- mVertexIndices = NULL;
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTargetInfo()
-//-----------------------------------------------------------------------------
-LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
- : mIsClothingMorph(false)
-{
-}
-
-bool LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
-
- if (!LLViewerVisualParamInfo::parseXml(node))
- return false;
-
- // Get mixed-case name
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if( !node->getFastAttributeString( name_string, mMorphName ) )
- {
- LL_WARNS() << "Avatar file: <param> is missing name attribute" << LL_ENDL;
- return false; // Continue, ignoring this tag
- }
-
- static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
- node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
-
- LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
-
- if (NULL == paramNode)
- {
- LL_WARNS() << "Failed to getChildByName(\"param_morph\")"
- << LL_ENDL;
- return false;
- }
-
- for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
- child_node;
- child_node = paramNode->getNextChild())
- {
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (child_node->hasName("volume_morph"))
- {
- std::string volume_name;
- if (child_node->getFastAttributeString(name_string, volume_name))
- {
- LLVector3 scale;
- static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
- child_node->getFastAttributeVector3(scale_string, scale);
-
- LLVector3 pos;
- static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
- child_node->getFastAttributeVector3(pos_string, pos);
-
- mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
- }
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTarget()
-//-----------------------------------------------------------------------------
-LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
- : LLViewerVisualParam(),
- mMorphData(NULL),
- mMesh(poly_mesh),
- mVertMask(NULL),
- mLastSex(SEX_FEMALE),
- mNumMorphMasksPending(0),
- mVolumeMorphs()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTarget()
-//-----------------------------------------------------------------------------
-LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther)
- : LLViewerVisualParam(pOther),
- mMorphData(pOther.mMorphData),
- mMesh(pOther.mMesh),
- mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)),
- mLastSex(pOther.mLastSex),
- mNumMorphMasksPending(pOther.mNumMorphMasksPending),
- mVolumeMorphs(pOther.mVolumeMorphs)
-{
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMorphTarget()
-//-----------------------------------------------------------------------------
-LLPolyMorphTarget::~LLPolyMorphTarget()
-{
- delete mVertMask;
- mVertMask = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// setInfo()
-//-----------------------------------------------------------------------------
-bool LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
-{
- llassert(mInfo == NULL);
- if (info->mID < 0)
- return false;
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight());
-
- LLAvatarAppearance* avatarp = mMesh->getAvatar();
- for (LLPolyVolumeMorphInfo& volume_info : getInfo()->mVolumeInfoList)
- {
- for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
- {
- if (avatarp->mCollisionVolumes[i].getName() == volume_info.mName)
- {
- mVolumeMorphs.push_back(
- LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
- volume_info.mScale,
- volume_info.mPos));
- break;
- }
- }
- }
-
- std::string morph_param_name = getInfo()->mMorphName;
-
- mMorphData = mMesh->getMorphData(morph_param_name);
- if (!mMorphData)
- {
- const std::string driven_tag = "_Driven";
- U32 pos = morph_param_name.find(driven_tag);
- if (pos > 0)
- {
- morph_param_name = morph_param_name.substr(0,pos);
- mMorphData = mMesh->getMorphData(morph_param_name);
- }
- }
- if (!mMorphData)
- {
- LL_WARNS() << "No morph target named " << morph_param_name << " found in mesh." << LL_ENDL;
- return false; // Continue, ignoring this tag
- }
- return true;
-}
-
-/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
-{
- return new LLPolyMorphTarget(*this);
-}
-
-#if 0 // obsolete
-//-----------------------------------------------------------------------------
-// parseData()
-//-----------------------------------------------------------------------------
-bool LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
-{
- LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
-
- info->parseXml(node);
- if (!setInfo(info))
- {
- delete info;
- return false;
- }
- return true;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// getVertexDistortion()
-//-----------------------------------------------------------------------------
-LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
-{
- if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
-
- for(U32 index = 0; index < mMorphData->mNumIndices; index++)
- {
- if (mMorphData->mVertexIndices[index] == (U32)requested_index)
- {
- return mMorphData->mCoords[index];
- }
- }
-
- return LLVector4a::getZero();
-}
-
-//-----------------------------------------------------------------------------
-// getFirstDistortion()
-//-----------------------------------------------------------------------------
-const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
-{
- if (!mMorphData) return &LLVector4a::getZero();
-
- LLVector4a* resultVec;
- mMorphData->mCurrentIndex = 0;
- if (mMorphData->mNumIndices)
- {
- resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
- if (index != NULL)
- {
- *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
- }
- if (poly_mesh != NULL)
- {
- *poly_mesh = mMesh;
- }
-
- return resultVec;
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getNextDistortion()
-//-----------------------------------------------------------------------------
-const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
-{
- if (!mMorphData) return &LLVector4a::getZero();
-
- LLVector4a* resultVec;
- mMorphData->mCurrentIndex++;
- if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
- {
- resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
- if (index != NULL)
- {
- *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
- }
- if (poly_mesh != NULL)
- {
- *poly_mesh = mMesh;
- }
- return resultVec;
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getTotalDistortion()
-//-----------------------------------------------------------------------------
-F32 LLPolyMorphTarget::getTotalDistortion()
-{
- if (mMorphData)
- {
- return mMorphData->mTotalDistortion;
- }
- else
- {
- return 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// getAvgDistortion()
-//-----------------------------------------------------------------------------
-const LLVector4a& LLPolyMorphTarget::getAvgDistortion()
-{
- if (mMorphData)
- {
- return mMorphData->mAvgDistortion;
- }
- else
- {
- return LLVector4a::getZero();
- }
-}
-
-//-----------------------------------------------------------------------------
-// getMaxDistortion()
-//-----------------------------------------------------------------------------
-F32 LLPolyMorphTarget::getMaxDistortion()
-{
- if (mMorphData)
- {
- return mMorphData->mMaxDistortion;
- }
- else
- {
- return 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// apply()
-//-----------------------------------------------------------------------------
-void LLPolyMorphTarget::apply( ESex avatar_sex )
-{
- if (!mMorphData || mNumMorphMasksPending > 0)
- {
- return;
- }
-
- LL_PROFILE_ZONE_SCOPED;
-
- mLastSex = avatar_sex;
-
- // Check for NaN condition (NaN is detected if a variable doesn't equal itself.
- if (mCurWeight != mCurWeight)
- {
- mCurWeight = 0.0;
- }
- if (mLastWeight != mLastWeight)
- {
- mLastWeight = mCurWeight+.001;
- }
-
- // perform differential update of morph
- F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
- // store last weight
- mLastWeight += delta_weight;
-
- if (delta_weight != 0.f)
- {
- llassert(!mMesh->isLOD());
- LLVector4a *coords = mMesh->getWritableCoords();
-
- LLVector4a *scaled_normals = mMesh->getScaledNormals();
- LLVector4a *normals = mMesh->getWritableNormals();
-
- LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
- LLVector4a *binormals = mMesh->getWritableBinormals();
-
- LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
- LLVector2 *tex_coords = mMesh->getWritableTexCoords();
-
- F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
-
- for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
- {
- S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
-
- F32 maskWeight = 1.f;
- if (maskWeightArray)
- {
- maskWeight = maskWeightArray[vert_index_morph];
- }
-
-
- LLVector4a pos = mMorphData->mCoords[vert_index_morph];
- pos.mul(delta_weight*maskWeight);
- coords[vert_index_mesh].add(pos);
-
- if (getInfo()->mIsClothingMorph && clothing_weights)
- {
- LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
- clothing_offset.mul(delta_weight * maskWeight);
- LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
- clothing_weight->add(clothing_offset);
- clothing_weight->getF32ptr()[VW] = maskWeight;
- }
-
- // calculate new normals based on half angles
- LLVector4a norm = mMorphData->mNormals[vert_index_morph];
- norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
- scaled_normals[vert_index_mesh].add(norm);
- norm = scaled_normals[vert_index_mesh];
-
- // guard against degenerate input data before we create NaNs below!
- //
- norm.normalize3fast();
- normals[vert_index_mesh] = norm;
-
- // calculate new binormals
- LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
-
- // guard against degenerate input data before we create NaNs below!
- //
- if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO))
- {
- binorm.set(1,0,0,1);
- }
-
- binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
- scaled_binormals[vert_index_mesh].add(binorm);
- LLVector4a tangent;
- tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
- LLVector4a& normalized_binormal = binormals[vert_index_mesh];
-
- normalized_binormal.setCross3(norm, tangent);
- normalized_binormal.normalize3fast();
-
- tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
- }
-
- // now apply volume changes
- for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
- {
- LLVector3 scale_delta = volume_morph.mScale * delta_weight;
- LLVector3 pos_delta = volume_morph.mPos * delta_weight;
-
- volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
- // SL-315
- volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
- }
- }
-
- if (mNext)
- {
- mNext->apply(avatar_sex);
- }
-}
-
-//-----------------------------------------------------------------------------
-// applyMask()
-//-----------------------------------------------------------------------------
-void LLPolyMorphTarget::applyMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert)
-{
- LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
-
- if (!mVertMask)
- {
- mVertMask = new LLPolyVertexMask(mMorphData);
- mNumMorphMasksPending--;
- }
- else
- {
- // remove effect of previous mask
- F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
-
- if (maskWeights)
- {
- LLVector4a *coords = mMesh->getWritableCoords();
- LLVector4a *scaled_normals = mMesh->getScaledNormals();
- LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
- LLVector2 *tex_coords = mMesh->getWritableTexCoords();
-
- LLVector4Logical clothing_mask;
- clothing_mask.clear();
- clothing_mask.setElement<0>();
- clothing_mask.setElement<1>();
- clothing_mask.setElement<2>();
-
-
- for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
- {
- F32 lastMaskWeight = mLastWeight * maskWeights[vert];
- S32 out_vert = mMorphData->mVertexIndices[vert];
-
- // remove effect of existing masked morph
- LLVector4a t;
- t = mMorphData->mCoords[vert];
- t.mul(lastMaskWeight);
- coords[out_vert].sub(t);
-
- t = mMorphData->mNormals[vert];
- t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
- scaled_normals[out_vert].sub(t);
-
- t = mMorphData->mBinormals[vert];
- t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
- scaled_binormals[out_vert].sub(t);
-
- tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
-
- if (clothing_weights)
- {
- LLVector4a clothing_offset = mMorphData->mCoords[vert];
- clothing_offset.mul(lastMaskWeight);
- LLVector4a* clothing_weight = &clothing_weights[out_vert];
- LLVector4a t;
- t.setSub(*clothing_weight, clothing_offset);
- clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
- }
- }
- }
- }
-
- // set last weight to 0, since we've removed the effect of this morph
- mLastWeight = 0.f;
-
- mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
-
- apply(mLastSex);
-}
-
-void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight)
-{
- // now apply volume changes
- for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
- {
- LLVector3 scale_delta = volume_morph.mScale * delta_weight;
- LLVector3 pos_delta = volume_morph.mPos * delta_weight;
-
- volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
- // SL-315
- volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyVertexMask()
-//-----------------------------------------------------------------------------
-LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
- : mWeights(new F32[morph_data->mNumIndices]),
- mMorphData(morph_data),
- mWeightsGenerated(false)
-{
- llassert(mMorphData != NULL);
- llassert(mMorphData->mNumIndices > 0);
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyVertexMask()
-//-----------------------------------------------------------------------------
-LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther)
- : mWeights(new F32[pOther.mMorphData->mNumIndices]),
- mMorphData(pOther.mMorphData),
- mWeightsGenerated(pOther.mWeightsGenerated)
-{
- llassert(mMorphData != NULL);
- llassert(mMorphData->mNumIndices > 0);
- memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices);
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolyVertexMask()
-//-----------------------------------------------------------------------------
-LLPolyVertexMask::~LLPolyVertexMask()
-{
- delete [] mWeights;
- mWeights = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// generateMask()
-//-----------------------------------------------------------------------------
-void LLPolyVertexMask::generateMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights)
-{
-// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
-// bool debugImg = false;
-// if (debugImg)
-// {
-// if (invert)
-// {
-// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
-// }
-// else
-// {
-// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
-// }
-// }
- for (U32 index = 0; index < mMorphData->mNumIndices; index++)
- {
- S32 vertIndex = mMorphData->mVertexIndices[index];
- const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
- LLVector2 uvCoords;
-
- if (sharedVertIndex)
- {
- uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
- }
- else
- {
- uvCoords = mMorphData->mMesh->getUVs(vertIndex);
- }
- U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
- U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
-
- mWeights[index] = maskTextureData ? ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f : 0.0f;
-
- if (invert)
- {
- mWeights[index] = 1.f - mWeights[index];
- }
-
- // now apply step function
- // mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
-
- if (clothing_weights)
- {
- clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
- }
- }
- mWeightsGenerated = true;
-}
-
-//-----------------------------------------------------------------------------
-// getMaskForMorphIndex()
-//-----------------------------------------------------------------------------
-F32* LLPolyVertexMask::getMorphMaskWeights()
-{
- if (!mWeightsGenerated)
- {
- return NULL;
- }
-
- return mWeights;
-}
+/**
+ * @file llpolymorph.cpp
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+
+#include "llpolymorph.h"
+#include "llavatarappearance.h"
+#include "llavatarjoint.h"
+#include "llwearable.h"
+#include "llxmltree.h"
+#include "llendianswizzle.h"
+#include "llpolymesh.h"
+#include "llfasttimer.h"
+
+//#include "../tools/imdebug/imdebug.h"
+
+const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
+ : mName(morph_name)
+{
+ mNumIndices = 0;
+ mCurrentIndex = 0;
+ mTotalDistortion = 0.f;
+ mAvgDistortion.clear();
+ mMaxDistortion = 0.f;
+ mVertexIndices = NULL;
+ mCoords = NULL;
+ mNormals = NULL;
+ mBinormals = NULL;
+ mTexCoords = NULL;
+
+ mMesh = NULL;
+}
+
+LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
+ mName(rhs.mName),
+ mNumIndices(rhs.mNumIndices),
+ mTotalDistortion(rhs.mTotalDistortion),
+ mAvgDistortion(rhs.mAvgDistortion),
+ mMaxDistortion(rhs.mMaxDistortion),
+ mVertexIndices(NULL),
+ mCoords(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL)
+{
+ const S32 numVertices = mNumIndices;
+
+ U32 size = sizeof(LLVector4a)*numVertices;
+
+ mCoords = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
+ mNormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
+ mBinormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
+ mTexCoords = new LLVector2[numVertices];
+ mVertexIndices = new U32[numVertices];
+
+ for (S32 v=0; v < numVertices; v++)
+ {
+ mCoords[v] = rhs.mCoords[v];
+ mNormals[v] = rhs.mNormals[v];
+ mBinormals[v] = rhs.mBinormals[v];
+ mTexCoords[v] = rhs.mTexCoords[v];
+ mVertexIndices[v] = rhs.mVertexIndices[v];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData::~LLPolyMorphData()
+{
+ freeData();
+}
+
+//-----------------------------------------------------------------------------
+// loadBinary()
+//-----------------------------------------------------------------------------
+bool LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
+{
+ S32 numVertices;
+ S32 numRead;
+
+ numRead = fread(&numVertices, sizeof(S32), 1, fp);
+ llendianswizzle(&numVertices, sizeof(S32), 1);
+ if (numRead != 1)
+ {
+ LL_WARNS() << "Can't read number of morph target vertices" << LL_ENDL;
+ return false;
+ }
+
+ //-------------------------------------------------------------------------
+ // free any existing data
+ //-------------------------------------------------------------------------
+ freeData();
+
+ //-------------------------------------------------------------------------
+ // allocate vertices
+ //-------------------------------------------------------------------------
+
+ U32 size = sizeof(LLVector4a)*numVertices;
+
+ mCoords = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
+ mNormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
+ mBinormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
+
+ mTexCoords = new LLVector2[numVertices];
+ // Actually, we are allocating more space than we need for the skiplist
+ mVertexIndices = new U32[numVertices];
+ mNumIndices = 0;
+ mTotalDistortion = 0.f;
+ mMaxDistortion = 0.f;
+ mAvgDistortion.clear();
+ mMesh = mesh;
+
+ //-------------------------------------------------------------------------
+ // read vertices
+ //-------------------------------------------------------------------------
+ for(S32 v = 0; v < numVertices; v++)
+ {
+ numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
+ llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
+ if (numRead != 1)
+ {
+ LL_WARNS() << "Can't read morph target vertex number" << LL_ENDL;
+ return false;
+ }
+
+ if (mVertexIndices[v] > 10000)
+ {
+ // Bad install? These are usually .llm files from 'character' fodler
+ LL_WARNS() << "Bad morph index " << v << ": " << mVertexIndices[v] << LL_ENDL;
+ return false;
+ }
+
+
+ numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
+ llendianswizzle(&mCoords[v], sizeof(F32), 3);
+ if (numRead != 3)
+ {
+ LL_WARNS() << "Can't read morph target vertex coordinates" << LL_ENDL;
+ return false;
+ }
+
+ F32 magnitude = mCoords[v].getLength3().getF32();
+
+ mTotalDistortion += magnitude;
+ LLVector4a t;
+ t.setAbs(mCoords[v]);
+ mAvgDistortion.add(t);
+
+ if (magnitude > mMaxDistortion)
+ {
+ mMaxDistortion = magnitude;
+ }
+
+ numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
+ llendianswizzle(&mNormals[v], sizeof(F32), 3);
+ if (numRead != 3)
+ {
+ LL_WARNS() << "Can't read morph target normal" << LL_ENDL;
+ return false;
+ }
+
+ numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
+ llendianswizzle(&mBinormals[v], sizeof(F32), 3);
+ if (numRead != 3)
+ {
+ LL_WARNS() << "Can't read morph target binormal" << LL_ENDL;
+ return false;
+ }
+
+
+ numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
+ llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
+ if (numRead != 2)
+ {
+ LL_WARNS() << "Can't read morph target uv" << LL_ENDL;
+ return false;
+ }
+
+ mNumIndices++;
+ }
+
+ mAvgDistortion.mul(1.f/(F32)mNumIndices);
+ mAvgDistortion.normalize3fast();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// freeData()
+//-----------------------------------------------------------------------------
+void LLPolyMorphData::freeData()
+{
+ if (mCoords != NULL)
+ {
+ ll_aligned_free_16(mCoords);
+ mCoords = NULL;
+ }
+
+ if (mNormals != NULL)
+ {
+ ll_aligned_free_16(mNormals);
+ mNormals = NULL;
+ }
+
+ if (mBinormals != NULL)
+ {
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+ }
+
+ if (mTexCoords != NULL)
+ {
+ delete [] mTexCoords;
+ mTexCoords = NULL;
+ }
+
+ if (mVertexIndices != NULL)
+ {
+ delete [] mVertexIndices;
+ mVertexIndices = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTargetInfo()
+//-----------------------------------------------------------------------------
+LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
+ : mIsClothingMorph(false)
+{
+}
+
+bool LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return false;
+
+ // Get mixed-case name
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if( !node->getFastAttributeString( name_string, mMorphName ) )
+ {
+ LL_WARNS() << "Avatar file: <param> is missing name attribute" << LL_ENDL;
+ return false; // Continue, ignoring this tag
+ }
+
+ static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
+ node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
+
+ LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
+
+ if (NULL == paramNode)
+ {
+ LL_WARNS() << "Failed to getChildByName(\"param_morph\")"
+ << LL_ENDL;
+ return false;
+ }
+
+ for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
+ child_node;
+ child_node = paramNode->getNextChild())
+ {
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (child_node->hasName("volume_morph"))
+ {
+ std::string volume_name;
+ if (child_node->getFastAttributeString(name_string, volume_name))
+ {
+ LLVector3 scale;
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ child_node->getFastAttributeVector3(scale_string, scale);
+
+ LLVector3 pos;
+ static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+ child_node->getFastAttributeVector3(pos_string, pos);
+
+ mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
+ }
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget()
+//-----------------------------------------------------------------------------
+LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
+ : LLViewerVisualParam(),
+ mMorphData(NULL),
+ mMesh(poly_mesh),
+ mVertMask(NULL),
+ mLastSex(SEX_FEMALE),
+ mNumMorphMasksPending(0),
+ mVolumeMorphs()
+{
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget()
+//-----------------------------------------------------------------------------
+LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther)
+ : LLViewerVisualParam(pOther),
+ mMorphData(pOther.mMorphData),
+ mMesh(pOther.mMesh),
+ mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)),
+ mLastSex(pOther.mLastSex),
+ mNumMorphMasksPending(pOther.mNumMorphMasksPending),
+ mVolumeMorphs(pOther.mVolumeMorphs)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMorphTarget()
+//-----------------------------------------------------------------------------
+LLPolyMorphTarget::~LLPolyMorphTarget()
+{
+ delete mVertMask;
+ mVertMask = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// setInfo()
+//-----------------------------------------------------------------------------
+bool LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
+{
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return false;
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight());
+
+ LLAvatarAppearance* avatarp = mMesh->getAvatar();
+ for (LLPolyVolumeMorphInfo& volume_info : getInfo()->mVolumeInfoList)
+ {
+ for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
+ {
+ if (avatarp->mCollisionVolumes[i].getName() == volume_info.mName)
+ {
+ mVolumeMorphs.push_back(
+ LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
+ volume_info.mScale,
+ volume_info.mPos));
+ break;
+ }
+ }
+ }
+
+ std::string morph_param_name = getInfo()->mMorphName;
+
+ mMorphData = mMesh->getMorphData(morph_param_name);
+ if (!mMorphData)
+ {
+ const std::string driven_tag = "_Driven";
+ U32 pos = morph_param_name.find(driven_tag);
+ if (pos > 0)
+ {
+ morph_param_name = morph_param_name.substr(0,pos);
+ mMorphData = mMesh->getMorphData(morph_param_name);
+ }
+ }
+ if (!mMorphData)
+ {
+ LL_WARNS() << "No morph target named " << morph_param_name << " found in mesh." << LL_ENDL;
+ return false; // Continue, ignoring this tag
+ }
+ return true;
+}
+
+/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
+{
+ return new LLPolyMorphTarget(*this);
+}
+
+#if 0 // obsolete
+//-----------------------------------------------------------------------------
+// parseData()
+//-----------------------------------------------------------------------------
+bool LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
+{
+ LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
+
+ info->parseXml(node);
+ if (!setInfo(info))
+ {
+ delete info;
+ return false;
+ }
+ return true;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// getVertexDistortion()
+//-----------------------------------------------------------------------------
+LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
+{
+ if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
+
+ for(U32 index = 0; index < mMorphData->mNumIndices; index++)
+ {
+ if (mMorphData->mVertexIndices[index] == (U32)requested_index)
+ {
+ return mMorphData->mCoords[index];
+ }
+ }
+
+ return LLVector4a::getZero();
+}
+
+//-----------------------------------------------------------------------------
+// getFirstDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ if (!mMorphData) return &LLVector4a::getZero();
+
+ LLVector4a* resultVec;
+ mMorphData->mCurrentIndex = 0;
+ if (mMorphData->mNumIndices)
+ {
+ resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
+ if (index != NULL)
+ {
+ *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
+ }
+ if (poly_mesh != NULL)
+ {
+ *poly_mesh = mMesh;
+ }
+
+ return resultVec;
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getNextDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+ if (!mMorphData) return &LLVector4a::getZero();
+
+ LLVector4a* resultVec;
+ mMorphData->mCurrentIndex++;
+ if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
+ {
+ resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
+ if (index != NULL)
+ {
+ *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
+ }
+ if (poly_mesh != NULL)
+ {
+ *poly_mesh = mMesh;
+ }
+ return resultVec;
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getTotalDistortion()
+//-----------------------------------------------------------------------------
+F32 LLPolyMorphTarget::getTotalDistortion()
+{
+ if (mMorphData)
+ {
+ return mMorphData->mTotalDistortion;
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getAvgDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a& LLPolyMorphTarget::getAvgDistortion()
+{
+ if (mMorphData)
+ {
+ return mMorphData->mAvgDistortion;
+ }
+ else
+ {
+ return LLVector4a::getZero();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getMaxDistortion()
+//-----------------------------------------------------------------------------
+F32 LLPolyMorphTarget::getMaxDistortion()
+{
+ if (mMorphData)
+ {
+ return mMorphData->mMaxDistortion;
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// apply()
+//-----------------------------------------------------------------------------
+void LLPolyMorphTarget::apply( ESex avatar_sex )
+{
+ if (!mMorphData || mNumMorphMasksPending > 0)
+ {
+ return;
+ }
+
+ LL_PROFILE_ZONE_SCOPED;
+
+ mLastSex = avatar_sex;
+
+ // Check for NaN condition (NaN is detected if a variable doesn't equal itself.
+ if (mCurWeight != mCurWeight)
+ {
+ mCurWeight = 0.0;
+ }
+ if (mLastWeight != mLastWeight)
+ {
+ mLastWeight = mCurWeight+.001;
+ }
+
+ // perform differential update of morph
+ F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
+ // store last weight
+ mLastWeight += delta_weight;
+
+ if (delta_weight != 0.f)
+ {
+ llassert(!mMesh->isLOD());
+ LLVector4a *coords = mMesh->getWritableCoords();
+
+ LLVector4a *scaled_normals = mMesh->getScaledNormals();
+ LLVector4a *normals = mMesh->getWritableNormals();
+
+ LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
+ LLVector4a *binormals = mMesh->getWritableBinormals();
+
+ LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
+ LLVector2 *tex_coords = mMesh->getWritableTexCoords();
+
+ F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
+
+ for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
+ {
+ S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
+
+ F32 maskWeight = 1.f;
+ if (maskWeightArray)
+ {
+ maskWeight = maskWeightArray[vert_index_morph];
+ }
+
+
+ LLVector4a pos = mMorphData->mCoords[vert_index_morph];
+ pos.mul(delta_weight*maskWeight);
+ coords[vert_index_mesh].add(pos);
+
+ if (getInfo()->mIsClothingMorph && clothing_weights)
+ {
+ LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
+ clothing_offset.mul(delta_weight * maskWeight);
+ LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
+ clothing_weight->add(clothing_offset);
+ clothing_weight->getF32ptr()[VW] = maskWeight;
+ }
+
+ // calculate new normals based on half angles
+ LLVector4a norm = mMorphData->mNormals[vert_index_morph];
+ norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+ scaled_normals[vert_index_mesh].add(norm);
+ norm = scaled_normals[vert_index_mesh];
+
+ // guard against degenerate input data before we create NaNs below!
+ //
+ norm.normalize3fast();
+ normals[vert_index_mesh] = norm;
+
+ // calculate new binormals
+ LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
+
+ // guard against degenerate input data before we create NaNs below!
+ //
+ if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO))
+ {
+ binorm.set(1,0,0,1);
+ }
+
+ binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+ scaled_binormals[vert_index_mesh].add(binorm);
+ LLVector4a tangent;
+ tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
+ LLVector4a& normalized_binormal = binormals[vert_index_mesh];
+
+ normalized_binormal.setCross3(norm, tangent);
+ normalized_binormal.normalize3fast();
+
+ tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
+ }
+
+ // now apply volume changes
+ for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
+ {
+ LLVector3 scale_delta = volume_morph.mScale * delta_weight;
+ LLVector3 pos_delta = volume_morph.mPos * delta_weight;
+
+ volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
+ // SL-315
+ volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
+ }
+ }
+
+ if (mNext)
+ {
+ mNext->apply(avatar_sex);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// applyMask()
+//-----------------------------------------------------------------------------
+void LLPolyMorphTarget::applyMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert)
+{
+ LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
+
+ if (!mVertMask)
+ {
+ mVertMask = new LLPolyVertexMask(mMorphData);
+ mNumMorphMasksPending--;
+ }
+ else
+ {
+ // remove effect of previous mask
+ F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
+
+ if (maskWeights)
+ {
+ LLVector4a *coords = mMesh->getWritableCoords();
+ LLVector4a *scaled_normals = mMesh->getScaledNormals();
+ LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
+ LLVector2 *tex_coords = mMesh->getWritableTexCoords();
+
+ LLVector4Logical clothing_mask;
+ clothing_mask.clear();
+ clothing_mask.setElement<0>();
+ clothing_mask.setElement<1>();
+ clothing_mask.setElement<2>();
+
+
+ for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
+ {
+ F32 lastMaskWeight = mLastWeight * maskWeights[vert];
+ S32 out_vert = mMorphData->mVertexIndices[vert];
+
+ // remove effect of existing masked morph
+ LLVector4a t;
+ t = mMorphData->mCoords[vert];
+ t.mul(lastMaskWeight);
+ coords[out_vert].sub(t);
+
+ t = mMorphData->mNormals[vert];
+ t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+ scaled_normals[out_vert].sub(t);
+
+ t = mMorphData->mBinormals[vert];
+ t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+ scaled_binormals[out_vert].sub(t);
+
+ tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
+
+ if (clothing_weights)
+ {
+ LLVector4a clothing_offset = mMorphData->mCoords[vert];
+ clothing_offset.mul(lastMaskWeight);
+ LLVector4a* clothing_weight = &clothing_weights[out_vert];
+ LLVector4a t;
+ t.setSub(*clothing_weight, clothing_offset);
+ clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
+ }
+ }
+ }
+ }
+
+ // set last weight to 0, since we've removed the effect of this morph
+ mLastWeight = 0.f;
+
+ mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
+
+ apply(mLastSex);
+}
+
+void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight)
+{
+ // now apply volume changes
+ for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
+ {
+ LLVector3 scale_delta = volume_morph.mScale * delta_weight;
+ LLVector3 pos_delta = volume_morph.mPos * delta_weight;
+
+ volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
+ // SL-315
+ volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
+ : mWeights(new F32[morph_data->mNumIndices]),
+ mMorphData(morph_data),
+ mWeightsGenerated(false)
+{
+ llassert(mMorphData != NULL);
+ llassert(mMorphData->mNumIndices > 0);
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther)
+ : mWeights(new F32[pOther.mMorphData->mNumIndices]),
+ mMorphData(pOther.mMorphData),
+ mWeightsGenerated(pOther.mWeightsGenerated)
+{
+ llassert(mMorphData != NULL);
+ llassert(mMorphData->mNumIndices > 0);
+ memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices);
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+LLPolyVertexMask::~LLPolyVertexMask()
+{
+ delete [] mWeights;
+ mWeights = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// generateMask()
+//-----------------------------------------------------------------------------
+void LLPolyVertexMask::generateMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights)
+{
+// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
+// bool debugImg = false;
+// if (debugImg)
+// {
+// if (invert)
+// {
+// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
+// }
+// else
+// {
+// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
+// }
+// }
+ for (U32 index = 0; index < mMorphData->mNumIndices; index++)
+ {
+ S32 vertIndex = mMorphData->mVertexIndices[index];
+ const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
+ LLVector2 uvCoords;
+
+ if (sharedVertIndex)
+ {
+ uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
+ }
+ else
+ {
+ uvCoords = mMorphData->mMesh->getUVs(vertIndex);
+ }
+ U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
+ U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
+
+ mWeights[index] = maskTextureData ? ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f : 0.0f;
+
+ if (invert)
+ {
+ mWeights[index] = 1.f - mWeights[index];
+ }
+
+ // now apply step function
+ // mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
+
+ if (clothing_weights)
+ {
+ clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
+ }
+ }
+ mWeightsGenerated = true;
+}
+
+//-----------------------------------------------------------------------------
+// getMaskForMorphIndex()
+//-----------------------------------------------------------------------------
+F32* LLPolyVertexMask::getMorphMaskWeights()
+{
+ if (!mWeightsGenerated)
+ {
+ return NULL;
+ }
+
+ return mWeights;
+}
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
index a932433819..3c7cf81c90 100644
--- a/indra/llappearance/llpolymorph.h
+++ b/indra/llappearance/llpolymorph.h
@@ -1,193 +1,193 @@
-/**
- * @file llpolymorph.h
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPOLYMORPH_H
-#define LL_LLPOLYMORPH_H
-
-#include <string>
-#include <vector>
-
-#include "llviewervisualparam.h"
-
-class LLAvatarJointCollisionVolume;
-class LLPolyMeshSharedData;
-class LLVector2;
-class LLAvatarJointCollisionVolume;
-class LLWearable;
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphData()
-//-----------------------------------------------------------------------------
-class alignas(16) LLPolyMorphData
-{
- LL_ALIGN_NEW
-public:
- LLPolyMorphData(const std::string& morph_name);
- ~LLPolyMorphData();
- LLPolyMorphData(const LLPolyMorphData &rhs);
-
- bool loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
- const std::string& getName() { return mName; }
-
-public:
- std::string mName;
-
- // morphology
- U32 mNumIndices;
- U32* mVertexIndices;
- U32 mCurrentIndex;
- LLVector4a* mCoords;
- LLVector4a* mNormals;
- LLVector4a* mBinormals;
- LLVector2* mTexCoords;
-
- F32 mTotalDistortion; // vertex distortion summed over entire morph
- F32 mMaxDistortion; // maximum single vertex distortion in a given morph
- LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph
- LLPolyMeshSharedData* mMesh;
-
-private:
- void freeData();
-} LL_ALIGN_POSTFIX(16);
-
-
-//-----------------------------------------------------------------------------
-// LLPolyVertexMask()
-//-----------------------------------------------------------------------------
-class LLPolyVertexMask
-{
-public:
- LLPolyVertexMask(LLPolyMorphData* morph_data);
- LLPolyVertexMask(const LLPolyVertexMask& pOther);
- ~LLPolyVertexMask();
-
- void generateMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights);
- F32* getMorphMaskWeights();
-
-
-protected:
- F32* mWeights;
- LLPolyMorphData *mMorphData;
- bool mWeightsGenerated;
-
-};
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTarget Data structs
-//-----------------------------------------------------------------------------
-struct LLPolyVolumeMorphInfo
-{
- LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos)
- : mName(name), mScale(scale), mPos(pos) {};
-
- std::string mName;
- LLVector3 mScale;
- LLVector3 mPos;
-};
-
-struct LLPolyVolumeMorph
-{
- LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
- : mVolume(volume), mScale(scale), mPos(pos) {};
-
- LLAvatarJointCollisionVolume* mVolume;
- LLVector3 mScale;
- LLVector3 mPos;
-};
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTargetInfo
-// Shared information for LLPolyMorphTargets
-//-----------------------------------------------------------------------------
-class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
-{
- friend class LLPolyMorphTarget;
-public:
- LLPolyMorphTargetInfo();
- /*virtual*/ ~LLPolyMorphTargetInfo() {};
-
- /*virtual*/ bool parseXml(LLXmlTreeNode* node);
-
-protected:
- std::string mMorphName;
- bool mIsClothingMorph;
- typedef std::vector<LLPolyVolumeMorphInfo> volume_info_list_t;
- volume_info_list_t mVolumeInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// LLPolyMorphTarget
-// A set of vertex data associated with morph target.
-// These morph targets must be topologically consistent with a given Polymesh
-// (share face sets)
-//-----------------------------------------------------------------------------
-class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
-{
- LL_ALIGN_NEW
-public:
- LLPolyMorphTarget(LLPolyMesh *poly_mesh);
- ~LLPolyMorphTarget();
-
- // Special: These functions are overridden by child classes
- LLPolyMorphTargetInfo* getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; }
- // This sets mInfo and calls initialization functions
- bool setInfo(LLPolyMorphTargetInfo *info);
-
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
- // LLVisualParam Virtual functions
- ///*virtual*/ bool parseData(LLXmlTreeNode* node);
- /*virtual*/ void apply( ESex sex );
-
- // LLViewerVisualParam Virtual functions
- /*virtual*/ F32 getTotalDistortion();
- /*virtual*/ const LLVector4a& getAvgDistortion();
- /*virtual*/ F32 getMaxDistortion();
- /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
- /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
- /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
-
- void applyMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert);
- void addPendingMorphMask() { mNumMorphMasksPending++; }
-
- void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
-
-protected:
- LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
-
- LLPolyMorphData* mMorphData;
- LLPolyMesh* mMesh;
- LLPolyVertexMask * mVertMask;
- ESex mLastSex;
- // number of morph masks that haven't been generated, must be 0 before this morph is applied
- S32 mNumMorphMasksPending;
-
- typedef std::vector<LLPolyVolumeMorph> volume_list_t;
- volume_list_t mVolumeMorphs;
-
-};
-
-#endif // LL_LLPOLYMORPH_H
+/**
+ * @file llpolymorph.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYMORPH_H
+#define LL_LLPOLYMORPH_H
+
+#include <string>
+#include <vector>
+
+#include "llviewervisualparam.h"
+
+class LLAvatarJointCollisionVolume;
+class LLPolyMeshSharedData;
+class LLVector2;
+class LLAvatarJointCollisionVolume;
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphData()
+//-----------------------------------------------------------------------------
+class alignas(16) LLPolyMorphData
+{
+ LL_ALIGN_NEW
+public:
+ LLPolyMorphData(const std::string& morph_name);
+ ~LLPolyMorphData();
+ LLPolyMorphData(const LLPolyMorphData &rhs);
+
+ bool loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
+ const std::string& getName() { return mName; }
+
+public:
+ std::string mName;
+
+ // morphology
+ U32 mNumIndices;
+ U32* mVertexIndices;
+ U32 mCurrentIndex;
+ LLVector4a* mCoords;
+ LLVector4a* mNormals;
+ LLVector4a* mBinormals;
+ LLVector2* mTexCoords;
+
+ F32 mTotalDistortion; // vertex distortion summed over entire morph
+ F32 mMaxDistortion; // maximum single vertex distortion in a given morph
+ LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph
+ LLPolyMeshSharedData* mMesh;
+
+private:
+ void freeData();
+} LL_ALIGN_POSTFIX(16);
+
+
+//-----------------------------------------------------------------------------
+// LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+class LLPolyVertexMask
+{
+public:
+ LLPolyVertexMask(LLPolyMorphData* morph_data);
+ LLPolyVertexMask(const LLPolyVertexMask& pOther);
+ ~LLPolyVertexMask();
+
+ void generateMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights);
+ F32* getMorphMaskWeights();
+
+
+protected:
+ F32* mWeights;
+ LLPolyMorphData *mMorphData;
+ bool mWeightsGenerated;
+
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget Data structs
+//-----------------------------------------------------------------------------
+struct LLPolyVolumeMorphInfo
+{
+ LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos)
+ : mName(name), mScale(scale), mPos(pos) {};
+
+ std::string mName;
+ LLVector3 mScale;
+ LLVector3 mPos;
+};
+
+struct LLPolyVolumeMorph
+{
+ LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
+ : mVolume(volume), mScale(scale), mPos(pos) {};
+
+ LLAvatarJointCollisionVolume* mVolume;
+ LLVector3 mScale;
+ LLVector3 mPos;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTargetInfo
+// Shared information for LLPolyMorphTargets
+//-----------------------------------------------------------------------------
+class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
+{
+ friend class LLPolyMorphTarget;
+public:
+ LLPolyMorphTargetInfo();
+ /*virtual*/ ~LLPolyMorphTargetInfo() {};
+
+ /*virtual*/ bool parseXml(LLXmlTreeNode* node);
+
+protected:
+ std::string mMorphName;
+ bool mIsClothingMorph;
+ typedef std::vector<LLPolyVolumeMorphInfo> volume_info_list_t;
+ volume_info_list_t mVolumeInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget
+// A set of vertex data associated with morph target.
+// These morph targets must be topologically consistent with a given Polymesh
+// (share face sets)
+//-----------------------------------------------------------------------------
+class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
+{
+ LL_ALIGN_NEW
+public:
+ LLPolyMorphTarget(LLPolyMesh *poly_mesh);
+ ~LLPolyMorphTarget();
+
+ // Special: These functions are overridden by child classes
+ LLPolyMorphTargetInfo* getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; }
+ // This sets mInfo and calls initialization functions
+ bool setInfo(LLPolyMorphTargetInfo *info);
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+ // LLVisualParam Virtual functions
+ ///*virtual*/ bool parseData(LLXmlTreeNode* node);
+ /*virtual*/ void apply( ESex sex );
+
+ // LLViewerVisualParam Virtual functions
+ /*virtual*/ F32 getTotalDistortion();
+ /*virtual*/ const LLVector4a& getAvgDistortion();
+ /*virtual*/ F32 getMaxDistortion();
+ /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
+ /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
+ /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
+
+ void applyMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert);
+ void addPendingMorphMask() { mNumMorphMasksPending++; }
+
+ void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
+
+protected:
+ LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
+
+ LLPolyMorphData* mMorphData;
+ LLPolyMesh* mMesh;
+ LLPolyVertexMask * mVertMask;
+ ESex mLastSex;
+ // number of morph masks that haven't been generated, must be 0 before this morph is applied
+ S32 mNumMorphMasksPending;
+
+ typedef std::vector<LLPolyVolumeMorph> volume_list_t;
+ volume_list_t mVolumeMorphs;
+
+};
+
+#endif // LL_LLPOLYMORPH_H
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index 3dd21ff62b..ed6a71d8f3 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -1,297 +1,297 @@
-/**
- * @file llpolyskeletaldistortion.cpp
- * @brief Implementation of LLPolySkeletalDistortion classes
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "llpreprocessor.h"
-#include "llerror.h"
-#include "llavatarappearance.h"
-#include "llavatarjoint.h"
-#include "llpolymorph.h"
-#include "llwearable.h"
-#include "llfasttimer.h"
-#include "llcallstack.h"
-
-#include "llpolyskeletaldistortion.h"
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDistortionInfo()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
-{
-}
-
-bool LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
-
- if (!LLViewerVisualParamInfo::parseXml(node))
- return false;
-
- LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
-
- if (NULL == skeletalParam)
- {
- LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")"
- << LL_ENDL;
- return false;
- }
-
- for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
- {
- if (bone->hasName("bone"))
- {
- std::string name;
- LLVector3 scale;
- LLVector3 pos;
- bool haspos = false;
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!bone->getFastAttributeString(name_string, name))
- {
- LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL;
- continue;
- }
-
- static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
- if (!bone->getFastAttributeVector3(scale_string, scale))
- {
- LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL;
- continue;
- }
-
- // optional offset deformation (translation)
- static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
- if (bone->getFastAttributeVector3(offset_string, pos))
- {
- haspos = true;
- }
- mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
- }
- else
- {
- LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL;
- continue;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDistortion()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
- : LLViewerVisualParam(),
- mDefaultVec(),
- mJointScales(),
- mJointOffsets(),
- mAvatar(avatarp)
-{
- mDefaultVec.splat(0.001f);
-}
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDistortion()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther)
- : LLViewerVisualParam(pOther),
- mDefaultVec(pOther.mDefaultVec),
- mJointScales(pOther.mJointScales),
- mJointOffsets(pOther.mJointOffsets),
- mAvatar(pOther.mAvatar)
-{
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolySkeletalDistortion()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
-{
-}
-
-bool LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
-{
- if (info->mID < 0)
- {
- return false;
- }
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight());
-
- for (LLPolySkeletalBoneInfo& bone_info : getInfo()->mBoneInfoList)
- {
- LLJoint* joint = mAvatar->getJoint(bone_info.mBoneName);
- if (!joint)
- {
- // There's no point continuing after this error - means
- // that either the skeleton or lad file is broken.
- LL_WARNS() << "Joint " << bone_info.mBoneName << " not found." << LL_ENDL;
- return false;
- }
-
- // store it
- mJointScales[joint] = bone_info.mScaleDeformation;
-
- // apply to children that need to inherit it
- for (LLJoint* joint : joint->mChildren)
- {
- LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
- if (child_joint->inheritScale())
- {
- LLVector3 childDeformation = LLVector3(child_joint->getScale());
- childDeformation.scaleVec(bone_info.mScaleDeformation);
- mJointScales[child_joint] = childDeformation;
- }
- }
-
- if (bone_info.mHasPositionDeformation)
- {
- mJointOffsets[joint] = bone_info.mPositionDeformation;
- }
- }
- return true;
-}
-
-/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
-{
- return new LLPolySkeletalDistortion(*this);
-}
-
-//-----------------------------------------------------------------------------
-// apply()
-//-----------------------------------------------------------------------------
-void LLPolySkeletalDistortion::apply( ESex avatar_sex )
-{
- LL_PROFILE_ZONE_SCOPED;
-
- F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
-
- LLJoint* joint;
-
- for (joint_vec_map_t::value_type& scale_pair : mJointScales)
- {
- joint = scale_pair.first;
- LLVector3 newScale = joint->getScale();
- LLVector3 scaleDelta = scale_pair.second;
- LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta;
- newScale = newScale + offset;
- //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
- // needed?
- // joint->storeScaleForReset( newScale );
-
- // BENTO for detailed stack tracing of params.
- std::stringstream ostr;
- ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset;
- LLScopedContextString str(ostr.str());
-
- joint->setScale(newScale, true);
- }
-
- for (joint_vec_map_t::value_type& offset_pair : mJointOffsets)
- {
- joint = offset_pair.first;
- LLVector3 newPosition = joint->getPosition();
- LLVector3 positionDelta = offset_pair.second;
- newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
- // SL-315
- bool allow_attachment_pos_overrides = true;
- joint->setPosition(newPosition, allow_attachment_pos_overrides);
- }
-
- if (mLastWeight != effective_weight && !mIsAnimating)
- {
- mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
- }
- mLastWeight = effective_weight;
-}
-
-
-LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
- const std::string &name)
-{
- LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
- cloned_morph_data->mName = name;
- for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
- {
- cloned_morph_data->mCoords[v] = src_data->mCoords[v];
- cloned_morph_data->mNormals[v] = src_data->mNormals[v];
- cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
- }
- return cloned_morph_data;
-}
-
-LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
- const LLVector3 &direction,
- const std::string &name)
-{
- LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
- cloned_morph_data->mName = name;
- LLVector4a dir;
- dir.load3(direction.mV);
-
- for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
- {
- cloned_morph_data->mCoords[v] = dir;
- cloned_morph_data->mNormals[v].clear();
- cloned_morph_data->mBinormals[v].clear();
- }
- return cloned_morph_data;
-}
-
-LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
- F32 scale,
- const std::string &name)
-{
- LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
- cloned_morph_data->mName = name;
-
- LLVector4a sc;
- sc.splat(scale);
-
- LLVector4a nsc;
- nsc.set(scale, -scale, scale, scale);
-
- for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
- {
- if (cloned_morph_data->mCoords[v][1] < 0)
- {
- cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
- cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
- cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
- }
- else
- {
- cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
- cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
- cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
- }
- }
- return cloned_morph_data;
-}
-
-// End
+/**
+ * @file llpolyskeletaldistortion.cpp
+ * @brief Implementation of LLPolySkeletalDistortion classes
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llpreprocessor.h"
+#include "llerror.h"
+#include "llavatarappearance.h"
+#include "llavatarjoint.h"
+#include "llpolymorph.h"
+#include "llwearable.h"
+#include "llfasttimer.h"
+#include "llcallstack.h"
+
+#include "llpolyskeletaldistortion.h"
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortionInfo()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
+{
+}
+
+bool LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return false;
+
+ LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
+
+ if (NULL == skeletalParam)
+ {
+ LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")"
+ << LL_ENDL;
+ return false;
+ }
+
+ for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
+ {
+ if (bone->hasName("bone"))
+ {
+ std::string name;
+ LLVector3 scale;
+ LLVector3 pos;
+ bool haspos = false;
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!bone->getFastAttributeString(name_string, name))
+ {
+ LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL;
+ continue;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!bone->getFastAttributeVector3(scale_string, scale))
+ {
+ LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL;
+ continue;
+ }
+
+ // optional offset deformation (translation)
+ static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
+ if (bone->getFastAttributeVector3(offset_string, pos))
+ {
+ haspos = true;
+ }
+ mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
+ }
+ else
+ {
+ LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL;
+ continue;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
+ : LLViewerVisualParam(),
+ mDefaultVec(),
+ mJointScales(),
+ mJointOffsets(),
+ mAvatar(avatarp)
+{
+ mDefaultVec.splat(0.001f);
+}
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther)
+ : LLViewerVisualParam(pOther),
+ mDefaultVec(pOther.mDefaultVec),
+ mJointScales(pOther.mJointScales),
+ mJointOffsets(pOther.mJointOffsets),
+ mAvatar(pOther.mAvatar)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
+{
+}
+
+bool LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
+{
+ if (info->mID < 0)
+ {
+ return false;
+ }
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight());
+
+ for (LLPolySkeletalBoneInfo& bone_info : getInfo()->mBoneInfoList)
+ {
+ LLJoint* joint = mAvatar->getJoint(bone_info.mBoneName);
+ if (!joint)
+ {
+ // There's no point continuing after this error - means
+ // that either the skeleton or lad file is broken.
+ LL_WARNS() << "Joint " << bone_info.mBoneName << " not found." << LL_ENDL;
+ return false;
+ }
+
+ // store it
+ mJointScales[joint] = bone_info.mScaleDeformation;
+
+ // apply to children that need to inherit it
+ for (LLJoint* joint : joint->mChildren)
+ {
+ LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
+ if (child_joint->inheritScale())
+ {
+ LLVector3 childDeformation = LLVector3(child_joint->getScale());
+ childDeformation.scaleVec(bone_info.mScaleDeformation);
+ mJointScales[child_joint] = childDeformation;
+ }
+ }
+
+ if (bone_info.mHasPositionDeformation)
+ {
+ mJointOffsets[joint] = bone_info.mPositionDeformation;
+ }
+ }
+ return true;
+}
+
+/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
+{
+ return new LLPolySkeletalDistortion(*this);
+}
+
+//-----------------------------------------------------------------------------
+// apply()
+//-----------------------------------------------------------------------------
+void LLPolySkeletalDistortion::apply( ESex avatar_sex )
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+
+ LLJoint* joint;
+
+ for (joint_vec_map_t::value_type& scale_pair : mJointScales)
+ {
+ joint = scale_pair.first;
+ LLVector3 newScale = joint->getScale();
+ LLVector3 scaleDelta = scale_pair.second;
+ LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta;
+ newScale = newScale + offset;
+ //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
+ // needed?
+ // joint->storeScaleForReset( newScale );
+
+ // BENTO for detailed stack tracing of params.
+ std::stringstream ostr;
+ ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset;
+ LLScopedContextString str(ostr.str());
+
+ joint->setScale(newScale, true);
+ }
+
+ for (joint_vec_map_t::value_type& offset_pair : mJointOffsets)
+ {
+ joint = offset_pair.first;
+ LLVector3 newPosition = joint->getPosition();
+ LLVector3 positionDelta = offset_pair.second;
+ newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+ // SL-315
+ bool allow_attachment_pos_overrides = true;
+ joint->setPosition(newPosition, allow_attachment_pos_overrides);
+ }
+
+ if (mLastWeight != effective_weight && !mIsAnimating)
+ {
+ mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
+ }
+ mLastWeight = effective_weight;
+}
+
+
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ cloned_morph_data->mCoords[v] = src_data->mCoords[v];
+ cloned_morph_data->mNormals[v] = src_data->mNormals[v];
+ cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
+ }
+ return cloned_morph_data;
+}
+
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+ const LLVector3 &direction,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+ LLVector4a dir;
+ dir.load3(direction.mV);
+
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ cloned_morph_data->mCoords[v] = dir;
+ cloned_morph_data->mNormals[v].clear();
+ cloned_morph_data->mBinormals[v].clear();
+ }
+ return cloned_morph_data;
+}
+
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+ F32 scale,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+
+ LLVector4a sc;
+ sc.splat(scale);
+
+ LLVector4a nsc;
+ nsc.set(scale, -scale, scale, scale);
+
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ if (cloned_morph_data->mCoords[v][1] < 0)
+ {
+ cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
+ cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
+ cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
+ }
+ else
+ {
+ cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
+ cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
+ cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
+ }
+ }
+ return cloned_morph_data;
+}
+
+// End
diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h
index 4c69f7e70a..252ed70b7f 100644
--- a/indra/llappearance/llpolyskeletaldistortion.h
+++ b/indra/llappearance/llpolyskeletaldistortion.h
@@ -1,123 +1,123 @@
-/**
- * @file llpolyskeletaldistortion.h
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPOLYSKELETALDISTORTION_H
-#define LL_LLPOLYSKELETALDISTORTION_H
-
-#include "llcommon.h"
-
-#include <string>
-#include <map>
-#include "llstl.h"
-
-#include "v3math.h"
-#include "v2math.h"
-#include "llquaternion.h"
-//#include "llpolymorph.h"
-#include "lljoint.h"
-#include "llviewervisualparam.h"
-
-//class LLSkinJoint;
-class LLAvatarAppearance;
-
-//#define USE_STRIPS // Use tri-strips for rendering.
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDeformationInfo
-// Shared information for LLPolySkeletalDeformations
-//-----------------------------------------------------------------------------
-struct LLPolySkeletalBoneInfo
-{
- LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, bool haspos)
- : mBoneName(name),
- mScaleDeformation(scale),
- mPositionDeformation(pos),
- mHasPositionDeformation(haspos) {}
- std::string mBoneName;
- LLVector3 mScaleDeformation;
- LLVector3 mPositionDeformation;
- bool mHasPositionDeformation;
-};
-
-class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
-{
- LL_ALIGN_NEW
- friend class LLPolySkeletalDistortion;
-public:
-
- LLPolySkeletalDistortionInfo();
- /*virtual*/ ~LLPolySkeletalDistortionInfo() {};
-
- /*virtual*/ bool parseXml(LLXmlTreeNode* node);
-
-protected:
- typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
- bone_info_list_t mBoneInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDeformation
-// A set of joint scale data for deforming the avatar mesh
-//-----------------------------------------------------------------------------
-class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
-{
- LL_ALIGN_NEW
-public:
- LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
- ~LLPolySkeletalDistortion();
-
- // Special: These functions are overridden by child classes
- LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
- // This sets mInfo and calls initialization functions
- bool setInfo(LLPolySkeletalDistortionInfo *info);
-
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
- // LLVisualParam Virtual functions
- ///*virtual*/ bool parseData(LLXmlTreeNode* node);
- /*virtual*/ void apply( ESex sex );
-
- // LLViewerVisualParam Virtual functions
- /*virtual*/ F32 getTotalDistortion() { return 0.1f; }
- /*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
- /*virtual*/ F32 getMaxDistortion() { return 0.1f; }
- /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
- /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
- /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
-
-protected:
- LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther);
-
- LL_ALIGN_16(LLVector4a mDefaultVec);
- typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
- joint_vec_map_t mJointScales;
- joint_vec_map_t mJointOffsets;
- // Backlink only; don't make this an LLPointer.
- LLAvatarAppearance *mAvatar;
-} LL_ALIGN_POSTFIX(16);
-
-#endif // LL_LLPOLYSKELETALDISTORTION_H
-
+/**
+ * @file llpolyskeletaldistortion.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYSKELETALDISTORTION_H
+#define LL_LLPOLYSKELETALDISTORTION_H
+
+#include "llcommon.h"
+
+#include <string>
+#include <map>
+#include "llstl.h"
+
+#include "v3math.h"
+#include "v2math.h"
+#include "llquaternion.h"
+//#include "llpolymorph.h"
+#include "lljoint.h"
+#include "llviewervisualparam.h"
+
+//class LLSkinJoint;
+class LLAvatarAppearance;
+
+//#define USE_STRIPS // Use tri-strips for rendering.
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDeformationInfo
+// Shared information for LLPolySkeletalDeformations
+//-----------------------------------------------------------------------------
+struct LLPolySkeletalBoneInfo
+{
+ LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, bool haspos)
+ : mBoneName(name),
+ mScaleDeformation(scale),
+ mPositionDeformation(pos),
+ mHasPositionDeformation(haspos) {}
+ std::string mBoneName;
+ LLVector3 mScaleDeformation;
+ LLVector3 mPositionDeformation;
+ bool mHasPositionDeformation;
+};
+
+class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
+{
+ LL_ALIGN_NEW
+ friend class LLPolySkeletalDistortion;
+public:
+
+ LLPolySkeletalDistortionInfo();
+ /*virtual*/ ~LLPolySkeletalDistortionInfo() {};
+
+ /*virtual*/ bool parseXml(LLXmlTreeNode* node);
+
+protected:
+ typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
+ bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDeformation
+// A set of joint scale data for deforming the avatar mesh
+//-----------------------------------------------------------------------------
+class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
+{
+ LL_ALIGN_NEW
+public:
+ LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
+ ~LLPolySkeletalDistortion();
+
+ // Special: These functions are overridden by child classes
+ LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
+ // This sets mInfo and calls initialization functions
+ bool setInfo(LLPolySkeletalDistortionInfo *info);
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+ // LLVisualParam Virtual functions
+ ///*virtual*/ bool parseData(LLXmlTreeNode* node);
+ /*virtual*/ void apply( ESex sex );
+
+ // LLViewerVisualParam Virtual functions
+ /*virtual*/ F32 getTotalDistortion() { return 0.1f; }
+ /*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
+ /*virtual*/ F32 getMaxDistortion() { return 0.1f; }
+ /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
+ /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
+ /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
+
+protected:
+ LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther);
+
+ LL_ALIGN_16(LLVector4a mDefaultVec);
+ typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
+ joint_vec_map_t mJointScales;
+ joint_vec_map_t mJointOffsets;
+ // Backlink only; don't make this an LLPointer.
+ LLAvatarAppearance *mAvatar;
+} LL_ALIGN_POSTFIX(16);
+
+#endif // LL_LLPOLYSKELETALDISTORTION_H
+
diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp
index cd416d6791..d01a7cb3d3 100644
--- a/indra/llappearance/lltexglobalcolor.cpp
+++ b/indra/llappearance/lltexglobalcolor.cpp
@@ -1,165 +1,165 @@
-/**
- * @file lltexlayerglobalcolor.cpp
- * @brief Color for texture layers.
- *
- * $LicenseInfo:firstyear=2008&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 "lltexlayer.h"
-#include "lltexglobalcolor.h"
-
-class LLWearable;
-
-//-----------------------------------------------------------------------------
-// LLTexGlobalColor
-//-----------------------------------------------------------------------------
-
-LLTexGlobalColor::LLTexGlobalColor(LLAvatarAppearance* appearance)
- :
- mAvatarAppearance(appearance),
- mInfo(NULL)
-{
-}
-
-LLTexGlobalColor::~LLTexGlobalColor()
-{
- // mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter()
- //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
-}
-
-bool LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info)
-{
- llassert(mInfo == NULL);
- mInfo = info;
- //mID = info->mID; // No ID
-
- mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size());
- for (LLTexLayerParamColorInfo* color_info : mInfo->mParamColorInfoList)
- {
- LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this);
- if (!param_color->setInfo(color_info, true))
- {
- mInfo = NULL;
- return false;
- }
- mParamGlobalColorList.push_back(param_color);
- }
-
- return true;
-}
-
-LLColor4 LLTexGlobalColor::getColor() const
-{
- // Sum of color params
- if (mParamGlobalColorList.empty())
- return LLColor4(1.f, 1.f, 1.f, 1.f);
-
- LLColor4 net_color(0.f, 0.f, 0.f, 0.f);
- LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color);
- return net_color;
-}
-
-const std::string& LLTexGlobalColor::getName() const
-{
- return mInfo->mName;
-}
-
-//-----------------------------------------------------------------------------
-// LLTexParamGlobalColor
-//-----------------------------------------------------------------------------
-LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
- : LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
- mTexGlobalColor(tex_global_color)
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLTexParamGlobalColor
-//-----------------------------------------------------------------------------
-LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther)
- : LLTexLayerParamColor(pOther),
- mTexGlobalColor(pOther.mTexGlobalColor)
-{
-}
-
-//-----------------------------------------------------------------------------
-// ~LLTexParamGlobalColor
-//-----------------------------------------------------------------------------
-LLTexParamGlobalColor::~LLTexParamGlobalColor()
-{
-}
-
-/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const
-{
- return new LLTexParamGlobalColor(*this);
-}
-
-void LLTexParamGlobalColor::onGlobalColorChanged()
-{
- mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
-}
-
-//-----------------------------------------------------------------------------
-// LLTexGlobalColorInfo
-//-----------------------------------------------------------------------------
-
-LLTexGlobalColorInfo::LLTexGlobalColorInfo()
-{
-}
-
-
-LLTexGlobalColorInfo::~LLTexGlobalColorInfo()
-{
- for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
- mParamColorInfoList.clear();
-}
-
-bool LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node)
-{
- // name attribute
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!node->getFastAttributeString(name_string, mName))
- {
- LL_WARNS() << "<global_color> element is missing name attribute." << LL_ENDL;
- return false;
- }
- // <param> sub-element
- for (LLXmlTreeNode* child = node->getChildByName("param");
- child;
- child = node->getNextNamedChild())
- {
- if (child->getChildByName("param_color"))
- {
- // <param><param_color/></param>
- LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo();
- if (!info->parseXml(child))
- {
- delete info;
- return false;
- }
- mParamColorInfoList.push_back(info);
- }
- }
- return true;
-}
+/**
+ * @file lltexlayerglobalcolor.cpp
+ * @brief Color for texture layers.
+ *
+ * $LicenseInfo:firstyear=2008&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 "lltexlayer.h"
+#include "lltexglobalcolor.h"
+
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+// LLTexGlobalColor
+//-----------------------------------------------------------------------------
+
+LLTexGlobalColor::LLTexGlobalColor(LLAvatarAppearance* appearance)
+ :
+ mAvatarAppearance(appearance),
+ mInfo(NULL)
+{
+}
+
+LLTexGlobalColor::~LLTexGlobalColor()
+{
+ // mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter()
+ //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
+}
+
+bool LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info)
+{
+ llassert(mInfo == NULL);
+ mInfo = info;
+ //mID = info->mID; // No ID
+
+ mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size());
+ for (LLTexLayerParamColorInfo* color_info : mInfo->mParamColorInfoList)
+ {
+ LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this);
+ if (!param_color->setInfo(color_info, true))
+ {
+ mInfo = NULL;
+ return false;
+ }
+ mParamGlobalColorList.push_back(param_color);
+ }
+
+ return true;
+}
+
+LLColor4 LLTexGlobalColor::getColor() const
+{
+ // Sum of color params
+ if (mParamGlobalColorList.empty())
+ return LLColor4(1.f, 1.f, 1.f, 1.f);
+
+ LLColor4 net_color(0.f, 0.f, 0.f, 0.f);
+ LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color);
+ return net_color;
+}
+
+const std::string& LLTexGlobalColor::getName() const
+{
+ return mInfo->mName;
+}
+
+//-----------------------------------------------------------------------------
+// LLTexParamGlobalColor
+//-----------------------------------------------------------------------------
+LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
+ : LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
+ mTexGlobalColor(tex_global_color)
+{
+}
+
+//-----------------------------------------------------------------------------
+// LLTexParamGlobalColor
+//-----------------------------------------------------------------------------
+LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther)
+ : LLTexLayerParamColor(pOther),
+ mTexGlobalColor(pOther.mTexGlobalColor)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLTexParamGlobalColor
+//-----------------------------------------------------------------------------
+LLTexParamGlobalColor::~LLTexParamGlobalColor()
+{
+}
+
+/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const
+{
+ return new LLTexParamGlobalColor(*this);
+}
+
+void LLTexParamGlobalColor::onGlobalColorChanged()
+{
+ mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
+}
+
+//-----------------------------------------------------------------------------
+// LLTexGlobalColorInfo
+//-----------------------------------------------------------------------------
+
+LLTexGlobalColorInfo::LLTexGlobalColorInfo()
+{
+}
+
+
+LLTexGlobalColorInfo::~LLTexGlobalColorInfo()
+{
+ for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
+ mParamColorInfoList.clear();
+}
+
+bool LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node)
+{
+ // name attribute
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ LL_WARNS() << "<global_color> element is missing name attribute." << LL_ENDL;
+ return false;
+ }
+ // <param> sub-element
+ for (LLXmlTreeNode* child = node->getChildByName("param");
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (child->getChildByName("param_color"))
+ {
+ // <param><param_color/></param>
+ LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo();
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return false;
+ }
+ mParamColorInfoList.push_back(info);
+ }
+ }
+ return true;
+}
diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h
index 52c80fc943..8fd0da79f6 100644
--- a/indra/llappearance/lltexglobalcolor.h
+++ b/indra/llappearance/lltexglobalcolor.h
@@ -1,85 +1,85 @@
-/**
- * @file lltexglobalcolor.h
- * @brief This is global texture color info used by llavatarappearance.
- *
- * $LicenseInfo:firstyear=2008&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$
- */
-
-#ifndef LL_LLTEXGLOBALCOLOR_H
-#define LL_LLTEXGLOBALCOLOR_H
-
-#include "lltexlayer.h"
-#include "lltexlayerparams.h"
-
-class LLAvatarAppearance;
-class LLWearable;
-class LLTexGlobalColorInfo;
-
-class LLTexGlobalColor
-{
-public:
- LLTexGlobalColor( LLAvatarAppearance* appearance );
- ~LLTexGlobalColor();
-
- LLTexGlobalColorInfo* getInfo() const { return mInfo; }
- // This sets mInfo and calls initialization functions
- bool setInfo(LLTexGlobalColorInfo *info);
-
- LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
- LLColor4 getColor() const;
- const std::string& getName() const;
-
-private:
- param_color_list_t mParamGlobalColorList;
- LLAvatarAppearance* mAvatarAppearance; // just backlink, don't LLPointer
- LLTexGlobalColorInfo *mInfo;
-};
-
-// Used by llavatarappearance to determine skin/eye/hair color.
-class LLTexGlobalColorInfo
-{
- friend class LLTexGlobalColor;
-public:
- LLTexGlobalColorInfo();
- ~LLTexGlobalColorInfo();
-
- bool parseXml(LLXmlTreeNode* node);
-
-private:
- param_color_info_list_t mParamColorInfoList;
- std::string mName;
-};
-
-class LLTexParamGlobalColor : public LLTexLayerParamColor
-{
-public:
- LLTexParamGlobalColor(LLTexGlobalColor *tex_color);
- virtual ~LLTexParamGlobalColor();
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-protected:
- LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther);
- /*virtual*/ void onGlobalColorChanged();
-private:
- LLTexGlobalColor* mTexGlobalColor;
-};
-
-#endif
+/**
+ * @file lltexglobalcolor.h
+ * @brief This is global texture color info used by llavatarappearance.
+ *
+ * $LicenseInfo:firstyear=2008&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$
+ */
+
+#ifndef LL_LLTEXGLOBALCOLOR_H
+#define LL_LLTEXGLOBALCOLOR_H
+
+#include "lltexlayer.h"
+#include "lltexlayerparams.h"
+
+class LLAvatarAppearance;
+class LLWearable;
+class LLTexGlobalColorInfo;
+
+class LLTexGlobalColor
+{
+public:
+ LLTexGlobalColor( LLAvatarAppearance* appearance );
+ ~LLTexGlobalColor();
+
+ LLTexGlobalColorInfo* getInfo() const { return mInfo; }
+ // This sets mInfo and calls initialization functions
+ bool setInfo(LLTexGlobalColorInfo *info);
+
+ LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+ LLColor4 getColor() const;
+ const std::string& getName() const;
+
+private:
+ param_color_list_t mParamGlobalColorList;
+ LLAvatarAppearance* mAvatarAppearance; // just backlink, don't LLPointer
+ LLTexGlobalColorInfo *mInfo;
+};
+
+// Used by llavatarappearance to determine skin/eye/hair color.
+class LLTexGlobalColorInfo
+{
+ friend class LLTexGlobalColor;
+public:
+ LLTexGlobalColorInfo();
+ ~LLTexGlobalColorInfo();
+
+ bool parseXml(LLXmlTreeNode* node);
+
+private:
+ param_color_info_list_t mParamColorInfoList;
+ std::string mName;
+};
+
+class LLTexParamGlobalColor : public LLTexLayerParamColor
+{
+public:
+ LLTexParamGlobalColor(LLTexGlobalColor *tex_color);
+ virtual ~LLTexParamGlobalColor();
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+protected:
+ LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther);
+ /*virtual*/ void onGlobalColorChanged();
+private:
+ LLTexGlobalColor* mTexGlobalColor;
+};
+
+#endif
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index 15a031f90c..d1913134c4 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -1,1920 +1,1920 @@
-/**
- * @file lltexlayer.cpp
- * @brief A texture layer. Used for avatars.
- *
- * $LicenseInfo:firstyear=2002&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 "lltexlayer.h"
-
-#include "llavatarappearance.h"
-#include "llcrc.h"
-#include "llimagej2c.h"
-#include "llimagetga.h"
-#include "lldir.h"
-#include "lltexlayerparams.h"
-#include "lltexturemanagerbridge.h"
-#include "lllocaltextureobject.h"
-#include "../llui/llui.h"
-#include "llwearable.h"
-#include "llwearabledata.h"
-#include "llvertexbuffer.h"
-#include "llviewervisualparam.h"
-#include "llfasttimer.h"
-
-//#include "../tools/imdebug/imdebug.h"
-
-using namespace LLAvatarAppearanceDefines;
-
-// runway consolidate
-extern std::string self_av_string();
-
-class LLTexLayerInfo
-{
- friend class LLTexLayer;
- friend class LLTexLayerTemplate;
- friend class LLTexLayerInterface;
-public:
- LLTexLayerInfo();
- ~LLTexLayerInfo();
-
- bool parseXml(LLXmlTreeNode* node);
- bool createVisualParams(LLAvatarAppearance *appearance);
- bool isUserSettable() { return mLocalTexture != -1; }
- S32 getLocalTexture() const { return mLocalTexture; }
- bool getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; }
- std::string getName() const { return mName; }
-
-private:
- std::string mName;
-
- bool mWriteAllChannels; // Don't use masking. Just write RGBA into buffer,
- LLTexLayerInterface::ERenderPass mRenderPass;
-
- std::string mGlobalColor;
- LLColor4 mFixedColor;
-
- S32 mLocalTexture;
- std::string mStaticImageFileName;
- bool mStaticImageIsMask;
- bool mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask
- bool mIsVisibilityMask;
-
- typedef std::vector< std::pair< std::string,bool > > morph_name_list_t;
- morph_name_list_t mMorphNameList;
- param_color_info_list_t mParamColorInfoList;
- param_alpha_info_list_t mParamAlphaInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// LLTexLayerSetBuffer
-// The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one.
-//-----------------------------------------------------------------------------
-
-LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner) :
- mTexLayerSet(owner)
-{
-}
-
-LLTexLayerSetBuffer::~LLTexLayerSetBuffer()
-{
-}
-
-void LLTexLayerSetBuffer::pushProjection() const
-{
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
- gGL.ortho(0.0f, getCompositeWidth(), 0.0f, getCompositeHeight(), -1.0f, 1.0f);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.loadIdentity();
-}
-
-void LLTexLayerSetBuffer::popProjection() const
-{
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
-}
-
-// virtual
-void LLTexLayerSetBuffer::preRenderTexLayerSet()
-{
- // Set up an ortho projection
- pushProjection();
-}
-
-// virtual
-void LLTexLayerSetBuffer::postRenderTexLayerSet(bool success)
-{
- popProjection();
-}
-
-bool LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
-{
- // Default color mask for tex layer render
- gGL.setColorMask(true, true);
-
- bool success = true;
-
- gAlphaMaskProgram.bind();
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
-
- LLVertexBuffer::unbind();
-
- // Composite the color data
- LLGLSUIDefault gls_ui;
- success &= mTexLayerSet->render( getCompositeOriginX(), getCompositeOriginY(),
- getCompositeWidth(), getCompositeHeight(), bound_target );
- gGL.flush();
-
- midRenderTexLayerSet(success);
-
- gAlphaMaskProgram.unbind();
-
- LLVertexBuffer::unbind();
-
- // reset GL state
- gGL.setColorMask(true, true);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// LLTexLayerSetInfo
-// An ordered set of texture layers that get composited into a single texture.
-//-----------------------------------------------------------------------------
-
-LLTexLayerSetInfo::LLTexLayerSetInfo() :
- mBodyRegion( "" ),
- mWidth( 512 ),
- mHeight( 512 ),
- mClearAlpha( true )
-{
-}
-
-LLTexLayerSetInfo::~LLTexLayerSetInfo( )
-{
- std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
- mLayerInfoList.clear();
-}
-
-bool LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert( node->hasName( "layer_set" ) );
- if( !node->hasName( "layer_set" ) )
- {
- return false;
- }
-
- // body_region
- static LLStdStringHandle body_region_string = LLXmlTree::addAttributeString("body_region");
- if( !node->getFastAttributeString( body_region_string, mBodyRegion ) )
- {
- LL_WARNS() << "<layer_set> is missing body_region attribute" << LL_ENDL;
- return false;
- }
-
- // width, height
- static LLStdStringHandle width_string = LLXmlTree::addAttributeString("width");
- if( !node->getFastAttributeS32( width_string, mWidth ) )
- {
- return false;
- }
-
- static LLStdStringHandle height_string = LLXmlTree::addAttributeString("height");
- if( !node->getFastAttributeS32( height_string, mHeight ) )
- {
- return false;
- }
-
- // Optional alpha component to apply after all compositing is complete.
- static LLStdStringHandle alpha_tga_file_string = LLXmlTree::addAttributeString("alpha_tga_file");
- node->getFastAttributeString( alpha_tga_file_string, mStaticAlphaFileName );
-
- static LLStdStringHandle clear_alpha_string = LLXmlTree::addAttributeString("clear_alpha");
- node->getFastAttributeBOOL( clear_alpha_string, mClearAlpha );
-
- // <layer>
- for (LLXmlTreeNode* child = node->getChildByName( "layer" );
- child;
- child = node->getNextNamedChild())
- {
- LLTexLayerInfo* info = new LLTexLayerInfo();
- if( !info->parseXml( child ))
- {
- delete info;
- return false;
- }
- mLayerInfoList.push_back( info );
- }
- return true;
-}
-
-// creates visual params without generating layersets or layers
-void LLTexLayerSetInfo::createVisualParams(LLAvatarAppearance *appearance)
-{
- //layer_info_list_t mLayerInfoList;
- for (LLTexLayerInfo* layer_info : mLayerInfoList)
- {
- layer_info->createVisualParams(appearance);
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLTexLayerSet
-// An ordered set of texture layers that get composited into a single texture.
-//-----------------------------------------------------------------------------
-
-bool LLTexLayerSet::sHasCaches = false;
-
-LLTexLayerSet::LLTexLayerSet(LLAvatarAppearance* const appearance) :
- mAvatarAppearance( appearance ),
- mIsVisible( true ),
- mBakedTexIndex(LLAvatarAppearanceDefines::BAKED_HEAD),
- mInfo( NULL )
-{
-}
-
-// virtual
-LLTexLayerSet::~LLTexLayerSet()
-{
- deleteCaches();
- std::for_each(mLayerList.begin(), mLayerList.end(), DeletePointer());
- mLayerList.clear();
-
- std::for_each(mMaskLayerList.begin(), mMaskLayerList.end(), DeletePointer());
- mMaskLayerList.clear();
-}
-
-//-----------------------------------------------------------------------------
-// setInfo
-//-----------------------------------------------------------------------------
-
-bool LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info)
-{
- llassert(mInfo == NULL);
- mInfo = info;
- //mID = info->mID; // No ID
-
- mLayerList.reserve(info->mLayerInfoList.size());
- for (LLTexLayerInfo* layer_info : info->mLayerInfoList)
- {
- LLTexLayerInterface *layer = NULL;
- if (layer_info->isUserSettable())
- {
- layer = new LLTexLayerTemplate( this, getAvatarAppearance() );
- }
- else
- {
- layer = new LLTexLayer(this);
- }
- // this is the first time this layer (of either type) is being created - make sure you add the parameters to the avatar appearance
- if (!layer->setInfo(layer_info, NULL))
- {
- mInfo = NULL;
- return false;
- }
- if (!layer->isVisibilityMask())
- {
- mLayerList.push_back( layer );
- }
- else
- {
- mMaskLayerList.push_back(layer);
- }
- }
-
- requestUpdate();
-
- stop_glerror();
-
- return true;
-}
-
-#if 0 // obsolete
-//-----------------------------------------------------------------------------
-// parseData
-//-----------------------------------------------------------------------------
-
-bool LLTexLayerSet::parseData(LLXmlTreeNode* node)
-{
- LLTexLayerSetInfo *info = new LLTexLayerSetInfo;
-
- if (!info->parseXml(node))
- {
- delete info;
- return false;
- }
- if (!setInfo(info))
- {
- delete info;
- return false;
- }
- return true;
-}
-#endif
-
-void LLTexLayerSet::deleteCaches()
-{
- for(LLTexLayerInterface* layer : mLayerList)
- {
- layer->deleteCaches();
- }
- for (LLTexLayerInterface* layer : mMaskLayerList)
- {
- layer->deleteCaches();
- }
-}
-
-
-bool LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target )
-{
- bool success = true;
- mIsVisible = true;
-
- if (mMaskLayerList.size() > 0)
- {
- for (LLTexLayerInterface* layer : mMaskLayerList)
- {
- if (layer->isInvisibleAlphaMask())
- {
- mIsVisible = false;
- }
- }
- }
-
- LLGLSUIDefault gls_ui;
- LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
- gGL.setColorMask(true, true);
-
- // clear buffer area to ensure we don't pick up UI elements
- {
- gGL.flush();
- gAlphaMaskProgram.setMinimumAlpha(0.0f);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4f( 0.f, 0.f, 0.f, 1.f );
-
- gl_rect_2d_simple( width, height );
-
- gGL.flush();
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
-
- if (mIsVisible)
- {
- // composite color layers
- for(LLTexLayerInterface* layer : mLayerList)
- {
- if (layer->getRenderPass() == LLTexLayer::RP_COLOR)
- {
- gGL.flush();
- success &= layer->render(x, y, width, height, bound_target);
- gGL.flush();
- }
- }
-
- renderAlphaMaskTextures(x, y, width, height, bound_target, false);
-
- stop_glerror();
- }
- else
- {
- gGL.flush();
-
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- gAlphaMaskProgram.setMinimumAlpha(0.f);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4f( 0.f, 0.f, 0.f, 0.f );
-
- gl_rect_2d_simple( width, height );
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- gGL.flush();
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
-
- return success;
-}
-
-
-bool LLTexLayerSet::isBodyRegion(const std::string& region) const
-{
- return mInfo->mBodyRegion == region;
-}
-
-const std::string LLTexLayerSet::getBodyRegionName() const
-{
- return mInfo->mBodyRegion;
-}
-
-void LLTexLayerSet::destroyComposite()
-{
- if( mComposite )
- {
- mComposite = NULL;
- }
-}
-
-LLTexLayerSetBuffer* LLTexLayerSet::getComposite()
-{
- if (!mComposite)
- {
- createComposite();
- }
- return mComposite;
-}
-
-const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
-{
- return mComposite;
-}
-
-void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- LL_PROFILE_ZONE_SCOPED;
- memset(data, 255, width * height);
-
- for(LLTexLayerInterface* layer : mLayerList)
- {
- layer->gatherAlphaMasks(data, origin_x, origin_y, width, height, bound_target);
- }
-
- // Set alpha back to that of our alpha masks.
- renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true);
-}
-
-void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear)
-{
- LL_PROFILE_ZONE_SCOPED;
- const LLTexLayerSetInfo *info = getInfo();
-
- gGL.setColorMask(false, true);
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
-
- // (Optionally) replace alpha with a single component image from a tga file.
- if (!info->mStaticAlphaFileName.empty())
- {
- gGL.flush();
- {
- LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, true);
- if( tex )
- {
- LLGLSUIDefault gls_ui;
- gGL.getTexUnit(0)->bind(tex);
- gl_rect_2d_simple_tex( width, height );
- }
- }
- gGL.flush();
- }
- else if (forceClear || info->mClearAlpha || (mMaskLayerList.size() > 0))
- {
- // Set the alpha channel to one (clean up after previous blending)
- gGL.flush();
- gAlphaMaskProgram.setMinimumAlpha(0.f);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4f( 0.f, 0.f, 0.f, 1.f );
-
- gl_rect_2d_simple( width, height );
-
- gGL.flush();
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
-
- // (Optional) Mask out part of the baked texture with alpha masks
- // will still have an effect even if mClearAlpha is set or the alpha component was replaced
- if (mMaskLayerList.size() > 0)
- {
- gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
- for (LLTexLayerInterface* layer : mMaskLayerList)
- {
- gGL.flush();
- layer->blendAlphaTexture(x,y,width, height);
- gGL.flush();
- }
-
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- gGL.setColorMask(true, true);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-}
-
-void LLTexLayerSet::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components)
-{
- mAvatarAppearance->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex);
-}
-
-bool LLTexLayerSet::isMorphValid() const
-{
- for(const LLTexLayerInterface* layer : mLayerList)
- {
- if (layer && !layer->isMorphValid())
- {
- return false;
- }
- }
- return true;
-}
-
-void LLTexLayerSet::invalidateMorphMasks()
-{
- for(LLTexLayerInterface* layer : mLayerList)
- {
- if (layer)
- {
- layer->invalidateMorphMasks();
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// LLTexLayerInfo
-//-----------------------------------------------------------------------------
-LLTexLayerInfo::LLTexLayerInfo() :
- mWriteAllChannels( false ),
- mRenderPass(LLTexLayer::RP_COLOR),
- mFixedColor( 0.f, 0.f, 0.f, 0.f ),
- mLocalTexture( -1 ),
- mStaticImageIsMask( false ),
- mUseLocalTextureAlphaOnly(false),
- mIsVisibilityMask(false)
-{
-}
-
-LLTexLayerInfo::~LLTexLayerInfo( )
-{
- std::for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
- mParamColorInfoList.clear();
- std::for_each(mParamAlphaInfoList.begin(), mParamAlphaInfoList.end(), DeletePointer());
- mParamAlphaInfoList.clear();
-}
-
-bool LLTexLayerInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert( node->hasName( "layer" ) );
-
- // name attribute
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if( !node->getFastAttributeString( name_string, mName ) )
- {
- return false;
- }
-
- static LLStdStringHandle write_all_channels_string = LLXmlTree::addAttributeString("write_all_channels");
- node->getFastAttributeBOOL( write_all_channels_string, mWriteAllChannels );
-
- std::string render_pass_name;
- static LLStdStringHandle render_pass_string = LLXmlTree::addAttributeString("render_pass");
- if( node->getFastAttributeString( render_pass_string, render_pass_name ) )
- {
- if( render_pass_name == "bump" )
- {
- mRenderPass = LLTexLayer::RP_BUMP;
- }
- }
-
- // Note: layers can have either a "global_color" attrib, a "fixed_color" attrib, or a <param_color> child.
- // global color attribute (optional)
- static LLStdStringHandle global_color_string = LLXmlTree::addAttributeString("global_color");
- node->getFastAttributeString( global_color_string, mGlobalColor );
-
- // Visibility mask (optional)
- bool is_visibility;
- static LLStdStringHandle visibility_mask_string = LLXmlTree::addAttributeString("visibility_mask");
- if (node->getFastAttributeBOOL(visibility_mask_string, is_visibility))
- {
- mIsVisibilityMask = is_visibility;
- }
-
- // color attribute (optional)
- LLColor4U color4u;
- static LLStdStringHandle fixed_color_string = LLXmlTree::addAttributeString("fixed_color");
- if( node->getFastAttributeColor4U( fixed_color_string, color4u ) )
- {
- mFixedColor.setVec( color4u );
- }
-
- // <texture> optional sub-element
- for (LLXmlTreeNode* texture_node = node->getChildByName( "texture" );
- texture_node;
- texture_node = node->getNextNamedChild())
- {
- std::string local_texture_name;
- static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
- static LLStdStringHandle local_texture_string = LLXmlTree::addAttributeString("local_texture");
- static LLStdStringHandle file_is_mask_string = LLXmlTree::addAttributeString("file_is_mask");
- static LLStdStringHandle local_texture_alpha_only_string = LLXmlTree::addAttributeString("local_texture_alpha_only");
- if( texture_node->getFastAttributeString( tga_file_string, mStaticImageFileName ) )
- {
- texture_node->getFastAttributeBOOL( file_is_mask_string, mStaticImageIsMask );
- }
- else if (texture_node->getFastAttributeString(local_texture_string, local_texture_name))
- {
- texture_node->getFastAttributeBOOL( local_texture_alpha_only_string, mUseLocalTextureAlphaOnly );
-
- /* if ("upper_shirt" == local_texture_name)
- mLocalTexture = TEX_UPPER_SHIRT; */
- mLocalTexture = TEX_NUM_INDICES;
- for (const LLAvatarAppearanceDictionary::Textures::value_type& dict_pair : LLAvatarAppearance::getDictionary()->getTextures())
- {
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = dict_pair.second;
- if (local_texture_name == texture_dict->mName)
- {
- mLocalTexture = dict_pair.first;
- break;
- }
- }
- if (mLocalTexture == TEX_NUM_INDICES)
- {
- LL_WARNS() << "<texture> element has invalid local_texture attribute: " << mName << " " << local_texture_name << LL_ENDL;
- return false;
- }
- }
- else
- {
- LL_WARNS() << "<texture> element is missing a required attribute. " << mName << LL_ENDL;
- return false;
- }
- }
-
- for (LLXmlTreeNode* maskNode = node->getChildByName( "morph_mask" );
- maskNode;
- maskNode = node->getNextNamedChild())
- {
- std::string morph_name;
- static LLStdStringHandle morph_name_string = LLXmlTree::addAttributeString("morph_name");
- if (maskNode->getFastAttributeString(morph_name_string, morph_name))
- {
- bool invert = false;
- static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
- maskNode->getFastAttributeBOOL(invert_string, invert);
- mMorphNameList.push_back(std::pair<std::string,bool>(morph_name,invert));
- }
- }
-
- // <param> optional sub-element (color or alpha params)
- for (LLXmlTreeNode* child = node->getChildByName( "param" );
- child;
- child = node->getNextNamedChild())
- {
- if( child->getChildByName( "param_color" ) )
- {
- // <param><param_color/></param>
- LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo();
- if (!info->parseXml(child))
- {
- delete info;
- return false;
- }
- mParamColorInfoList.push_back(info);
- }
- else if( child->getChildByName( "param_alpha" ) )
- {
- // <param><param_alpha/></param>
- LLTexLayerParamAlphaInfo* info = new LLTexLayerParamAlphaInfo( );
- if (!info->parseXml(child))
- {
- delete info;
- return false;
- }
- mParamAlphaInfoList.push_back(info);
- }
- }
-
- return true;
-}
-
-bool LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance)
-{
- bool success = true;
- for (LLTexLayerParamColorInfo* color_info : mParamColorInfoList)
- {
- LLTexLayerParamColor* param_color = new LLTexLayerParamColor(appearance);
- if (!param_color->setInfo(color_info, true))
- {
- LL_WARNS() << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << LL_ENDL;
- delete param_color;
- success = false;
- }
- }
-
- for (LLTexLayerParamAlphaInfo* alpha_info : mParamAlphaInfoList)
- {
- LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(appearance);
- if (!param_alpha->setInfo(alpha_info, true))
- {
- LL_WARNS() << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << LL_ENDL;
- delete param_alpha;
- success = false;
- }
- }
-
- return success;
-}
-
-LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set):
- mTexLayerSet( layer_set ),
- mMorphMasksValid( false ),
- mInfo(NULL),
- mHasMorph(false)
-{
-}
-
-LLTexLayerInterface::LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable):
- mTexLayerSet( layer.mTexLayerSet ),
- mInfo(NULL)
-{
- // don't add visual params for cloned layers
- setInfo(layer.getInfo(), wearable);
-
- mHasMorph = layer.mHasMorph;
-}
-
-bool LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearable ) // This sets mInfo and calls initialization functions
-{
- // setInfo should only be called once. Code is not robust enough to handle redefinition of a texlayer.
- // Not a critical warning, but could be useful for debugging later issues. -Nyx
- if (mInfo != NULL)
- {
- LL_WARNS() << "mInfo != NULL" << LL_ENDL;
- }
- mInfo = info;
- //mID = info->mID; // No ID
-
- mParamColorList.reserve(mInfo->mParamColorInfoList.size());
- for (LLTexLayerParamColorInfo* color_info : mInfo->mParamColorInfoList)
- {
- LLTexLayerParamColor* param_color;
- if (!wearable)
- {
- param_color = new LLTexLayerParamColor(this);
- if (!param_color->setInfo(color_info, true))
- {
- mInfo = NULL;
- return false;
- }
- }
- else
- {
- param_color = (LLTexLayerParamColor*)wearable->getVisualParam(color_info->getID());
- if (!param_color)
- {
- mInfo = NULL;
- return false;
- }
- }
- mParamColorList.push_back( param_color );
- }
-
- mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size());
- for (LLTexLayerParamAlphaInfo* alpha_info : mInfo->mParamAlphaInfoList)
- {
- LLTexLayerParamAlpha* param_alpha;
- if (!wearable)
- {
- param_alpha = new LLTexLayerParamAlpha( this );
- if (!param_alpha->setInfo(alpha_info, true))
- {
- mInfo = NULL;
- return false;
- }
- }
- else
- {
- param_alpha = (LLTexLayerParamAlpha*) wearable->getVisualParam(alpha_info->getID());
- if (!param_alpha)
- {
- mInfo = NULL;
- return false;
- }
- }
- mParamAlphaList.push_back( param_alpha );
- }
-
- return true;
-}
-
-/*virtual*/ void LLTexLayerInterface::requestUpdate()
-{
- mTexLayerSet->requestUpdate();
-}
-
-const std::string& LLTexLayerInterface::getName() const
-{
- return mInfo->mName;
-}
-
-ETextureIndex LLTexLayerInterface::getLocalTextureIndex() const
-{
- return (ETextureIndex) mInfo->mLocalTexture;
-}
-
-LLWearableType::EType LLTexLayerInterface::getWearableType() const
-{
- ETextureIndex te = getLocalTextureIndex();
- if (TEX_INVALID == te)
- {
- LLWearableType::EType type = LLWearableType::WT_INVALID;
-
- for (LLTexLayerParamColor* param : mParamColorList)
- {
- if (param)
- {
- LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
- if (new_type != LLWearableType::WT_INVALID && new_type != type)
- {
- if (type != LLWearableType::WT_INVALID)
- {
- return LLWearableType::WT_INVALID;
- }
- type = new_type;
- }
- }
- }
-
- for (LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- if (param)
- {
- LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
- if (new_type != LLWearableType::WT_INVALID && new_type != type)
- {
- if (type != LLWearableType::WT_INVALID)
- {
- return LLWearableType::WT_INVALID;
- }
- type = new_type;
- }
- }
- }
-
- return type;
- }
- return LLAvatarAppearance::getDictionary()->getTEWearableType(te);
-}
-
-LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const
-{
- return mInfo->mRenderPass;
-}
-
-const std::string& LLTexLayerInterface::getGlobalColor() const
-{
- return mInfo->mGlobalColor;
-}
-
-bool LLTexLayerInterface::isVisibilityMask() const
-{
- return mInfo->mIsVisibilityMask;
-}
-
-void LLTexLayerInterface::invalidateMorphMasks()
-{
- mMorphMasksValid = false;
-}
-
-LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const
-{
- LLViewerVisualParam *result = NULL;
- for (LLTexLayerParamColor* param : mParamColorList)
- {
- if (param->getID() == index)
- {
- result = param;
- }
- }
- for (LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- if (param->getID() == index)
- {
- result = param;
- }
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// LLTexLayer
-// A single texture layer, consisting of:
-// * color, consisting of either
-// * one or more color parameters (weighted colors)
-// * a reference to a global color
-// * a fixed color with non-zero alpha
-// * opaque white (the default)
-// * (optional) a texture defined by either
-// * a GUID
-// * a texture entry index (TE)
-// * (optional) one or more alpha parameters (weighted alpha textures)
-//-----------------------------------------------------------------------------
-LLTexLayer::LLTexLayer(LLTexLayerSet* const layer_set) :
- LLTexLayerInterface( layer_set ),
- mLocalTextureObject(NULL)
-{
-}
-
-LLTexLayer::LLTexLayer(const LLTexLayer &layer, LLWearable *wearable) :
- LLTexLayerInterface( layer, wearable ),
- mLocalTextureObject(NULL)
-{
-}
-
-LLTexLayer::LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable) :
- LLTexLayerInterface( layer_template, wearable ),
- mLocalTextureObject(lto)
-{
-}
-
-LLTexLayer::~LLTexLayer()
-{
- // mParamAlphaList and mParamColorList are LLViewerVisualParam's and get
- // deleted with ~LLCharacter()
- //std::for_each(mParamAlphaList.begin(), mParamAlphaList.end(), DeletePointer());
- //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
-
- for (alpha_cache_t::value_type& alpha_pair : mAlphaCache)
- {
- U8* alpha_data = alpha_pair.second;
- ll_aligned_free_32(alpha_data);
- }
-
-}
-
-void LLTexLayer::asLLSD(LLSD& sd) const
-{
- // *TODO: Finish
- sd["id"] = getUUID();
-}
-
-//-----------------------------------------------------------------------------
-// setInfo
-//-----------------------------------------------------------------------------
-
-bool LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable )
-{
- return LLTexLayerInterface::setInfo(info, wearable);
-}
-
-//static
-void LLTexLayer::calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color)
-{
- for (const LLTexLayerParamColor* param : param_list)
- {
- LLColor4 param_net = param->getNetColor();
- const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)param->getInfo();
- switch(info->getOperation())
- {
- case LLTexLayerParamColor::OP_ADD:
- net_color += param_net;
- break;
- case LLTexLayerParamColor::OP_MULTIPLY:
- net_color = net_color * param_net;
- break;
- case LLTexLayerParamColor::OP_BLEND:
- net_color = lerp(net_color, param_net, param->getWeight());
- break;
- default:
- llassert(0);
- break;
- }
- }
- net_color.clamp();
-}
-
-/*virtual*/ void LLTexLayer::deleteCaches()
-{
- // Only need to delete caches for alpha params. Color params don't hold extra memory
- for (LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- param->deleteCaches();
- }
-}
-
-bool LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- // *TODO: Is this correct?
- //gPipeline.disableLights();
- stop_glerror();
-
- LLColor4 net_color;
- bool color_specified = findNetColor(&net_color);
-
- if (mTexLayerSet->getAvatarAppearance()->mIsDummy)
- {
- color_specified = true;
- net_color = LLAvatarAppearance::getDummyColor();
- }
-
- bool success = true;
-
- // If you can't see the layer, don't render it.
- if( is_approx_zero( net_color.mV[VW] ) )
- {
- return success;
- }
-
- bool alpha_mask_specified = false;
- param_alpha_list_t::const_iterator iter = mParamAlphaList.begin();
- if( iter != mParamAlphaList.end() )
- {
- // If we have alpha masks, but we're skipping all of them, skip the whole layer.
- // However, we can't do this optimization if we have morph masks that need updating.
-/* if (!mHasMorph)
- {
- bool skip_layer = true;
-
- while( iter != mParamAlphaList.end() )
- {
- const LLTexLayerParamAlpha* param = *iter;
-
- if( !param->getSkip() )
- {
- skip_layer = false;
- break;
- }
-
- iter++;
- }
-
- if( skip_layer )
- {
- return success;
- }
- }//*/
-
- const bool force_render = true;
- renderMorphMasks(x, y, width, height, net_color, bound_target, force_render);
- alpha_mask_specified = true;
- gGL.flush();
- gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA);
- }
-
- gGL.color4fv( net_color.mV);
-
- if( getInfo()->mWriteAllChannels )
- {
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- }
-
- if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly )
- {
- {
- LLGLTexture* tex = NULL;
- if (mLocalTextureObject && mLocalTextureObject->getImage())
- {
- tex = mLocalTextureObject->getImage();
- if (mLocalTextureObject->getID() == IMG_DEFAULT_AVATAR)
- {
- tex = NULL;
- }
- }
- else
- {
- LL_INFOS() << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << LL_ENDL;
- }
-// if( mTexLayerSet->getAvatarAppearance()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) )
- {
- if( tex )
- {
- bool no_alpha_test = getInfo()->mWriteAllChannels;
- if (no_alpha_test)
- {
- gAlphaMaskProgram.setMinimumAlpha(0.f);
- }
-
- LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
-
- gGL.getTexUnit(0)->bind(tex, true);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
-
- gl_rect_2d_simple_tex( width, height );
-
- gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- if (no_alpha_test)
- {
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
- }
- }
-// else
-// {
-// success = false;
-// }
- }
- }
-
- if( !getInfo()->mStaticImageFileName.empty() )
- {
- {
- LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
- if( tex )
- {
- gGL.getTexUnit(0)->bind(tex, true);
- gl_rect_2d_simple_tex( width, height );
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
- else
- {
- success = false;
- }
- }
- }
-
- if(((-1 == getInfo()->mLocalTexture) ||
- getInfo()->mUseLocalTextureAlphaOnly) &&
- getInfo()->mStaticImageFileName.empty() &&
- color_specified )
- {
- gAlphaMaskProgram.setMinimumAlpha(0.000f);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4fv( net_color.mV );
- gl_rect_2d_simple( width, height );
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
-
- if( alpha_mask_specified || getInfo()->mWriteAllChannels )
- {
- // Restore standard blend func value
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- stop_glerror();
- }
-
- if( !success )
- {
- LL_INFOS() << "LLTexLayer::render() partial: " << getInfo()->mName << LL_ENDL;
- }
- return success;
-}
-
-const U8* LLTexLayer::getAlphaData() const
-{
- LLCRC alpha_mask_crc;
- const LLUUID& uuid = getUUID();
- alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
-
- for (const LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- // MULTI-WEARABLE: verify visual parameters used here
- F32 param_weight = param->getWeight();
- alpha_mask_crc.update((U8*)&param_weight, sizeof(F32));
- }
-
- U32 cache_index = alpha_mask_crc.getCRC();
-
- alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index);
- return (iter2 == mAlphaCache.end()) ? 0 : iter2->second;
-}
-
-bool LLTexLayer::findNetColor(LLColor4* net_color) const
-{
- // Color is either:
- // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color)
- // * a reference to a global color
- // * a fixed color with non-zero alpha
- // * opaque white (the default)
-
- if( !mParamColorList.empty() )
- {
- if( !getGlobalColor().empty() )
- {
- net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getInfo()->mGlobalColor ) );
- }
- else if (getInfo()->mFixedColor.mV[VW])
- {
- net_color->setVec( getInfo()->mFixedColor );
- }
- else
- {
- net_color->setVec( 0.f, 0.f, 0.f, 0.f );
- }
-
- calculateTexLayerColor(mParamColorList, *net_color);
- return true;
- }
-
- if( !getGlobalColor().empty() )
- {
- net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getGlobalColor() ) );
- return true;
- }
-
- if( getInfo()->mFixedColor.mV[VW] )
- {
- net_color->setVec( getInfo()->mFixedColor );
- return true;
- }
-
- net_color->setToWhite();
-
- return false; // No need to draw a separate colored polygon
-}
-
-bool LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
-{
- bool success = true;
-
- gGL.flush();
-
- if( !getInfo()->mStaticImageFileName.empty() )
- {
- LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
- if( tex )
- {
- gAlphaMaskProgram.setMinimumAlpha(0.f);
- gGL.getTexUnit(0)->bind(tex, true);
- gl_rect_2d_simple_tex( width, height );
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
- else
- {
- success = false;
- }
- }
- else
- {
- if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES)
- {
- LLGLTexture* tex = mLocalTextureObject->getImage();
- if (tex)
- {
- gAlphaMaskProgram.setMinimumAlpha(0.f);
- gGL.getTexUnit(0)->bind(tex);
- gl_rect_2d_simple_tex( width, height );
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
- }
- }
- }
-
- return success;
-}
-
-/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- addAlphaMask(data, originX, originY, width, height, bound_target);
-}
-
-void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render)
-{
- if (!force_render && !hasMorph())
- {
- LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
- return;
- }
- LL_PROFILE_ZONE_SCOPED;
- bool success = true;
-
- llassert( !mParamAlphaList.empty() );
-
- gAlphaMaskProgram.setMinimumAlpha(0.f);
- gGL.setColorMask(false, true);
-
- LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin();
- // Note: if the first param is a mulitply, multiply against the current buffer's alpha
- if( !first_param || !first_param->getMultiplyBlend() )
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- // Clear the alpha
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
-
- gGL.color4f( 0.f, 0.f, 0.f, 0.f );
- gl_rect_2d_simple( width, height );
- }
-
- // Accumulate alphas
- gGL.color4f( 1.f, 1.f, 1.f, 1.f );
- for (LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- success &= param->render( x, y, width, height );
- if (!success && !force_render)
- {
- LL_DEBUGS() << "Failed to render param " << param->getID() << " ; skipping morph mask." << LL_ENDL;
- return;
- }
- }
-
- // Approximates a min() function
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
-
- // Accumulate the alpha component of the texture
- if( getInfo()->mLocalTexture != -1 )
- {
- LLGLTexture* tex = mLocalTextureObject->getImage();
- if( tex && (tex->getComponents() == 4) )
- {
- LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
-
- gGL.getTexUnit(0)->bind(tex, true);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
-
- gl_rect_2d_simple_tex( width, height );
-
- gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
- }
-
- if( !getInfo()->mStaticImageFileName.empty() && getInfo()->mStaticImageIsMask )
- {
- LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
- if( tex )
- {
- if( (tex->getComponents() == 4) || (tex->getComponents() == 1) )
- {
- gGL.getTexUnit(0)->bind(tex, true);
- gl_rect_2d_simple_tex( width, height );
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
- else
- {
- LL_WARNS() << "Skipping rendering of " << getInfo()->mStaticImageFileName
- << "; expected 1 or 4 components." << LL_ENDL;
- }
- }
- }
-
- // Draw a rectangle with the layer color to multiply the alpha by that color's alpha.
- // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
- if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4fv(layer_color.mV);
- gl_rect_2d_simple( width, height );
- }
-
- gAlphaMaskProgram.setMinimumAlpha(0.004f);
-
- LLGLSUIDefault gls_ui;
-
- gGL.setColorMask(true, true);
-
- if (hasMorph() && success)
- {
- LLCRC alpha_mask_crc;
- const LLUUID& uuid = getUUID();
- alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
-
- for (const LLTexLayerParamAlpha* param : mParamAlphaList)
- {
- F32 param_weight = param->getWeight();
- alpha_mask_crc.update((U8*)&param_weight, sizeof(F32));
- }
-
- U32 cache_index = alpha_mask_crc.getCRC();
- U8* alpha_data = NULL;
- // We believe we need to generate morph masks, do not assume that the cached version is accurate.
- // We can get bad morph masks during login, on minimize, and occasional gl errors.
- // We should only be doing this when we believe something has changed with respect to the user's appearance.
- {
- LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
- // clear out a slot if we have filled our cache
- S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
- while ((S32)mAlphaCache.size() >= max_cache_entries)
- {
- alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry
- alpha_data = iter2->second;
- ll_aligned_free_32(alpha_data);
- mAlphaCache.erase(iter2);
- }
-
- // GPUs tend to be very uptight about memory alignment as the DMA used to convey
- // said data to the card works better when well-aligned so plain old default-aligned heap mem is a no-no
- //new U8[width * height];
- size_t bytes_per_pixel = 1; // unsigned byte alpha channel only...
- size_t row_size = (width + 3) & ~0x3; // OpenGL 4-byte row align (even for things < 4 bpp...)
- size_t pixels = (row_size * height);
- size_t mem_size = pixels * bytes_per_pixel;
-
- alpha_data = (U8*)ll_aligned_malloc_32(mem_size);
-
- bool skip_readback = LLRender::sNsightDebugSupport; // nSight doesn't support use of glReadPixels
-
- if (!skip_readback)
- {
- if (gGLManager.mIsIntel)
- { // work-around for broken intel drivers which cannot do glReadPixels on an RGBA FBO
- // returning only the alpha portion without locking up downstream
- U8* temp = (U8*)ll_aligned_malloc_32(mem_size << 2); // allocate same size, but RGBA
-
- if (bound_target)
- {
- gGL.getTexUnit(0)->bind(bound_target);
- }
- else
- {
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, 0);
- }
-
- glGetTexImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
-
- U8* alpha_cursor = alpha_data;
- U8* pixel = temp;
- for (int i = 0; i < pixels; i++)
- {
- *alpha_cursor++ = pixel[3];
- pixel += 4;
- }
-
- gGL.getTexUnit(0)->disable();
-
- ll_aligned_free_32(temp);
- }
- else
- { // platforms with working drivers...
- // We just want GL_ALPHA, but that isn't supported in OGL core profile 4.
- static const size_t TEMP_BYTES_PER_PIXEL = 4;
- U8* temp_data = (U8*)ll_aligned_malloc_32(mem_size * TEMP_BYTES_PER_PIXEL);
- glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_data);
- for (size_t pixel = 0; pixel < pixels; pixel++) {
- alpha_data[pixel] = temp_data[(pixel * TEMP_BYTES_PER_PIXEL) + 3];
- }
- ll_aligned_free_32(temp_data);
- }
- }
- else
- {
- ll_aligned_free_32(alpha_data);
- alpha_data = nullptr;
- }
-
- mAlphaCache[cache_index] = alpha_data;
- }
-
- getTexLayerSet()->getAvatarAppearance()->dirtyMesh();
-
- mMorphMasksValid = true;
- getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1);
- }
-}
-
-void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- LL_PROFILE_ZONE_SCOPED;
- S32 size = width * height;
- const U8* alphaData = getAlphaData();
- if (!alphaData && hasAlphaParams())
- {
- LLColor4 net_color;
- findNetColor( &net_color );
- // TODO: eliminate need for layer morph mask valid flag
- invalidateMorphMasks();
- const bool force_render = false;
- renderMorphMasks(originX, originY, width, height, net_color, bound_target, force_render);
- alphaData = getAlphaData();
- }
- if (alphaData)
- {
- for( S32 i = 0; i < size; i++ )
- {
- U8 curAlpha = data[i];
- U16 resultAlpha = curAlpha;
- resultAlpha *= ( ((U16)alphaData[i]) + 1);
- resultAlpha = resultAlpha >> 8;
- data[i] = (U8)resultAlpha;
- }
- }
-}
-
-/*virtual*/ bool LLTexLayer::isInvisibleAlphaMask() const
-{
- if (mLocalTextureObject)
- {
- if (mLocalTextureObject->getID() == IMG_INVISIBLE)
- {
- return true;
- }
- }
-
- return false;
-}
-
-LLUUID LLTexLayer::getUUID() const
-{
- LLUUID uuid;
- if( getInfo()->mLocalTexture != -1 )
- {
- LLGLTexture* tex = mLocalTextureObject->getImage();
- if (tex)
- {
- uuid = mLocalTextureObject->getID();
- }
- }
- if( !getInfo()->mStaticImageFileName.empty() )
- {
- LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
- if( tex )
- {
- uuid = tex->getID();
- }
- }
- return uuid;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLTexLayerTemplate
-// A single texture layer, consisting of:
-// * color, consisting of either
-// * one or more color parameters (weighted colors)
-// * a reference to a global color
-// * a fixed color with non-zero alpha
-// * opaque white (the default)
-// * (optional) a texture defined by either
-// * a GUID
-// * a texture entry index (TE)
-// * (optional) one or more alpha parameters (weighted alpha textures)
-//-----------------------------------------------------------------------------
-LLTexLayerTemplate::LLTexLayerTemplate(LLTexLayerSet* layer_set, LLAvatarAppearance* const appearance) :
- LLTexLayerInterface(layer_set),
- mAvatarAppearance( appearance )
-{
-}
-
-LLTexLayerTemplate::LLTexLayerTemplate(const LLTexLayerTemplate &layer) :
- LLTexLayerInterface(layer),
- mAvatarAppearance(layer.getAvatarAppearance())
-{
-}
-
-LLTexLayerTemplate::~LLTexLayerTemplate()
-{
-}
-
-//-----------------------------------------------------------------------------
-// setInfo
-//-----------------------------------------------------------------------------
-
-/*virtual*/ bool LLTexLayerTemplate::setInfo(const LLTexLayerInfo* info, LLWearable* wearable )
-{
- return LLTexLayerInterface::setInfo(info, wearable);
-}
-
-U32 LLTexLayerTemplate::updateWearableCache() const
-{
- mWearableCache.clear();
-
- LLWearableType::EType wearable_type = getWearableType();
- if (LLWearableType::WT_INVALID == wearable_type)
- {
- //this isn't a cloneable layer
- return 0;
- }
- U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type);
- U32 added = 0;
- for (U32 i = 0; i < num_wearables; i++)
- {
- LLWearable* wearable = getAvatarAppearance()->getWearableData()->getWearable(wearable_type, i);
- if (!wearable)
- {
- continue;
- }
- mWearableCache.push_back(wearable);
- added++;
- }
- return added;
-}
-LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
-{
- if (mWearableCache.size() <= i)
- {
- return NULL;
- }
- LLWearable *wearable = mWearableCache[i];
- LLLocalTextureObject *lto = NULL;
- LLTexLayer *layer = NULL;
- if (wearable)
- {
- lto = wearable->getLocalTextureObject(mInfo->mLocalTexture);
- }
- if (lto)
- {
- layer = lto->getTexLayer(getName());
- }
- return layer;
-}
-
-/*virtual*/ bool LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- if(!mInfo)
- {
- return false ;
- }
-
- bool success = true;
- updateWearableCache();
- for (LLWearable* wearable : mWearableCache)
- {
- LLLocalTextureObject *lto = NULL;
- LLTexLayer *layer = NULL;
- if (wearable)
- {
- lto = wearable->getLocalTextureObject(mInfo->mLocalTexture);
- }
- if (lto)
- {
- layer = lto->getTexLayer(getName());
- }
- if (layer)
- {
- wearable->writeToAvatar(mAvatarAppearance);
- layer->setLTO(lto);
- success &= layer->render(x, y, width, height, bound_target);
- }
- }
-
- return success;
-}
-
-/*virtual*/ bool LLTexLayerTemplate::blendAlphaTexture( S32 x, S32 y, S32 width, S32 height) // Multiplies a single alpha texture against the frame buffer
-{
- bool success = true;
- U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
- {
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- success &= layer->blendAlphaTexture(x,y,width,height);
- }
- }
- return success;
-}
-
-/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
-{
- U32 num_wearables = updateWearableCache();
- U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- layer->addAlphaMask(data, originX, originY, width, height, bound_target);
- }
-}
-
-/*virtual*/ void LLTexLayerTemplate::setHasMorph(bool newval)
-{
- mHasMorph = newval;
- U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
- {
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- layer->setHasMorph(newval);
- }
- }
-}
-
-/*virtual*/ void LLTexLayerTemplate::deleteCaches()
-{
- U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
- {
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- layer->deleteCaches();
- }
- }
-}
-
-/*virtual*/ bool LLTexLayerTemplate::isInvisibleAlphaMask() const
-{
- U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
- {
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- if (layer->isInvisibleAlphaMask())
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-// finds a specific layer based on a passed in name
-//-----------------------------------------------------------------------------
-LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
-{
- for (LLTexLayerInterface* layer : mLayerList)
- {
- if (layer->getName() == name)
- {
- return layer;
- }
- }
- for (LLTexLayerInterface* layer : mMaskLayerList)
- {
- if (layer->getName() == name)
- {
- return layer;
- }
- }
- return NULL;
-}
-
-void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable *wearable)
-{
- // initialize all texlayers with this texture type for this LTO
- for(LLTexLayerInterface* layer : mLayerList)
- {
- LLTexLayerTemplate* layer_template = (LLTexLayerTemplate*)layer;
- if (layer_template->getInfo()->getLocalTexture() == (S32)tex_index)
- {
- lto->addTexLayer(layer_template, wearable);
- }
- }
- for(LLTexLayerInterface* layer : mMaskLayerList)
- {
- LLTexLayerTemplate* layer_template = (LLTexLayerTemplate*)layer;
- if (layer_template->getInfo()->getLocalTexture() == (S32)tex_index)
- {
- lto->addTexLayer(layer_template, wearable);
- }
- }
-}
-//-----------------------------------------------------------------------------
-// LLTexLayerStaticImageList
-//-----------------------------------------------------------------------------
-
-LLTexLayerStaticImageList::LLTexLayerStaticImageList() :
- mGLBytes(0),
- mTGABytes(0),
- mImageNames(16384)
-{
-}
-
-LLTexLayerStaticImageList::~LLTexLayerStaticImageList()
-{
- deleteCachedImages();
-}
-
-void LLTexLayerStaticImageList::dumpByteCount() const
-{
- LL_INFOS() << "Avatar Static Textures " <<
- "KB GL:" << (mGLBytes / 1024) <<
- "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL;
-}
-
-void LLTexLayerStaticImageList::deleteCachedImages()
-{
- if( mGLBytes || mTGABytes )
- {
- LL_INFOS() << "Clearing Static Textures " <<
- "KB GL:" << (mGLBytes / 1024) <<
- "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL;
-
- //mStaticImageLists uses LLPointers, clear() will cause deletion
-
- mStaticImageListTGA.clear();
- mStaticImageList.clear();
-
- mGLBytes = 0;
- mTGABytes = 0;
- }
-}
-
-// Note: in general, for a given image image we'll call either getImageTga() or getTexture().
-// We call getImageTga() if the image is used as an alpha gradient.
-// Otherwise, we call getTexture()
-
-// Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
-// Caches the result to speed identical subsequent requests.
-LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
-{
- LL_PROFILE_ZONE_SCOPED;
- const char *namekey = mImageNames.addString(file_name);
- image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
- if( iter != mStaticImageListTGA.end() )
- {
- return iter->second;
- }
- else
- {
- std::string path;
- path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
- LLPointer<LLImageTGA> image_tga = new LLImageTGA( path );
- if( image_tga->getDataSize() > 0 )
- {
- mStaticImageListTGA[ namekey ] = image_tga;
- mTGABytes += image_tga->getDataSize();
- return image_tga;
- }
- else
- {
- return NULL;
- }
- }
-}
-
-// Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
-// Caches the result to speed identical subsequent requests.
-LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, bool is_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLPointer<LLGLTexture> tex;
- const char *namekey = mImageNames.addString(file_name);
-
- texture_map_t::const_iterator iter = mStaticImageList.find(namekey);
- if( iter != mStaticImageList.end() )
- {
- tex = iter->second;
- }
- else
- {
- llassert(gTextureManagerBridgep);
- tex = gTextureManagerBridgep->getLocalTexture( false );
- LLPointer<LLImageRaw> image_raw = new LLImageRaw;
- if( loadImageRaw( file_name, image_raw ) )
- {
- if( (image_raw->getComponents() == 1) && is_mask )
- {
- // Convert grayscale alpha masks from single channel into RGBA.
- // Fill RGB with black to allow fixed function gl calls
- // to match shader implementation.
- LLPointer<LLImageRaw> alpha_image_raw = image_raw;
- image_raw = new LLImageRaw(image_raw->getWidth(),
- image_raw->getHeight(),
- 4);
-
- image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black);
- }
- tex->createGLTexture(0, image_raw, 0, true, LLGLTexture::LOCAL);
-
- gGL.getTexUnit(0)->bind(tex);
- tex->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- mStaticImageList [ namekey ] = tex;
- mGLBytes += (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
- }
- else
- {
- tex = NULL;
- }
- }
-
- return tex;
-}
-
-// Reads a .tga file, decodes it, and puts the decoded data in image_raw.
-// Returns true if successful.
-bool LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
-{
- LL_PROFILE_ZONE_SCOPED;
- bool success = false;
- std::string path;
- path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
- LLPointer<LLImageTGA> image_tga = new LLImageTGA( path );
- if( image_tga->getDataSize() > 0 )
- {
- // Copy data from tga to raw.
- success = image_tga->decode( image_raw );
- }
-
- return success;
-}
-
+/**
+ * @file lltexlayer.cpp
+ * @brief A texture layer. Used for avatars.
+ *
+ * $LicenseInfo:firstyear=2002&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 "lltexlayer.h"
+
+#include "llavatarappearance.h"
+#include "llcrc.h"
+#include "llimagej2c.h"
+#include "llimagetga.h"
+#include "lldir.h"
+#include "lltexlayerparams.h"
+#include "lltexturemanagerbridge.h"
+#include "lllocaltextureobject.h"
+#include "../llui/llui.h"
+#include "llwearable.h"
+#include "llwearabledata.h"
+#include "llvertexbuffer.h"
+#include "llviewervisualparam.h"
+#include "llfasttimer.h"
+
+//#include "../tools/imdebug/imdebug.h"
+
+using namespace LLAvatarAppearanceDefines;
+
+// runway consolidate
+extern std::string self_av_string();
+
+class LLTexLayerInfo
+{
+ friend class LLTexLayer;
+ friend class LLTexLayerTemplate;
+ friend class LLTexLayerInterface;
+public:
+ LLTexLayerInfo();
+ ~LLTexLayerInfo();
+
+ bool parseXml(LLXmlTreeNode* node);
+ bool createVisualParams(LLAvatarAppearance *appearance);
+ bool isUserSettable() { return mLocalTexture != -1; }
+ S32 getLocalTexture() const { return mLocalTexture; }
+ bool getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; }
+ std::string getName() const { return mName; }
+
+private:
+ std::string mName;
+
+ bool mWriteAllChannels; // Don't use masking. Just write RGBA into buffer,
+ LLTexLayerInterface::ERenderPass mRenderPass;
+
+ std::string mGlobalColor;
+ LLColor4 mFixedColor;
+
+ S32 mLocalTexture;
+ std::string mStaticImageFileName;
+ bool mStaticImageIsMask;
+ bool mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask
+ bool mIsVisibilityMask;
+
+ typedef std::vector< std::pair< std::string,bool > > morph_name_list_t;
+ morph_name_list_t mMorphNameList;
+ param_color_info_list_t mParamColorInfoList;
+ param_alpha_info_list_t mParamAlphaInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLTexLayerSetBuffer
+// The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one.
+//-----------------------------------------------------------------------------
+
+LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner) :
+ mTexLayerSet(owner)
+{
+}
+
+LLTexLayerSetBuffer::~LLTexLayerSetBuffer()
+{
+}
+
+void LLTexLayerSetBuffer::pushProjection() const
+{
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.ortho(0.0f, getCompositeWidth(), 0.0f, getCompositeHeight(), -1.0f, 1.0f);
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+}
+
+void LLTexLayerSetBuffer::popProjection() const
+{
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+}
+
+// virtual
+void LLTexLayerSetBuffer::preRenderTexLayerSet()
+{
+ // Set up an ortho projection
+ pushProjection();
+}
+
+// virtual
+void LLTexLayerSetBuffer::postRenderTexLayerSet(bool success)
+{
+ popProjection();
+}
+
+bool LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
+{
+ // Default color mask for tex layer render
+ gGL.setColorMask(true, true);
+
+ bool success = true;
+
+ gAlphaMaskProgram.bind();
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+
+ LLVertexBuffer::unbind();
+
+ // Composite the color data
+ LLGLSUIDefault gls_ui;
+ success &= mTexLayerSet->render( getCompositeOriginX(), getCompositeOriginY(),
+ getCompositeWidth(), getCompositeHeight(), bound_target );
+ gGL.flush();
+
+ midRenderTexLayerSet(success);
+
+ gAlphaMaskProgram.unbind();
+
+ LLVertexBuffer::unbind();
+
+ // reset GL state
+ gGL.setColorMask(true, true);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// LLTexLayerSetInfo
+// An ordered set of texture layers that get composited into a single texture.
+//-----------------------------------------------------------------------------
+
+LLTexLayerSetInfo::LLTexLayerSetInfo() :
+ mBodyRegion( "" ),
+ mWidth( 512 ),
+ mHeight( 512 ),
+ mClearAlpha( true )
+{
+}
+
+LLTexLayerSetInfo::~LLTexLayerSetInfo( )
+{
+ std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ mLayerInfoList.clear();
+}
+
+bool LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "layer_set" ) );
+ if( !node->hasName( "layer_set" ) )
+ {
+ return false;
+ }
+
+ // body_region
+ static LLStdStringHandle body_region_string = LLXmlTree::addAttributeString("body_region");
+ if( !node->getFastAttributeString( body_region_string, mBodyRegion ) )
+ {
+ LL_WARNS() << "<layer_set> is missing body_region attribute" << LL_ENDL;
+ return false;
+ }
+
+ // width, height
+ static LLStdStringHandle width_string = LLXmlTree::addAttributeString("width");
+ if( !node->getFastAttributeS32( width_string, mWidth ) )
+ {
+ return false;
+ }
+
+ static LLStdStringHandle height_string = LLXmlTree::addAttributeString("height");
+ if( !node->getFastAttributeS32( height_string, mHeight ) )
+ {
+ return false;
+ }
+
+ // Optional alpha component to apply after all compositing is complete.
+ static LLStdStringHandle alpha_tga_file_string = LLXmlTree::addAttributeString("alpha_tga_file");
+ node->getFastAttributeString( alpha_tga_file_string, mStaticAlphaFileName );
+
+ static LLStdStringHandle clear_alpha_string = LLXmlTree::addAttributeString("clear_alpha");
+ node->getFastAttributeBOOL( clear_alpha_string, mClearAlpha );
+
+ // <layer>
+ for (LLXmlTreeNode* child = node->getChildByName( "layer" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ LLTexLayerInfo* info = new LLTexLayerInfo();
+ if( !info->parseXml( child ))
+ {
+ delete info;
+ return false;
+ }
+ mLayerInfoList.push_back( info );
+ }
+ return true;
+}
+
+// creates visual params without generating layersets or layers
+void LLTexLayerSetInfo::createVisualParams(LLAvatarAppearance *appearance)
+{
+ //layer_info_list_t mLayerInfoList;
+ for (LLTexLayerInfo* layer_info : mLayerInfoList)
+ {
+ layer_info->createVisualParams(appearance);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLTexLayerSet
+// An ordered set of texture layers that get composited into a single texture.
+//-----------------------------------------------------------------------------
+
+bool LLTexLayerSet::sHasCaches = false;
+
+LLTexLayerSet::LLTexLayerSet(LLAvatarAppearance* const appearance) :
+ mAvatarAppearance( appearance ),
+ mIsVisible( true ),
+ mBakedTexIndex(LLAvatarAppearanceDefines::BAKED_HEAD),
+ mInfo( NULL )
+{
+}
+
+// virtual
+LLTexLayerSet::~LLTexLayerSet()
+{
+ deleteCaches();
+ std::for_each(mLayerList.begin(), mLayerList.end(), DeletePointer());
+ mLayerList.clear();
+
+ std::for_each(mMaskLayerList.begin(), mMaskLayerList.end(), DeletePointer());
+ mMaskLayerList.clear();
+}
+
+//-----------------------------------------------------------------------------
+// setInfo
+//-----------------------------------------------------------------------------
+
+bool LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info)
+{
+ llassert(mInfo == NULL);
+ mInfo = info;
+ //mID = info->mID; // No ID
+
+ mLayerList.reserve(info->mLayerInfoList.size());
+ for (LLTexLayerInfo* layer_info : info->mLayerInfoList)
+ {
+ LLTexLayerInterface *layer = NULL;
+ if (layer_info->isUserSettable())
+ {
+ layer = new LLTexLayerTemplate( this, getAvatarAppearance() );
+ }
+ else
+ {
+ layer = new LLTexLayer(this);
+ }
+ // this is the first time this layer (of either type) is being created - make sure you add the parameters to the avatar appearance
+ if (!layer->setInfo(layer_info, NULL))
+ {
+ mInfo = NULL;
+ return false;
+ }
+ if (!layer->isVisibilityMask())
+ {
+ mLayerList.push_back( layer );
+ }
+ else
+ {
+ mMaskLayerList.push_back(layer);
+ }
+ }
+
+ requestUpdate();
+
+ stop_glerror();
+
+ return true;
+}
+
+#if 0 // obsolete
+//-----------------------------------------------------------------------------
+// parseData
+//-----------------------------------------------------------------------------
+
+bool LLTexLayerSet::parseData(LLXmlTreeNode* node)
+{
+ LLTexLayerSetInfo *info = new LLTexLayerSetInfo;
+
+ if (!info->parseXml(node))
+ {
+ delete info;
+ return false;
+ }
+ if (!setInfo(info))
+ {
+ delete info;
+ return false;
+ }
+ return true;
+}
+#endif
+
+void LLTexLayerSet::deleteCaches()
+{
+ for(LLTexLayerInterface* layer : mLayerList)
+ {
+ layer->deleteCaches();
+ }
+ for (LLTexLayerInterface* layer : mMaskLayerList)
+ {
+ layer->deleteCaches();
+ }
+}
+
+
+bool LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target )
+{
+ bool success = true;
+ mIsVisible = true;
+
+ if (mMaskLayerList.size() > 0)
+ {
+ for (LLTexLayerInterface* layer : mMaskLayerList)
+ {
+ if (layer->isInvisibleAlphaMask())
+ {
+ mIsVisible = false;
+ }
+ }
+ }
+
+ LLGLSUIDefault gls_ui;
+ LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
+ gGL.setColorMask(true, true);
+
+ // clear buffer area to ensure we don't pick up UI elements
+ {
+ gGL.flush();
+ gAlphaMaskProgram.setMinimumAlpha(0.0f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4f( 0.f, 0.f, 0.f, 1.f );
+
+ gl_rect_2d_simple( width, height );
+
+ gGL.flush();
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+
+ if (mIsVisible)
+ {
+ // composite color layers
+ for(LLTexLayerInterface* layer : mLayerList)
+ {
+ if (layer->getRenderPass() == LLTexLayer::RP_COLOR)
+ {
+ gGL.flush();
+ success &= layer->render(x, y, width, height, bound_target);
+ gGL.flush();
+ }
+ }
+
+ renderAlphaMaskTextures(x, y, width, height, bound_target, false);
+
+ stop_glerror();
+ }
+ else
+ {
+ gGL.flush();
+
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4f( 0.f, 0.f, 0.f, 0.f );
+
+ gl_rect_2d_simple( width, height );
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ gGL.flush();
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+
+ return success;
+}
+
+
+bool LLTexLayerSet::isBodyRegion(const std::string& region) const
+{
+ return mInfo->mBodyRegion == region;
+}
+
+const std::string LLTexLayerSet::getBodyRegionName() const
+{
+ return mInfo->mBodyRegion;
+}
+
+void LLTexLayerSet::destroyComposite()
+{
+ if( mComposite )
+ {
+ mComposite = NULL;
+ }
+}
+
+LLTexLayerSetBuffer* LLTexLayerSet::getComposite()
+{
+ if (!mComposite)
+ {
+ createComposite();
+ }
+ return mComposite;
+}
+
+const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
+{
+ return mComposite;
+}
+
+void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ memset(data, 255, width * height);
+
+ for(LLTexLayerInterface* layer : mLayerList)
+ {
+ layer->gatherAlphaMasks(data, origin_x, origin_y, width, height, bound_target);
+ }
+
+ // Set alpha back to that of our alpha masks.
+ renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true);
+}
+
+void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ const LLTexLayerSetInfo *info = getInfo();
+
+ gGL.setColorMask(false, true);
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+
+ // (Optionally) replace alpha with a single component image from a tga file.
+ if (!info->mStaticAlphaFileName.empty())
+ {
+ gGL.flush();
+ {
+ LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, true);
+ if( tex )
+ {
+ LLGLSUIDefault gls_ui;
+ gGL.getTexUnit(0)->bind(tex);
+ gl_rect_2d_simple_tex( width, height );
+ }
+ }
+ gGL.flush();
+ }
+ else if (forceClear || info->mClearAlpha || (mMaskLayerList.size() > 0))
+ {
+ // Set the alpha channel to one (clean up after previous blending)
+ gGL.flush();
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4f( 0.f, 0.f, 0.f, 1.f );
+
+ gl_rect_2d_simple( width, height );
+
+ gGL.flush();
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+
+ // (Optional) Mask out part of the baked texture with alpha masks
+ // will still have an effect even if mClearAlpha is set or the alpha component was replaced
+ if (mMaskLayerList.size() > 0)
+ {
+ gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
+ for (LLTexLayerInterface* layer : mMaskLayerList)
+ {
+ gGL.flush();
+ layer->blendAlphaTexture(x,y,width, height);
+ gGL.flush();
+ }
+
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ gGL.setColorMask(true, true);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+}
+
+void LLTexLayerSet::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components)
+{
+ mAvatarAppearance->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex);
+}
+
+bool LLTexLayerSet::isMorphValid() const
+{
+ for(const LLTexLayerInterface* layer : mLayerList)
+ {
+ if (layer && !layer->isMorphValid())
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void LLTexLayerSet::invalidateMorphMasks()
+{
+ for(LLTexLayerInterface* layer : mLayerList)
+ {
+ if (layer)
+ {
+ layer->invalidateMorphMasks();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// LLTexLayerInfo
+//-----------------------------------------------------------------------------
+LLTexLayerInfo::LLTexLayerInfo() :
+ mWriteAllChannels( false ),
+ mRenderPass(LLTexLayer::RP_COLOR),
+ mFixedColor( 0.f, 0.f, 0.f, 0.f ),
+ mLocalTexture( -1 ),
+ mStaticImageIsMask( false ),
+ mUseLocalTextureAlphaOnly(false),
+ mIsVisibilityMask(false)
+{
+}
+
+LLTexLayerInfo::~LLTexLayerInfo( )
+{
+ std::for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
+ mParamColorInfoList.clear();
+ std::for_each(mParamAlphaInfoList.begin(), mParamAlphaInfoList.end(), DeletePointer());
+ mParamAlphaInfoList.clear();
+}
+
+bool LLTexLayerInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert( node->hasName( "layer" ) );
+
+ // name attribute
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if( !node->getFastAttributeString( name_string, mName ) )
+ {
+ return false;
+ }
+
+ static LLStdStringHandle write_all_channels_string = LLXmlTree::addAttributeString("write_all_channels");
+ node->getFastAttributeBOOL( write_all_channels_string, mWriteAllChannels );
+
+ std::string render_pass_name;
+ static LLStdStringHandle render_pass_string = LLXmlTree::addAttributeString("render_pass");
+ if( node->getFastAttributeString( render_pass_string, render_pass_name ) )
+ {
+ if( render_pass_name == "bump" )
+ {
+ mRenderPass = LLTexLayer::RP_BUMP;
+ }
+ }
+
+ // Note: layers can have either a "global_color" attrib, a "fixed_color" attrib, or a <param_color> child.
+ // global color attribute (optional)
+ static LLStdStringHandle global_color_string = LLXmlTree::addAttributeString("global_color");
+ node->getFastAttributeString( global_color_string, mGlobalColor );
+
+ // Visibility mask (optional)
+ bool is_visibility;
+ static LLStdStringHandle visibility_mask_string = LLXmlTree::addAttributeString("visibility_mask");
+ if (node->getFastAttributeBOOL(visibility_mask_string, is_visibility))
+ {
+ mIsVisibilityMask = is_visibility;
+ }
+
+ // color attribute (optional)
+ LLColor4U color4u;
+ static LLStdStringHandle fixed_color_string = LLXmlTree::addAttributeString("fixed_color");
+ if( node->getFastAttributeColor4U( fixed_color_string, color4u ) )
+ {
+ mFixedColor.setVec( color4u );
+ }
+
+ // <texture> optional sub-element
+ for (LLXmlTreeNode* texture_node = node->getChildByName( "texture" );
+ texture_node;
+ texture_node = node->getNextNamedChild())
+ {
+ std::string local_texture_name;
+ static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
+ static LLStdStringHandle local_texture_string = LLXmlTree::addAttributeString("local_texture");
+ static LLStdStringHandle file_is_mask_string = LLXmlTree::addAttributeString("file_is_mask");
+ static LLStdStringHandle local_texture_alpha_only_string = LLXmlTree::addAttributeString("local_texture_alpha_only");
+ if( texture_node->getFastAttributeString( tga_file_string, mStaticImageFileName ) )
+ {
+ texture_node->getFastAttributeBOOL( file_is_mask_string, mStaticImageIsMask );
+ }
+ else if (texture_node->getFastAttributeString(local_texture_string, local_texture_name))
+ {
+ texture_node->getFastAttributeBOOL( local_texture_alpha_only_string, mUseLocalTextureAlphaOnly );
+
+ /* if ("upper_shirt" == local_texture_name)
+ mLocalTexture = TEX_UPPER_SHIRT; */
+ mLocalTexture = TEX_NUM_INDICES;
+ for (const LLAvatarAppearanceDictionary::Textures::value_type& dict_pair : LLAvatarAppearance::getDictionary()->getTextures())
+ {
+ const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = dict_pair.second;
+ if (local_texture_name == texture_dict->mName)
+ {
+ mLocalTexture = dict_pair.first;
+ break;
+ }
+ }
+ if (mLocalTexture == TEX_NUM_INDICES)
+ {
+ LL_WARNS() << "<texture> element has invalid local_texture attribute: " << mName << " " << local_texture_name << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "<texture> element is missing a required attribute. " << mName << LL_ENDL;
+ return false;
+ }
+ }
+
+ for (LLXmlTreeNode* maskNode = node->getChildByName( "morph_mask" );
+ maskNode;
+ maskNode = node->getNextNamedChild())
+ {
+ std::string morph_name;
+ static LLStdStringHandle morph_name_string = LLXmlTree::addAttributeString("morph_name");
+ if (maskNode->getFastAttributeString(morph_name_string, morph_name))
+ {
+ bool invert = false;
+ static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
+ maskNode->getFastAttributeBOOL(invert_string, invert);
+ mMorphNameList.push_back(std::pair<std::string,bool>(morph_name,invert));
+ }
+ }
+
+ // <param> optional sub-element (color or alpha params)
+ for (LLXmlTreeNode* child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if( child->getChildByName( "param_color" ) )
+ {
+ // <param><param_color/></param>
+ LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo();
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return false;
+ }
+ mParamColorInfoList.push_back(info);
+ }
+ else if( child->getChildByName( "param_alpha" ) )
+ {
+ // <param><param_alpha/></param>
+ LLTexLayerParamAlphaInfo* info = new LLTexLayerParamAlphaInfo( );
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return false;
+ }
+ mParamAlphaInfoList.push_back(info);
+ }
+ }
+
+ return true;
+}
+
+bool LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance)
+{
+ bool success = true;
+ for (LLTexLayerParamColorInfo* color_info : mParamColorInfoList)
+ {
+ LLTexLayerParamColor* param_color = new LLTexLayerParamColor(appearance);
+ if (!param_color->setInfo(color_info, true))
+ {
+ LL_WARNS() << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << LL_ENDL;
+ delete param_color;
+ success = false;
+ }
+ }
+
+ for (LLTexLayerParamAlphaInfo* alpha_info : mParamAlphaInfoList)
+ {
+ LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(appearance);
+ if (!param_alpha->setInfo(alpha_info, true))
+ {
+ LL_WARNS() << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << LL_ENDL;
+ delete param_alpha;
+ success = false;
+ }
+ }
+
+ return success;
+}
+
+LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set):
+ mTexLayerSet( layer_set ),
+ mMorphMasksValid( false ),
+ mInfo(NULL),
+ mHasMorph(false)
+{
+}
+
+LLTexLayerInterface::LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable):
+ mTexLayerSet( layer.mTexLayerSet ),
+ mInfo(NULL)
+{
+ // don't add visual params for cloned layers
+ setInfo(layer.getInfo(), wearable);
+
+ mHasMorph = layer.mHasMorph;
+}
+
+bool LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearable ) // This sets mInfo and calls initialization functions
+{
+ // setInfo should only be called once. Code is not robust enough to handle redefinition of a texlayer.
+ // Not a critical warning, but could be useful for debugging later issues. -Nyx
+ if (mInfo != NULL)
+ {
+ LL_WARNS() << "mInfo != NULL" << LL_ENDL;
+ }
+ mInfo = info;
+ //mID = info->mID; // No ID
+
+ mParamColorList.reserve(mInfo->mParamColorInfoList.size());
+ for (LLTexLayerParamColorInfo* color_info : mInfo->mParamColorInfoList)
+ {
+ LLTexLayerParamColor* param_color;
+ if (!wearable)
+ {
+ param_color = new LLTexLayerParamColor(this);
+ if (!param_color->setInfo(color_info, true))
+ {
+ mInfo = NULL;
+ return false;
+ }
+ }
+ else
+ {
+ param_color = (LLTexLayerParamColor*)wearable->getVisualParam(color_info->getID());
+ if (!param_color)
+ {
+ mInfo = NULL;
+ return false;
+ }
+ }
+ mParamColorList.push_back( param_color );
+ }
+
+ mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size());
+ for (LLTexLayerParamAlphaInfo* alpha_info : mInfo->mParamAlphaInfoList)
+ {
+ LLTexLayerParamAlpha* param_alpha;
+ if (!wearable)
+ {
+ param_alpha = new LLTexLayerParamAlpha( this );
+ if (!param_alpha->setInfo(alpha_info, true))
+ {
+ mInfo = NULL;
+ return false;
+ }
+ }
+ else
+ {
+ param_alpha = (LLTexLayerParamAlpha*) wearable->getVisualParam(alpha_info->getID());
+ if (!param_alpha)
+ {
+ mInfo = NULL;
+ return false;
+ }
+ }
+ mParamAlphaList.push_back( param_alpha );
+ }
+
+ return true;
+}
+
+/*virtual*/ void LLTexLayerInterface::requestUpdate()
+{
+ mTexLayerSet->requestUpdate();
+}
+
+const std::string& LLTexLayerInterface::getName() const
+{
+ return mInfo->mName;
+}
+
+ETextureIndex LLTexLayerInterface::getLocalTextureIndex() const
+{
+ return (ETextureIndex) mInfo->mLocalTexture;
+}
+
+LLWearableType::EType LLTexLayerInterface::getWearableType() const
+{
+ ETextureIndex te = getLocalTextureIndex();
+ if (TEX_INVALID == te)
+ {
+ LLWearableType::EType type = LLWearableType::WT_INVALID;
+
+ for (LLTexLayerParamColor* param : mParamColorList)
+ {
+ if (param)
+ {
+ LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
+ if (new_type != LLWearableType::WT_INVALID && new_type != type)
+ {
+ if (type != LLWearableType::WT_INVALID)
+ {
+ return LLWearableType::WT_INVALID;
+ }
+ type = new_type;
+ }
+ }
+ }
+
+ for (LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ if (param)
+ {
+ LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
+ if (new_type != LLWearableType::WT_INVALID && new_type != type)
+ {
+ if (type != LLWearableType::WT_INVALID)
+ {
+ return LLWearableType::WT_INVALID;
+ }
+ type = new_type;
+ }
+ }
+ }
+
+ return type;
+ }
+ return LLAvatarAppearance::getDictionary()->getTEWearableType(te);
+}
+
+LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const
+{
+ return mInfo->mRenderPass;
+}
+
+const std::string& LLTexLayerInterface::getGlobalColor() const
+{
+ return mInfo->mGlobalColor;
+}
+
+bool LLTexLayerInterface::isVisibilityMask() const
+{
+ return mInfo->mIsVisibilityMask;
+}
+
+void LLTexLayerInterface::invalidateMorphMasks()
+{
+ mMorphMasksValid = false;
+}
+
+LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const
+{
+ LLViewerVisualParam *result = NULL;
+ for (LLTexLayerParamColor* param : mParamColorList)
+ {
+ if (param->getID() == index)
+ {
+ result = param;
+ }
+ }
+ for (LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ if (param->getID() == index)
+ {
+ result = param;
+ }
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// LLTexLayer
+// A single texture layer, consisting of:
+// * color, consisting of either
+// * one or more color parameters (weighted colors)
+// * a reference to a global color
+// * a fixed color with non-zero alpha
+// * opaque white (the default)
+// * (optional) a texture defined by either
+// * a GUID
+// * a texture entry index (TE)
+// * (optional) one or more alpha parameters (weighted alpha textures)
+//-----------------------------------------------------------------------------
+LLTexLayer::LLTexLayer(LLTexLayerSet* const layer_set) :
+ LLTexLayerInterface( layer_set ),
+ mLocalTextureObject(NULL)
+{
+}
+
+LLTexLayer::LLTexLayer(const LLTexLayer &layer, LLWearable *wearable) :
+ LLTexLayerInterface( layer, wearable ),
+ mLocalTextureObject(NULL)
+{
+}
+
+LLTexLayer::LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable) :
+ LLTexLayerInterface( layer_template, wearable ),
+ mLocalTextureObject(lto)
+{
+}
+
+LLTexLayer::~LLTexLayer()
+{
+ // mParamAlphaList and mParamColorList are LLViewerVisualParam's and get
+ // deleted with ~LLCharacter()
+ //std::for_each(mParamAlphaList.begin(), mParamAlphaList.end(), DeletePointer());
+ //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
+
+ for (alpha_cache_t::value_type& alpha_pair : mAlphaCache)
+ {
+ U8* alpha_data = alpha_pair.second;
+ ll_aligned_free_32(alpha_data);
+ }
+
+}
+
+void LLTexLayer::asLLSD(LLSD& sd) const
+{
+ // *TODO: Finish
+ sd["id"] = getUUID();
+}
+
+//-----------------------------------------------------------------------------
+// setInfo
+//-----------------------------------------------------------------------------
+
+bool LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable )
+{
+ return LLTexLayerInterface::setInfo(info, wearable);
+}
+
+//static
+void LLTexLayer::calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color)
+{
+ for (const LLTexLayerParamColor* param : param_list)
+ {
+ LLColor4 param_net = param->getNetColor();
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)param->getInfo();
+ switch(info->getOperation())
+ {
+ case LLTexLayerParamColor::OP_ADD:
+ net_color += param_net;
+ break;
+ case LLTexLayerParamColor::OP_MULTIPLY:
+ net_color = net_color * param_net;
+ break;
+ case LLTexLayerParamColor::OP_BLEND:
+ net_color = lerp(net_color, param_net, param->getWeight());
+ break;
+ default:
+ llassert(0);
+ break;
+ }
+ }
+ net_color.clamp();
+}
+
+/*virtual*/ void LLTexLayer::deleteCaches()
+{
+ // Only need to delete caches for alpha params. Color params don't hold extra memory
+ for (LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ param->deleteCaches();
+ }
+}
+
+bool LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ // *TODO: Is this correct?
+ //gPipeline.disableLights();
+ stop_glerror();
+
+ LLColor4 net_color;
+ bool color_specified = findNetColor(&net_color);
+
+ if (mTexLayerSet->getAvatarAppearance()->mIsDummy)
+ {
+ color_specified = true;
+ net_color = LLAvatarAppearance::getDummyColor();
+ }
+
+ bool success = true;
+
+ // If you can't see the layer, don't render it.
+ if( is_approx_zero( net_color.mV[VW] ) )
+ {
+ return success;
+ }
+
+ bool alpha_mask_specified = false;
+ param_alpha_list_t::const_iterator iter = mParamAlphaList.begin();
+ if( iter != mParamAlphaList.end() )
+ {
+ // If we have alpha masks, but we're skipping all of them, skip the whole layer.
+ // However, we can't do this optimization if we have morph masks that need updating.
+/* if (!mHasMorph)
+ {
+ bool skip_layer = true;
+
+ while( iter != mParamAlphaList.end() )
+ {
+ const LLTexLayerParamAlpha* param = *iter;
+
+ if( !param->getSkip() )
+ {
+ skip_layer = false;
+ break;
+ }
+
+ iter++;
+ }
+
+ if( skip_layer )
+ {
+ return success;
+ }
+ }//*/
+
+ const bool force_render = true;
+ renderMorphMasks(x, y, width, height, net_color, bound_target, force_render);
+ alpha_mask_specified = true;
+ gGL.flush();
+ gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA);
+ }
+
+ gGL.color4fv( net_color.mV);
+
+ if( getInfo()->mWriteAllChannels )
+ {
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+ }
+
+ if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly )
+ {
+ {
+ LLGLTexture* tex = NULL;
+ if (mLocalTextureObject && mLocalTextureObject->getImage())
+ {
+ tex = mLocalTextureObject->getImage();
+ if (mLocalTextureObject->getID() == IMG_DEFAULT_AVATAR)
+ {
+ tex = NULL;
+ }
+ }
+ else
+ {
+ LL_INFOS() << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << LL_ENDL;
+ }
+// if( mTexLayerSet->getAvatarAppearance()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) )
+ {
+ if( tex )
+ {
+ bool no_alpha_test = getInfo()->mWriteAllChannels;
+ if (no_alpha_test)
+ {
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+ }
+
+ LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
+
+ gGL.getTexUnit(0)->bind(tex, true);
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+
+ gl_rect_2d_simple_tex( width, height );
+
+ gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ if (no_alpha_test)
+ {
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+ }
+ }
+// else
+// {
+// success = false;
+// }
+ }
+ }
+
+ if( !getInfo()->mStaticImageFileName.empty() )
+ {
+ {
+ LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
+ if( tex )
+ {
+ gGL.getTexUnit(0)->bind(tex, true);
+ gl_rect_2d_simple_tex( width, height );
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ }
+
+ if(((-1 == getInfo()->mLocalTexture) ||
+ getInfo()->mUseLocalTextureAlphaOnly) &&
+ getInfo()->mStaticImageFileName.empty() &&
+ color_specified )
+ {
+ gAlphaMaskProgram.setMinimumAlpha(0.000f);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4fv( net_color.mV );
+ gl_rect_2d_simple( width, height );
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+
+ if( alpha_mask_specified || getInfo()->mWriteAllChannels )
+ {
+ // Restore standard blend func value
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ stop_glerror();
+ }
+
+ if( !success )
+ {
+ LL_INFOS() << "LLTexLayer::render() partial: " << getInfo()->mName << LL_ENDL;
+ }
+ return success;
+}
+
+const U8* LLTexLayer::getAlphaData() const
+{
+ LLCRC alpha_mask_crc;
+ const LLUUID& uuid = getUUID();
+ alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
+
+ for (const LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ // MULTI-WEARABLE: verify visual parameters used here
+ F32 param_weight = param->getWeight();
+ alpha_mask_crc.update((U8*)&param_weight, sizeof(F32));
+ }
+
+ U32 cache_index = alpha_mask_crc.getCRC();
+
+ alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index);
+ return (iter2 == mAlphaCache.end()) ? 0 : iter2->second;
+}
+
+bool LLTexLayer::findNetColor(LLColor4* net_color) const
+{
+ // Color is either:
+ // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color)
+ // * a reference to a global color
+ // * a fixed color with non-zero alpha
+ // * opaque white (the default)
+
+ if( !mParamColorList.empty() )
+ {
+ if( !getGlobalColor().empty() )
+ {
+ net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getInfo()->mGlobalColor ) );
+ }
+ else if (getInfo()->mFixedColor.mV[VW])
+ {
+ net_color->setVec( getInfo()->mFixedColor );
+ }
+ else
+ {
+ net_color->setVec( 0.f, 0.f, 0.f, 0.f );
+ }
+
+ calculateTexLayerColor(mParamColorList, *net_color);
+ return true;
+ }
+
+ if( !getGlobalColor().empty() )
+ {
+ net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getGlobalColor() ) );
+ return true;
+ }
+
+ if( getInfo()->mFixedColor.mV[VW] )
+ {
+ net_color->setVec( getInfo()->mFixedColor );
+ return true;
+ }
+
+ net_color->setToWhite();
+
+ return false; // No need to draw a separate colored polygon
+}
+
+bool LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
+{
+ bool success = true;
+
+ gGL.flush();
+
+ if( !getInfo()->mStaticImageFileName.empty() )
+ {
+ LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
+ if( tex )
+ {
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+ gGL.getTexUnit(0)->bind(tex, true);
+ gl_rect_2d_simple_tex( width, height );
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else
+ {
+ if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES)
+ {
+ LLGLTexture* tex = mLocalTextureObject->getImage();
+ if (tex)
+ {
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+ gGL.getTexUnit(0)->bind(tex);
+ gl_rect_2d_simple_tex( width, height );
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+ }
+ }
+ }
+
+ return success;
+}
+
+/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ addAlphaMask(data, originX, originY, width, height, bound_target);
+}
+
+void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render)
+{
+ if (!force_render && !hasMorph())
+ {
+ LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
+ return;
+ }
+ LL_PROFILE_ZONE_SCOPED;
+ bool success = true;
+
+ llassert( !mParamAlphaList.empty() );
+
+ gAlphaMaskProgram.setMinimumAlpha(0.f);
+ gGL.setColorMask(false, true);
+
+ LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin();
+ // Note: if the first param is a mulitply, multiply against the current buffer's alpha
+ if( !first_param || !first_param->getMultiplyBlend() )
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // Clear the alpha
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+
+ gGL.color4f( 0.f, 0.f, 0.f, 0.f );
+ gl_rect_2d_simple( width, height );
+ }
+
+ // Accumulate alphas
+ gGL.color4f( 1.f, 1.f, 1.f, 1.f );
+ for (LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ success &= param->render( x, y, width, height );
+ if (!success && !force_render)
+ {
+ LL_DEBUGS() << "Failed to render param " << param->getID() << " ; skipping morph mask." << LL_ENDL;
+ return;
+ }
+ }
+
+ // Approximates a min() function
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
+
+ // Accumulate the alpha component of the texture
+ if( getInfo()->mLocalTexture != -1 )
+ {
+ LLGLTexture* tex = mLocalTextureObject->getImage();
+ if( tex && (tex->getComponents() == 4) )
+ {
+ LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
+
+ gGL.getTexUnit(0)->bind(tex, true);
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+
+ gl_rect_2d_simple_tex( width, height );
+
+ gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ }
+
+ if( !getInfo()->mStaticImageFileName.empty() && getInfo()->mStaticImageIsMask )
+ {
+ LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
+ if( tex )
+ {
+ if( (tex->getComponents() == 4) || (tex->getComponents() == 1) )
+ {
+ gGL.getTexUnit(0)->bind(tex, true);
+ gl_rect_2d_simple_tex( width, height );
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ else
+ {
+ LL_WARNS() << "Skipping rendering of " << getInfo()->mStaticImageFileName
+ << "; expected 1 or 4 components." << LL_ENDL;
+ }
+ }
+ }
+
+ // Draw a rectangle with the layer color to multiply the alpha by that color's alpha.
+ // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
+ if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4fv(layer_color.mV);
+ gl_rect_2d_simple( width, height );
+ }
+
+ gAlphaMaskProgram.setMinimumAlpha(0.004f);
+
+ LLGLSUIDefault gls_ui;
+
+ gGL.setColorMask(true, true);
+
+ if (hasMorph() && success)
+ {
+ LLCRC alpha_mask_crc;
+ const LLUUID& uuid = getUUID();
+ alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
+
+ for (const LLTexLayerParamAlpha* param : mParamAlphaList)
+ {
+ F32 param_weight = param->getWeight();
+ alpha_mask_crc.update((U8*)&param_weight, sizeof(F32));
+ }
+
+ U32 cache_index = alpha_mask_crc.getCRC();
+ U8* alpha_data = NULL;
+ // We believe we need to generate morph masks, do not assume that the cached version is accurate.
+ // We can get bad morph masks during login, on minimize, and occasional gl errors.
+ // We should only be doing this when we believe something has changed with respect to the user's appearance.
+ {
+ LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
+ // clear out a slot if we have filled our cache
+ S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
+ while ((S32)mAlphaCache.size() >= max_cache_entries)
+ {
+ alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry
+ alpha_data = iter2->second;
+ ll_aligned_free_32(alpha_data);
+ mAlphaCache.erase(iter2);
+ }
+
+ // GPUs tend to be very uptight about memory alignment as the DMA used to convey
+ // said data to the card works better when well-aligned so plain old default-aligned heap mem is a no-no
+ //new U8[width * height];
+ size_t bytes_per_pixel = 1; // unsigned byte alpha channel only...
+ size_t row_size = (width + 3) & ~0x3; // OpenGL 4-byte row align (even for things < 4 bpp...)
+ size_t pixels = (row_size * height);
+ size_t mem_size = pixels * bytes_per_pixel;
+
+ alpha_data = (U8*)ll_aligned_malloc_32(mem_size);
+
+ bool skip_readback = LLRender::sNsightDebugSupport; // nSight doesn't support use of glReadPixels
+
+ if (!skip_readback)
+ {
+ if (gGLManager.mIsIntel)
+ { // work-around for broken intel drivers which cannot do glReadPixels on an RGBA FBO
+ // returning only the alpha portion without locking up downstream
+ U8* temp = (U8*)ll_aligned_malloc_32(mem_size << 2); // allocate same size, but RGBA
+
+ if (bound_target)
+ {
+ gGL.getTexUnit(0)->bind(bound_target);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, 0);
+ }
+
+ glGetTexImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
+
+ U8* alpha_cursor = alpha_data;
+ U8* pixel = temp;
+ for (int i = 0; i < pixels; i++)
+ {
+ *alpha_cursor++ = pixel[3];
+ pixel += 4;
+ }
+
+ gGL.getTexUnit(0)->disable();
+
+ ll_aligned_free_32(temp);
+ }
+ else
+ { // platforms with working drivers...
+ // We just want GL_ALPHA, but that isn't supported in OGL core profile 4.
+ static const size_t TEMP_BYTES_PER_PIXEL = 4;
+ U8* temp_data = (U8*)ll_aligned_malloc_32(mem_size * TEMP_BYTES_PER_PIXEL);
+ glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_data);
+ for (size_t pixel = 0; pixel < pixels; pixel++) {
+ alpha_data[pixel] = temp_data[(pixel * TEMP_BYTES_PER_PIXEL) + 3];
+ }
+ ll_aligned_free_32(temp_data);
+ }
+ }
+ else
+ {
+ ll_aligned_free_32(alpha_data);
+ alpha_data = nullptr;
+ }
+
+ mAlphaCache[cache_index] = alpha_data;
+ }
+
+ getTexLayerSet()->getAvatarAppearance()->dirtyMesh();
+
+ mMorphMasksValid = true;
+ getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1);
+ }
+}
+
+void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ S32 size = width * height;
+ const U8* alphaData = getAlphaData();
+ if (!alphaData && hasAlphaParams())
+ {
+ LLColor4 net_color;
+ findNetColor( &net_color );
+ // TODO: eliminate need for layer morph mask valid flag
+ invalidateMorphMasks();
+ const bool force_render = false;
+ renderMorphMasks(originX, originY, width, height, net_color, bound_target, force_render);
+ alphaData = getAlphaData();
+ }
+ if (alphaData)
+ {
+ for( S32 i = 0; i < size; i++ )
+ {
+ U8 curAlpha = data[i];
+ U16 resultAlpha = curAlpha;
+ resultAlpha *= ( ((U16)alphaData[i]) + 1);
+ resultAlpha = resultAlpha >> 8;
+ data[i] = (U8)resultAlpha;
+ }
+ }
+}
+
+/*virtual*/ bool LLTexLayer::isInvisibleAlphaMask() const
+{
+ if (mLocalTextureObject)
+ {
+ if (mLocalTextureObject->getID() == IMG_INVISIBLE)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+LLUUID LLTexLayer::getUUID() const
+{
+ LLUUID uuid;
+ if( getInfo()->mLocalTexture != -1 )
+ {
+ LLGLTexture* tex = mLocalTextureObject->getImage();
+ if (tex)
+ {
+ uuid = mLocalTextureObject->getID();
+ }
+ }
+ if( !getInfo()->mStaticImageFileName.empty() )
+ {
+ LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
+ if( tex )
+ {
+ uuid = tex->getID();
+ }
+ }
+ return uuid;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLTexLayerTemplate
+// A single texture layer, consisting of:
+// * color, consisting of either
+// * one or more color parameters (weighted colors)
+// * a reference to a global color
+// * a fixed color with non-zero alpha
+// * opaque white (the default)
+// * (optional) a texture defined by either
+// * a GUID
+// * a texture entry index (TE)
+// * (optional) one or more alpha parameters (weighted alpha textures)
+//-----------------------------------------------------------------------------
+LLTexLayerTemplate::LLTexLayerTemplate(LLTexLayerSet* layer_set, LLAvatarAppearance* const appearance) :
+ LLTexLayerInterface(layer_set),
+ mAvatarAppearance( appearance )
+{
+}
+
+LLTexLayerTemplate::LLTexLayerTemplate(const LLTexLayerTemplate &layer) :
+ LLTexLayerInterface(layer),
+ mAvatarAppearance(layer.getAvatarAppearance())
+{
+}
+
+LLTexLayerTemplate::~LLTexLayerTemplate()
+{
+}
+
+//-----------------------------------------------------------------------------
+// setInfo
+//-----------------------------------------------------------------------------
+
+/*virtual*/ bool LLTexLayerTemplate::setInfo(const LLTexLayerInfo* info, LLWearable* wearable )
+{
+ return LLTexLayerInterface::setInfo(info, wearable);
+}
+
+U32 LLTexLayerTemplate::updateWearableCache() const
+{
+ mWearableCache.clear();
+
+ LLWearableType::EType wearable_type = getWearableType();
+ if (LLWearableType::WT_INVALID == wearable_type)
+ {
+ //this isn't a cloneable layer
+ return 0;
+ }
+ U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type);
+ U32 added = 0;
+ for (U32 i = 0; i < num_wearables; i++)
+ {
+ LLWearable* wearable = getAvatarAppearance()->getWearableData()->getWearable(wearable_type, i);
+ if (!wearable)
+ {
+ continue;
+ }
+ mWearableCache.push_back(wearable);
+ added++;
+ }
+ return added;
+}
+LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
+{
+ if (mWearableCache.size() <= i)
+ {
+ return NULL;
+ }
+ LLWearable *wearable = mWearableCache[i];
+ LLLocalTextureObject *lto = NULL;
+ LLTexLayer *layer = NULL;
+ if (wearable)
+ {
+ lto = wearable->getLocalTextureObject(mInfo->mLocalTexture);
+ }
+ if (lto)
+ {
+ layer = lto->getTexLayer(getName());
+ }
+ return layer;
+}
+
+/*virtual*/ bool LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ if(!mInfo)
+ {
+ return false ;
+ }
+
+ bool success = true;
+ updateWearableCache();
+ for (LLWearable* wearable : mWearableCache)
+ {
+ LLLocalTextureObject *lto = NULL;
+ LLTexLayer *layer = NULL;
+ if (wearable)
+ {
+ lto = wearable->getLocalTextureObject(mInfo->mLocalTexture);
+ }
+ if (lto)
+ {
+ layer = lto->getTexLayer(getName());
+ }
+ if (layer)
+ {
+ wearable->writeToAvatar(mAvatarAppearance);
+ layer->setLTO(lto);
+ success &= layer->render(x, y, width, height, bound_target);
+ }
+ }
+
+ return success;
+}
+
+/*virtual*/ bool LLTexLayerTemplate::blendAlphaTexture( S32 x, S32 y, S32 width, S32 height) // Multiplies a single alpha texture against the frame buffer
+{
+ bool success = true;
+ U32 num_wearables = updateWearableCache();
+ for (U32 i = 0; i < num_wearables; i++)
+ {
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
+ {
+ success &= layer->blendAlphaTexture(x,y,width,height);
+ }
+ }
+ return success;
+}
+
+/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
+{
+ U32 num_wearables = updateWearableCache();
+ U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
+ {
+ layer->addAlphaMask(data, originX, originY, width, height, bound_target);
+ }
+}
+
+/*virtual*/ void LLTexLayerTemplate::setHasMorph(bool newval)
+{
+ mHasMorph = newval;
+ U32 num_wearables = updateWearableCache();
+ for (U32 i = 0; i < num_wearables; i++)
+ {
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
+ {
+ layer->setHasMorph(newval);
+ }
+ }
+}
+
+/*virtual*/ void LLTexLayerTemplate::deleteCaches()
+{
+ U32 num_wearables = updateWearableCache();
+ for (U32 i = 0; i < num_wearables; i++)
+ {
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
+ {
+ layer->deleteCaches();
+ }
+ }
+}
+
+/*virtual*/ bool LLTexLayerTemplate::isInvisibleAlphaMask() const
+{
+ U32 num_wearables = updateWearableCache();
+ for (U32 i = 0; i < num_wearables; i++)
+ {
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
+ {
+ if (layer->isInvisibleAlphaMask())
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// finds a specific layer based on a passed in name
+//-----------------------------------------------------------------------------
+LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
+{
+ for (LLTexLayerInterface* layer : mLayerList)
+ {
+ if (layer->getName() == name)
+ {
+ return layer;
+ }
+ }
+ for (LLTexLayerInterface* layer : mMaskLayerList)
+ {
+ if (layer->getName() == name)
+ {
+ return layer;
+ }
+ }
+ return NULL;
+}
+
+void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable *wearable)
+{
+ // initialize all texlayers with this texture type for this LTO
+ for(LLTexLayerInterface* layer : mLayerList)
+ {
+ LLTexLayerTemplate* layer_template = (LLTexLayerTemplate*)layer;
+ if (layer_template->getInfo()->getLocalTexture() == (S32)tex_index)
+ {
+ lto->addTexLayer(layer_template, wearable);
+ }
+ }
+ for(LLTexLayerInterface* layer : mMaskLayerList)
+ {
+ LLTexLayerTemplate* layer_template = (LLTexLayerTemplate*)layer;
+ if (layer_template->getInfo()->getLocalTexture() == (S32)tex_index)
+ {
+ lto->addTexLayer(layer_template, wearable);
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// LLTexLayerStaticImageList
+//-----------------------------------------------------------------------------
+
+LLTexLayerStaticImageList::LLTexLayerStaticImageList() :
+ mGLBytes(0),
+ mTGABytes(0),
+ mImageNames(16384)
+{
+}
+
+LLTexLayerStaticImageList::~LLTexLayerStaticImageList()
+{
+ deleteCachedImages();
+}
+
+void LLTexLayerStaticImageList::dumpByteCount() const
+{
+ LL_INFOS() << "Avatar Static Textures " <<
+ "KB GL:" << (mGLBytes / 1024) <<
+ "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL;
+}
+
+void LLTexLayerStaticImageList::deleteCachedImages()
+{
+ if( mGLBytes || mTGABytes )
+ {
+ LL_INFOS() << "Clearing Static Textures " <<
+ "KB GL:" << (mGLBytes / 1024) <<
+ "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL;
+
+ //mStaticImageLists uses LLPointers, clear() will cause deletion
+
+ mStaticImageListTGA.clear();
+ mStaticImageList.clear();
+
+ mGLBytes = 0;
+ mTGABytes = 0;
+ }
+}
+
+// Note: in general, for a given image image we'll call either getImageTga() or getTexture().
+// We call getImageTga() if the image is used as an alpha gradient.
+// Otherwise, we call getTexture()
+
+// Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
+// Caches the result to speed identical subsequent requests.
+LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ const char *namekey = mImageNames.addString(file_name);
+ image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
+ if( iter != mStaticImageListTGA.end() )
+ {
+ return iter->second;
+ }
+ else
+ {
+ std::string path;
+ path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
+ LLPointer<LLImageTGA> image_tga = new LLImageTGA( path );
+ if( image_tga->getDataSize() > 0 )
+ {
+ mStaticImageListTGA[ namekey ] = image_tga;
+ mTGABytes += image_tga->getDataSize();
+ return image_tga;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+}
+
+// Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
+// Caches the result to speed identical subsequent requests.
+LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, bool is_mask)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ LLPointer<LLGLTexture> tex;
+ const char *namekey = mImageNames.addString(file_name);
+
+ texture_map_t::const_iterator iter = mStaticImageList.find(namekey);
+ if( iter != mStaticImageList.end() )
+ {
+ tex = iter->second;
+ }
+ else
+ {
+ llassert(gTextureManagerBridgep);
+ tex = gTextureManagerBridgep->getLocalTexture( false );
+ LLPointer<LLImageRaw> image_raw = new LLImageRaw;
+ if( loadImageRaw( file_name, image_raw ) )
+ {
+ if( (image_raw->getComponents() == 1) && is_mask )
+ {
+ // Convert grayscale alpha masks from single channel into RGBA.
+ // Fill RGB with black to allow fixed function gl calls
+ // to match shader implementation.
+ LLPointer<LLImageRaw> alpha_image_raw = image_raw;
+ image_raw = new LLImageRaw(image_raw->getWidth(),
+ image_raw->getHeight(),
+ 4);
+
+ image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black);
+ }
+ tex->createGLTexture(0, image_raw, 0, true, LLGLTexture::LOCAL);
+
+ gGL.getTexUnit(0)->bind(tex);
+ tex->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+ mStaticImageList [ namekey ] = tex;
+ mGLBytes += (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
+ }
+ else
+ {
+ tex = NULL;
+ }
+ }
+
+ return tex;
+}
+
+// Reads a .tga file, decodes it, and puts the decoded data in image_raw.
+// Returns true if successful.
+bool LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ bool success = false;
+ std::string path;
+ path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
+ LLPointer<LLImageTGA> image_tga = new LLImageTGA( path );
+ if( image_tga->getDataSize() > 0 )
+ {
+ // Copy data from tga to raw.
+ success = image_tga->decode( image_raw );
+ }
+
+ return success;
+}
+
diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h
index bc55db01fc..ea43135310 100644
--- a/indra/llappearance/lltexlayer.h
+++ b/indra/llappearance/lltexlayer.h
@@ -1,313 +1,313 @@
-/**
- * @file lltexlayer.h
- * @brief Texture layer classes. Used for avatars.
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#ifndef LL_LLTEXLAYER_H
-#define LL_LLTEXLAYER_H
-
-#include <deque>
-#include "llglslshader.h"
-#include "llgltexture.h"
-#include "llavatarappearancedefines.h"
-#include "lltexlayerparams.h"
-
-class LLAvatarAppearance;
-class LLImageTGA;
-class LLImageRaw;
-class LLLocalTextureObject;
-class LLXmlTreeNode;
-class LLTexLayerSet;
-class LLTexLayerSetInfo;
-class LLTexLayerInfo;
-class LLTexLayerSetBuffer;
-class LLWearable;
-class LLViewerVisualParam;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerInterface
-//
-// Interface class to generalize functionality shared by LLTexLayer
-// and LLTexLayerTemplate.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerInterface
-{
-public:
- enum ERenderPass
- {
- RP_COLOR,
- RP_BUMP,
- RP_SHINE
- };
-
- LLTexLayerInterface(LLTexLayerSet* const layer_set);
- LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable);
- virtual ~LLTexLayerInterface() {}
-
- virtual bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
- virtual void deleteCaches() = 0;
- virtual bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0;
- virtual bool isInvisibleAlphaMask() const = 0;
-
- const LLTexLayerInfo* getInfo() const { return mInfo; }
- virtual bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions
- LLWearableType::EType getWearableType() const;
- LLAvatarAppearanceDefines::ETextureIndex getLocalTextureIndex() const;
-
- const std::string& getName() const;
- const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
- LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; }
-
- void invalidateMorphMasks();
- virtual void setHasMorph(bool newval) { mHasMorph = newval; }
- bool hasMorph() const { return mHasMorph; }
- bool isMorphValid() const { return mMorphMasksValid; }
-
- void requestUpdate();
- virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
- bool hasAlphaParams() const { return !mParamAlphaList.empty(); }
-
- ERenderPass getRenderPass() const;
- bool isVisibilityMask() const;
-
- virtual void asLLSD(LLSD& sd) const {}
-
-protected:
- const std::string& getGlobalColor() const;
- LLViewerVisualParam* getVisualParamPtr(S32 index) const;
-
-protected:
- LLTexLayerSet* const mTexLayerSet;
- const LLTexLayerInfo* mInfo;
- bool mMorphMasksValid;
- bool mHasMorph;
-
- // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order.
- param_color_list_t mParamColorList;
- param_alpha_list_t mParamAlphaList;
- // mGlobalColor name stored in mInfo
- // mFixedColor value stored in mInfo
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerTemplate
-//
-// Only exists for llvoavatarself.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerTemplate : public LLTexLayerInterface
-{
-public:
- LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance);
- LLTexLayerTemplate(const LLTexLayerTemplate &layer);
- /*virtual*/ ~LLTexLayerTemplate();
- /*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
- /*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
- /*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
- /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
- /*virtual*/ void setHasMorph(bool newval);
- /*virtual*/ void deleteCaches();
- /*virtual*/ bool isInvisibleAlphaMask() const;
-protected:
- U32 updateWearableCache() const;
- LLTexLayer* getLayer(U32 i) const;
- LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
-private:
- LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
- typedef std::vector<LLWearable*> wearable_cache_t;
- mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayer
-//
-// A single texture layer. Only exists for llvoavatarself.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayer : public LLTexLayerInterface
-{
-public:
- LLTexLayer(LLTexLayerSet* const layer_set);
- LLTexLayer(const LLTexLayer &layer, LLWearable *wearable);
- LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable);
- /*virtual*/ ~LLTexLayer();
-
- /*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
- /*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
-
- /*virtual*/ void deleteCaches();
- const U8* getAlphaData() const;
-
- bool findNetColor(LLColor4* color) const;
- /*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
- /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
- void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render);
- void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
- /*virtual*/ bool isInvisibleAlphaMask() const;
-
- void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
- LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
-
- /*virtual*/ void asLLSD(LLSD& sd) const;
-
- static void calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color);
-protected:
- LLUUID getUUID() const;
- typedef std::map<U32, U8*> alpha_cache_t;
- alpha_cache_t mAlphaCache;
- LLLocalTextureObject* mLocalTextureObject;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerSet
-//
-// An ordered set of texture layers that gets composited into a single texture.
-// Only exists for llvoavatarself.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerSet
-{
- friend class LLTexLayerSetBuffer;
-public:
- LLTexLayerSet(LLAvatarAppearance* const appearance);
- virtual ~LLTexLayerSet();
-
- LLTexLayerSetBuffer* getComposite();
- const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
- virtual void createComposite() = 0;
- void destroyComposite();
- void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target);
-
- const LLTexLayerSetInfo* getInfo() const { return mInfo; }
- bool setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
-
- bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr);
- void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false);
-
- bool isBodyRegion(const std::string& region) const;
- void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components);
- bool isMorphValid() const;
- virtual void requestUpdate() = 0;
- void invalidateMorphMasks();
- void deleteCaches();
- LLTexLayerInterface* findLayerByName(const std::string& name);
- void cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable* wearable);
-
- LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
- const std::string getBodyRegionName() const;
- bool hasComposite() const { return (mComposite.notNull()); }
- LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() const { return mBakedTexIndex; }
- void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
- bool isVisible() const { return mIsVisible; }
-
- static bool sHasCaches;
-
-protected:
- typedef std::vector<LLTexLayerInterface *> layer_list_t;
- layer_list_t mLayerList;
- layer_list_t mMaskLayerList;
- LLPointer<LLTexLayerSetBuffer> mComposite;
- LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
- bool mIsVisible;
-
- LLAvatarAppearanceDefines::EBakedTextureIndex mBakedTexIndex;
- const LLTexLayerSetInfo* mInfo;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerSetInfo
-//
-// Contains shared layer set data.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerSetInfo
-{
- friend class LLTexLayerSet;
-public:
- LLTexLayerSetInfo();
- ~LLTexLayerSetInfo();
- bool parseXml(LLXmlTreeNode* node);
- void createVisualParams(LLAvatarAppearance *appearance);
- S32 getWidth() const { return mWidth; }
- S32 getHeight() const { return mHeight; }
-protected:
- std::string mBodyRegion;
- S32 mWidth;
- S32 mHeight;
- std::string mStaticAlphaFileName;
- bool mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName)
- typedef std::vector<LLTexLayerInfo*> layer_info_list_t;
- layer_info_list_t mLayerInfoList;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerSetBuffer
-//
-// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerSetBuffer : public virtual LLRefCount
-{
- LOG_CLASS(LLTexLayerSetBuffer);
-
-public:
- LLTexLayerSetBuffer(LLTexLayerSet* const owner);
- virtual ~LLTexLayerSetBuffer();
-
-protected:
- void pushProjection() const;
- void popProjection() const;
- virtual void preRenderTexLayerSet();
- virtual void midRenderTexLayerSet(bool success) {}
- virtual void postRenderTexLayerSet(bool success);
- virtual S32 getCompositeOriginX() const = 0;
- virtual S32 getCompositeOriginY() const = 0;
- virtual S32 getCompositeWidth() const = 0;
- virtual S32 getCompositeHeight() const = 0;
- bool renderTexLayerSet(LLRenderTarget* bound_target);
-
- LLTexLayerSet* const mTexLayerSet;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerStaticImageList
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerStaticImageList : public LLSingleton<LLTexLayerStaticImageList>
-{
- LLSINGLETON(LLTexLayerStaticImageList);
- ~LLTexLayerStaticImageList();
-public:
- LLGLTexture* getTexture(const std::string& file_name, bool is_mask);
- LLImageTGA* getImageTGA(const std::string& file_name);
- void deleteCachedImages();
- void dumpByteCount() const;
-protected:
- bool loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
-private:
- LLStringTable mImageNames;
- typedef std::map<const char*, LLPointer<LLGLTexture> > texture_map_t;
- texture_map_t mStaticImageList;
- typedef std::map<const char*, LLPointer<LLImageTGA> > image_tga_map_t;
- image_tga_map_t mStaticImageListTGA;
- S32 mGLBytes;
- S32 mTGABytes;
-};
-
-#endif // LL_LLTEXLAYER_H
+/**
+ * @file lltexlayer.h
+ * @brief Texture layer classes. Used for avatars.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLTEXLAYER_H
+#define LL_LLTEXLAYER_H
+
+#include <deque>
+#include "llglslshader.h"
+#include "llgltexture.h"
+#include "llavatarappearancedefines.h"
+#include "lltexlayerparams.h"
+
+class LLAvatarAppearance;
+class LLImageTGA;
+class LLImageRaw;
+class LLLocalTextureObject;
+class LLXmlTreeNode;
+class LLTexLayerSet;
+class LLTexLayerSetInfo;
+class LLTexLayerInfo;
+class LLTexLayerSetBuffer;
+class LLWearable;
+class LLViewerVisualParam;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerInterface
+//
+// Interface class to generalize functionality shared by LLTexLayer
+// and LLTexLayerTemplate.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerInterface
+{
+public:
+ enum ERenderPass
+ {
+ RP_COLOR,
+ RP_BUMP,
+ RP_SHINE
+ };
+
+ LLTexLayerInterface(LLTexLayerSet* const layer_set);
+ LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable);
+ virtual ~LLTexLayerInterface() {}
+
+ virtual bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
+ virtual void deleteCaches() = 0;
+ virtual bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0;
+ virtual bool isInvisibleAlphaMask() const = 0;
+
+ const LLTexLayerInfo* getInfo() const { return mInfo; }
+ virtual bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions
+ LLWearableType::EType getWearableType() const;
+ LLAvatarAppearanceDefines::ETextureIndex getLocalTextureIndex() const;
+
+ const std::string& getName() const;
+ const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
+ LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; }
+
+ void invalidateMorphMasks();
+ virtual void setHasMorph(bool newval) { mHasMorph = newval; }
+ bool hasMorph() const { return mHasMorph; }
+ bool isMorphValid() const { return mMorphMasksValid; }
+
+ void requestUpdate();
+ virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
+ bool hasAlphaParams() const { return !mParamAlphaList.empty(); }
+
+ ERenderPass getRenderPass() const;
+ bool isVisibilityMask() const;
+
+ virtual void asLLSD(LLSD& sd) const {}
+
+protected:
+ const std::string& getGlobalColor() const;
+ LLViewerVisualParam* getVisualParamPtr(S32 index) const;
+
+protected:
+ LLTexLayerSet* const mTexLayerSet;
+ const LLTexLayerInfo* mInfo;
+ bool mMorphMasksValid;
+ bool mHasMorph;
+
+ // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order.
+ param_color_list_t mParamColorList;
+ param_alpha_list_t mParamAlphaList;
+ // mGlobalColor name stored in mInfo
+ // mFixedColor value stored in mInfo
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerTemplate
+//
+// Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerTemplate : public LLTexLayerInterface
+{
+public:
+ LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance);
+ LLTexLayerTemplate(const LLTexLayerTemplate &layer);
+ /*virtual*/ ~LLTexLayerTemplate();
+ /*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
+ /*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
+ /*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
+ /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
+ /*virtual*/ void setHasMorph(bool newval);
+ /*virtual*/ void deleteCaches();
+ /*virtual*/ bool isInvisibleAlphaMask() const;
+protected:
+ U32 updateWearableCache() const;
+ LLTexLayer* getLayer(U32 i) const;
+ LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+private:
+ LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
+ typedef std::vector<LLWearable*> wearable_cache_t;
+ mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayer
+//
+// A single texture layer. Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayer : public LLTexLayerInterface
+{
+public:
+ LLTexLayer(LLTexLayerSet* const layer_set);
+ LLTexLayer(const LLTexLayer &layer, LLWearable *wearable);
+ LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable);
+ /*virtual*/ ~LLTexLayer();
+
+ /*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
+ /*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
+
+ /*virtual*/ void deleteCaches();
+ const U8* getAlphaData() const;
+
+ bool findNetColor(LLColor4* color) const;
+ /*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
+ /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
+ void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render);
+ void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
+ /*virtual*/ bool isInvisibleAlphaMask() const;
+
+ void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
+ LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
+
+ /*virtual*/ void asLLSD(LLSD& sd) const;
+
+ static void calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color);
+protected:
+ LLUUID getUUID() const;
+ typedef std::map<U32, U8*> alpha_cache_t;
+ alpha_cache_t mAlphaCache;
+ LLLocalTextureObject* mLocalTextureObject;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerSet
+//
+// An ordered set of texture layers that gets composited into a single texture.
+// Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerSet
+{
+ friend class LLTexLayerSetBuffer;
+public:
+ LLTexLayerSet(LLAvatarAppearance* const appearance);
+ virtual ~LLTexLayerSet();
+
+ LLTexLayerSetBuffer* getComposite();
+ const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
+ virtual void createComposite() = 0;
+ void destroyComposite();
+ void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target);
+
+ const LLTexLayerSetInfo* getInfo() const { return mInfo; }
+ bool setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
+
+ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr);
+ void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false);
+
+ bool isBodyRegion(const std::string& region) const;
+ void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components);
+ bool isMorphValid() const;
+ virtual void requestUpdate() = 0;
+ void invalidateMorphMasks();
+ void deleteCaches();
+ LLTexLayerInterface* findLayerByName(const std::string& name);
+ void cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable* wearable);
+
+ LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
+ const std::string getBodyRegionName() const;
+ bool hasComposite() const { return (mComposite.notNull()); }
+ LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() const { return mBakedTexIndex; }
+ void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
+ bool isVisible() const { return mIsVisible; }
+
+ static bool sHasCaches;
+
+protected:
+ typedef std::vector<LLTexLayerInterface *> layer_list_t;
+ layer_list_t mLayerList;
+ layer_list_t mMaskLayerList;
+ LLPointer<LLTexLayerSetBuffer> mComposite;
+ LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
+ bool mIsVisible;
+
+ LLAvatarAppearanceDefines::EBakedTextureIndex mBakedTexIndex;
+ const LLTexLayerSetInfo* mInfo;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerSetInfo
+//
+// Contains shared layer set data.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerSetInfo
+{
+ friend class LLTexLayerSet;
+public:
+ LLTexLayerSetInfo();
+ ~LLTexLayerSetInfo();
+ bool parseXml(LLXmlTreeNode* node);
+ void createVisualParams(LLAvatarAppearance *appearance);
+ S32 getWidth() const { return mWidth; }
+ S32 getHeight() const { return mHeight; }
+protected:
+ std::string mBodyRegion;
+ S32 mWidth;
+ S32 mHeight;
+ std::string mStaticAlphaFileName;
+ bool mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName)
+ typedef std::vector<LLTexLayerInfo*> layer_info_list_t;
+ layer_info_list_t mLayerInfoList;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerSetBuffer
+//
+// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerSetBuffer : public virtual LLRefCount
+{
+ LOG_CLASS(LLTexLayerSetBuffer);
+
+public:
+ LLTexLayerSetBuffer(LLTexLayerSet* const owner);
+ virtual ~LLTexLayerSetBuffer();
+
+protected:
+ void pushProjection() const;
+ void popProjection() const;
+ virtual void preRenderTexLayerSet();
+ virtual void midRenderTexLayerSet(bool success) {}
+ virtual void postRenderTexLayerSet(bool success);
+ virtual S32 getCompositeOriginX() const = 0;
+ virtual S32 getCompositeOriginY() const = 0;
+ virtual S32 getCompositeWidth() const = 0;
+ virtual S32 getCompositeHeight() const = 0;
+ bool renderTexLayerSet(LLRenderTarget* bound_target);
+
+ LLTexLayerSet* const mTexLayerSet;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerStaticImageList
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerStaticImageList : public LLSingleton<LLTexLayerStaticImageList>
+{
+ LLSINGLETON(LLTexLayerStaticImageList);
+ ~LLTexLayerStaticImageList();
+public:
+ LLGLTexture* getTexture(const std::string& file_name, bool is_mask);
+ LLImageTGA* getImageTGA(const std::string& file_name);
+ void deleteCachedImages();
+ void dumpByteCount() const;
+protected:
+ bool loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
+private:
+ LLStringTable mImageNames;
+ typedef std::map<const char*, LLPointer<LLGLTexture> > texture_map_t;
+ texture_map_t mStaticImageList;
+ typedef std::map<const char*, LLPointer<LLImageTGA> > image_tga_map_t;
+ image_tga_map_t mStaticImageListTGA;
+ S32 mGLBytes;
+ S32 mTGABytes;
+};
+
+#endif // LL_LLTEXLAYER_H
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index 19eb0c784d..b55df16185 100644
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -1,594 +1,594 @@
-/**
- * @file lltexlayerparams.cpp
- * @brief Texture layer parameters
- *
- * $LicenseInfo:firstyear=2002&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 "lltexlayerparams.h"
-
-#include "llavatarappearance.h"
-#include "llimagetga.h"
-#include "llquantize.h"
-#include "lltexlayer.h"
-#include "lltexturemanagerbridge.h"
-#include "../llui/llui.h"
-#include "llwearable.h"
-#include "llfasttimer.h"
-
-//-----------------------------------------------------------------------------
-// LLTexLayerParam
-//-----------------------------------------------------------------------------
-LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer)
- : LLViewerVisualParam(),
- mTexLayer(layer),
- mAvatarAppearance(NULL)
-{
- if (mTexLayer != NULL)
- {
- mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
- }
- else
- {
- LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL;
- }
-}
-
-LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance)
- : LLViewerVisualParam(),
- mTexLayer(NULL),
- mAvatarAppearance(appearance)
-{
-}
-
-LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther)
- : LLViewerVisualParam(pOther),
- mTexLayer(pOther.mTexLayer),
- mAvatarAppearance(pOther.mAvatarAppearance)
-{
-}
-
-bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance)
-{
- LLViewerVisualParam::setInfo(info);
-
- if (add_to_appearance)
- {
- mAvatarAppearance->addVisualParam( this);
- this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLTexLayerParamAlpha
-//-----------------------------------------------------------------------------
-
-// static
-LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances;
-
-// static
-void LLTexLayerParamAlpha::dumpCacheByteCount()
-{
- S32 gl_bytes = 0;
- getCacheByteCount( &gl_bytes);
- LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
-}
-
-// static
-void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
-{
- *gl_bytes = 0;
-
- for (LLTexLayerParamAlpha* instance : sInstances)
- {
- LLGLTexture* tex = instance->mCachedProcessedTexture;
- if (tex)
- {
- S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
-
- if (tex->hasGLTexture())
- {
- *gl_bytes += bytes;
- }
- }
- }
-}
-
-LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer)
- : LLTexLayerParam(layer),
- mCachedProcessedTexture(NULL),
- mStaticImageTGA(),
- mStaticImageRaw(),
- mNeedsCreateTexture(false),
- mStaticImageInvalid(false),
- mAvgDistortionVec(1.f, 1.f, 1.f),
- mCachedEffectiveWeight(0.f)
-{
- sInstances.push_front(this);
-}
-
-LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance)
- : LLTexLayerParam(appearance),
- mCachedProcessedTexture(NULL),
- mStaticImageTGA(),
- mStaticImageRaw(),
- mNeedsCreateTexture(false),
- mStaticImageInvalid(false),
- mAvgDistortionVec(1.f, 1.f, 1.f),
- mCachedEffectiveWeight(0.f)
-{
- sInstances.push_front(this);
-}
-
-LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
- : LLTexLayerParam(pOther),
- mCachedProcessedTexture(pOther.mCachedProcessedTexture),
- mStaticImageTGA(pOther.mStaticImageTGA),
- mStaticImageRaw(pOther.mStaticImageRaw),
- mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
- mStaticImageInvalid(pOther.mStaticImageInvalid),
- mAvgDistortionVec(pOther.mAvgDistortionVec),
- mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
-{
- sInstances.push_front(this);
-}
-
-LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
-{
- deleteCaches();
- sInstances.remove(this);
-}
-
-/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
-{
- return new LLTexLayerParamAlpha(*this);
-}
-
-void LLTexLayerParamAlpha::deleteCaches()
-{
- mStaticImageTGA = NULL; // deletes image
- mCachedProcessedTexture = NULL;
- mStaticImageRaw = NULL;
- mNeedsCreateTexture = false;
-}
-
-bool LLTexLayerParamAlpha::getMultiplyBlend() const
-{
- return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend;
-}
-
-void LLTexLayerParamAlpha::setWeight(F32 weight)
-{
- if (mIsAnimating || mTexLayer == NULL)
- {
- return;
- }
- F32 min_weight = getMinWeight();
- F32 max_weight = getMaxWeight();
- F32 new_weight = llclamp(weight, min_weight, max_weight);
- U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
- U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
- if (cur_u8 != new_u8)
- {
- mCurWeight = new_weight;
-
- if ((mAvatarAppearance->getSex() & getSex()) &&
- (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
- {
- mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
- mTexLayer->invalidateMorphMasks();
- }
- }
-}
-
-void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
-{
- // do not animate dummy parameters
- if (mIsDummy)
- {
- setWeight(target_value);
- return;
- }
-
- mTargetWeight = target_value;
- setWeight(target_value);
- mIsAnimating = true;
- if (mNext)
- {
- mNext->setAnimationTarget(target_value);
- }
-}
-
-void LLTexLayerParamAlpha::animate(F32 delta)
-{
- if (mNext)
- {
- mNext->animate(delta);
- }
-}
-
-bool LLTexLayerParamAlpha::getSkip() const
-{
- if (!mTexLayer)
- {
- return true;
- }
-
- const LLAvatarAppearance *appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
-
- if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight)
- {
- F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
- if (is_approx_zero(effective_weight))
- {
- return true;
- }
- }
-
- LLWearableType::EType type = (LLWearableType::EType)getWearableType();
- if ((type != LLWearableType::WT_INVALID) && !appearance->isWearingWearableType(type))
- {
- return true;
- }
-
- return false;
-}
-
-
-bool LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
-{
- LL_PROFILE_ZONE_SCOPED;
- bool success = true;
-
- if (!mTexLayer)
- {
- return success;
- }
-
- F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
- bool weight_changed = effective_weight != mCachedEffectiveWeight;
- if (getSkip())
- {
- return success;
- }
-
- LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo();
- gGL.flush();
- if (info->mMultiplyBlend)
- {
- gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function
- }
- else
- {
- gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function
- }
-
- if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid)
- {
- if (mStaticImageTGA.isNull())
- {
- // Don't load the image file until we actually need it the first time. Like now.
- mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName);
- // We now have something in one of our caches
- LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull();
-
- if (mStaticImageTGA.isNull())
- {
- LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL;
- mStaticImageInvalid = true; // don't try again.
- return false;
- }
- }
-
- const S32 image_tga_width = mStaticImageTGA->getWidth();
- const S32 image_tga_height = mStaticImageTGA->getHeight();
- if (!mCachedProcessedTexture ||
- (mCachedProcessedTexture->getWidth() != image_tga_width) ||
- (mCachedProcessedTexture->getHeight() != image_tga_height) ||
- (weight_changed))
- {
- mCachedEffectiveWeight = effective_weight;
-
- if (!mCachedProcessedTexture)
- {
- llassert(gTextureManagerBridgep);
- mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width, image_tga_height, 1, false);
-
- // We now have something in one of our caches
- LLTexLayerSet::sHasCaches |= mCachedProcessedTexture.notNull();
-
- mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
- }
-
- // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed.
- mStaticImageRaw = NULL;
- mStaticImageRaw = new LLImageRaw;
- mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight);
- mNeedsCreateTexture = true;
- LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL;
- }
-
- if (mCachedProcessedTexture)
- {
- {
- // Create the GL texture, and then hang onto it for future use.
- if (mNeedsCreateTexture)
- {
- mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw);
- mNeedsCreateTexture = false;
- gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
- mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
- }
-
- gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
- gl_rect_2d_simple_tex(width, height);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- stop_glerror();
- }
- }
-
- // Don't keep the cache for other people's avatars
- // (It's not really a "cache" in that case, but the logic is the same)
- if (!mAvatarAppearance->isSelf())
- {
- mCachedProcessedTexture = NULL;
- }
- }
- else
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4f(0.f, 0.f, 0.f, effective_weight);
- gl_rect_2d_simple(width, height);
- }
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// LLTexLayerParamAlphaInfo
-//-----------------------------------------------------------------------------
-LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo() :
- mMultiplyBlend(false),
- mSkipIfZeroWeight(false),
- mDomain(0.f)
-{
-}
-
-bool LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node)
-{
- llassert(node->hasName("param") && node->getChildByName("param_alpha"));
-
- if (!LLViewerVisualParamInfo::parseXml(node))
- return false;
-
- LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha");
- if (!param_alpha_node)
- {
- return false;
- }
-
- static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
- if (param_alpha_node->getFastAttributeString(tga_file_string, mStaticImageFileName))
- {
- // Don't load the image file until it's actually needed.
- }
-// else
-// {
-// LL_WARNS() << "<param_alpha> element is missing tga_file attribute." << LL_ENDL;
-// }
-
- static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend");
- param_alpha_node->getFastAttributeBOOL(multiply_blend_string, mMultiplyBlend);
-
- static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero");
- param_alpha_node->getFastAttributeBOOL(skip_if_zero_string, mSkipIfZeroWeight);
-
- static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain");
- param_alpha_node->getFastAttributeF32(domain_string, mDomain);
-
- return true;
-}
-
-
-
-
-LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer)
- : LLTexLayerParam(layer),
- mAvgDistortionVec(1.f, 1.f, 1.f)
-{
-}
-
-LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance)
- : LLTexLayerParam(appearance),
- mAvgDistortionVec(1.f, 1.f, 1.f)
-{
-}
-
-LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther)
- : LLTexLayerParam(pOther),
- mAvgDistortionVec(pOther.mAvgDistortionVec)
-{
-}
-
-LLTexLayerParamColor::~LLTexLayerParamColor()
-{
-}
-
-/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
-{
- return new LLTexLayerParamColor(*this);
-}
-
-LLColor4 LLTexLayerParamColor::getNetColor() const
-{
- const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
-
- llassert(info->mNumColors >= 1);
-
- F32 effective_weight = (mAvatarAppearance && (mAvatarAppearance->getSex() & getSex())) ? mCurWeight : getDefaultWeight();
-
- S32 index_last = info->mNumColors - 1;
- F32 scaled_weight = effective_weight * index_last;
- S32 index_start = (S32) scaled_weight;
- S32 index_end = index_start + 1;
- if (index_start == index_last)
- {
- return info->mColors[index_last];
- }
- else
- {
- F32 weight = scaled_weight - index_start;
- const LLColor4 *start = &info->mColors[ index_start ];
- const LLColor4 *end = &info->mColors[ index_end ];
- return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX],
- (1.f - weight) * start->mV[VY] + weight * end->mV[VY],
- (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ],
- (1.f - weight) * start->mV[VW] + weight * end->mV[VW]);
- }
-}
-
-
-void LLTexLayerParamColor::setWeight(F32 weight)
-{
- if (mIsAnimating)
- {
- return;
- }
-
- F32 min_weight = getMinWeight();
- F32 max_weight = getMaxWeight();
- F32 new_weight = llclamp(weight, min_weight, max_weight);
- U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
- U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
- if (cur_u8 != new_u8)
- {
- mCurWeight = new_weight;
-
- const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
-
- if (info->mNumColors <= 0)
- {
- // This will happen when we set the default weight the first time.
- return;
- }
-
- if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
- {
- onGlobalColorChanged();
- if (mTexLayer)
- {
- mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
- }
- }
-
-// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL;
- }
-}
-
-void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
-{
- // set value first then set interpolating flag to ignore further updates
- mTargetWeight = target_value;
- setWeight(target_value);
- mIsAnimating = true;
- if (mNext)
- {
- mNext->setAnimationTarget(target_value);
- }
-}
-
-void LLTexLayerParamColor::animate(F32 delta)
-{
- if (mNext)
- {
- mNext->animate(delta);
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLTexLayerParamColorInfo
-//-----------------------------------------------------------------------------
-LLTexLayerParamColorInfo::LLTexLayerParamColorInfo() :
- mOperation(LLTexLayerParamColor::OP_ADD),
- mNumColors(0)
-{
-}
-
-bool LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node)
-{
- llassert(node->hasName("param") && node->getChildByName("param_color"));
-
- if (!LLViewerVisualParamInfo::parseXml(node))
- return false;
-
- LLXmlTreeNode* param_color_node = node->getChildByName("param_color");
- if (!param_color_node)
- {
- return false;
- }
-
- std::string op_string;
- static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation");
- if (param_color_node->getFastAttributeString(operation_string, op_string))
- {
- LLStringUtil::toLower(op_string);
- if (op_string == "add") mOperation = LLTexLayerParamColor::OP_ADD;
- else if (op_string == "multiply") mOperation = LLTexLayerParamColor::OP_MULTIPLY;
- else if (op_string == "blend") mOperation = LLTexLayerParamColor::OP_BLEND;
- }
-
- mNumColors = 0;
-
- LLColor4U color4u;
- for (LLXmlTreeNode* child = param_color_node->getChildByName("value");
- child;
- child = param_color_node->getNextNamedChild())
- {
- if ((mNumColors < MAX_COLOR_VALUES))
- {
- static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color");
- if (child->getFastAttributeColor4U(color_string, color4u))
- {
- mColors[ mNumColors ].setVec(color4u);
- mNumColors++;
- }
- }
- }
- if (!mNumColors)
- {
- LL_WARNS() << "<param_color> is missing <value> sub-elements" << LL_ENDL;
- return false;
- }
-
- if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1))
- {
- LL_WARNS() << "<param_color> with operation\"blend\" must have exactly one <value>" << LL_ENDL;
- return false;
- }
-
- return true;
-}
+/**
+ * @file lltexlayerparams.cpp
+ * @brief Texture layer parameters
+ *
+ * $LicenseInfo:firstyear=2002&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 "lltexlayerparams.h"
+
+#include "llavatarappearance.h"
+#include "llimagetga.h"
+#include "llquantize.h"
+#include "lltexlayer.h"
+#include "lltexturemanagerbridge.h"
+#include "../llui/llui.h"
+#include "llwearable.h"
+#include "llfasttimer.h"
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParam
+//-----------------------------------------------------------------------------
+LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer)
+ : LLViewerVisualParam(),
+ mTexLayer(layer),
+ mAvatarAppearance(NULL)
+{
+ if (mTexLayer != NULL)
+ {
+ mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
+ }
+ else
+ {
+ LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL;
+ }
+}
+
+LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance)
+ : LLViewerVisualParam(),
+ mTexLayer(NULL),
+ mAvatarAppearance(appearance)
+{
+}
+
+LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther)
+ : LLViewerVisualParam(pOther),
+ mTexLayer(pOther.mTexLayer),
+ mAvatarAppearance(pOther.mAvatarAppearance)
+{
+}
+
+bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance)
+{
+ LLViewerVisualParam::setInfo(info);
+
+ if (add_to_appearance)
+ {
+ mAvatarAppearance->addVisualParam( this);
+ this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParamAlpha
+//-----------------------------------------------------------------------------
+
+// static
+LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances;
+
+// static
+void LLTexLayerParamAlpha::dumpCacheByteCount()
+{
+ S32 gl_bytes = 0;
+ getCacheByteCount( &gl_bytes);
+ LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
+}
+
+// static
+void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
+{
+ *gl_bytes = 0;
+
+ for (LLTexLayerParamAlpha* instance : sInstances)
+ {
+ LLGLTexture* tex = instance->mCachedProcessedTexture;
+ if (tex)
+ {
+ S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
+
+ if (tex->hasGLTexture())
+ {
+ *gl_bytes += bytes;
+ }
+ }
+ }
+}
+
+LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer)
+ : LLTexLayerParam(layer),
+ mCachedProcessedTexture(NULL),
+ mStaticImageTGA(),
+ mStaticImageRaw(),
+ mNeedsCreateTexture(false),
+ mStaticImageInvalid(false),
+ mAvgDistortionVec(1.f, 1.f, 1.f),
+ mCachedEffectiveWeight(0.f)
+{
+ sInstances.push_front(this);
+}
+
+LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance)
+ : LLTexLayerParam(appearance),
+ mCachedProcessedTexture(NULL),
+ mStaticImageTGA(),
+ mStaticImageRaw(),
+ mNeedsCreateTexture(false),
+ mStaticImageInvalid(false),
+ mAvgDistortionVec(1.f, 1.f, 1.f),
+ mCachedEffectiveWeight(0.f)
+{
+ sInstances.push_front(this);
+}
+
+LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
+ : LLTexLayerParam(pOther),
+ mCachedProcessedTexture(pOther.mCachedProcessedTexture),
+ mStaticImageTGA(pOther.mStaticImageTGA),
+ mStaticImageRaw(pOther.mStaticImageRaw),
+ mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
+ mStaticImageInvalid(pOther.mStaticImageInvalid),
+ mAvgDistortionVec(pOther.mAvgDistortionVec),
+ mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
+{
+ sInstances.push_front(this);
+}
+
+LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
+{
+ deleteCaches();
+ sInstances.remove(this);
+}
+
+/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
+{
+ return new LLTexLayerParamAlpha(*this);
+}
+
+void LLTexLayerParamAlpha::deleteCaches()
+{
+ mStaticImageTGA = NULL; // deletes image
+ mCachedProcessedTexture = NULL;
+ mStaticImageRaw = NULL;
+ mNeedsCreateTexture = false;
+}
+
+bool LLTexLayerParamAlpha::getMultiplyBlend() const
+{
+ return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend;
+}
+
+void LLTexLayerParamAlpha::setWeight(F32 weight)
+{
+ if (mIsAnimating || mTexLayer == NULL)
+ {
+ return;
+ }
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ F32 new_weight = llclamp(weight, min_weight, max_weight);
+ U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
+ U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
+ if (cur_u8 != new_u8)
+ {
+ mCurWeight = new_weight;
+
+ if ((mAvatarAppearance->getSex() & getSex()) &&
+ (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
+ {
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+ mTexLayer->invalidateMorphMasks();
+ }
+ }
+}
+
+void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
+{
+ // do not animate dummy parameters
+ if (mIsDummy)
+ {
+ setWeight(target_value);
+ return;
+ }
+
+ mTargetWeight = target_value;
+ setWeight(target_value);
+ mIsAnimating = true;
+ if (mNext)
+ {
+ mNext->setAnimationTarget(target_value);
+ }
+}
+
+void LLTexLayerParamAlpha::animate(F32 delta)
+{
+ if (mNext)
+ {
+ mNext->animate(delta);
+ }
+}
+
+bool LLTexLayerParamAlpha::getSkip() const
+{
+ if (!mTexLayer)
+ {
+ return true;
+ }
+
+ const LLAvatarAppearance *appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
+
+ if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight)
+ {
+ F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
+ if (is_approx_zero(effective_weight))
+ {
+ return true;
+ }
+ }
+
+ LLWearableType::EType type = (LLWearableType::EType)getWearableType();
+ if ((type != LLWearableType::WT_INVALID) && !appearance->isWearingWearableType(type))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ bool success = true;
+
+ if (!mTexLayer)
+ {
+ return success;
+ }
+
+ F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
+ bool weight_changed = effective_weight != mCachedEffectiveWeight;
+ if (getSkip())
+ {
+ return success;
+ }
+
+ LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo();
+ gGL.flush();
+ if (info->mMultiplyBlend)
+ {
+ gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function
+ }
+ else
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function
+ }
+
+ if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid)
+ {
+ if (mStaticImageTGA.isNull())
+ {
+ // Don't load the image file until we actually need it the first time. Like now.
+ mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName);
+ // We now have something in one of our caches
+ LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull();
+
+ if (mStaticImageTGA.isNull())
+ {
+ LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL;
+ mStaticImageInvalid = true; // don't try again.
+ return false;
+ }
+ }
+
+ const S32 image_tga_width = mStaticImageTGA->getWidth();
+ const S32 image_tga_height = mStaticImageTGA->getHeight();
+ if (!mCachedProcessedTexture ||
+ (mCachedProcessedTexture->getWidth() != image_tga_width) ||
+ (mCachedProcessedTexture->getHeight() != image_tga_height) ||
+ (weight_changed))
+ {
+ mCachedEffectiveWeight = effective_weight;
+
+ if (!mCachedProcessedTexture)
+ {
+ llassert(gTextureManagerBridgep);
+ mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width, image_tga_height, 1, false);
+
+ // We now have something in one of our caches
+ LLTexLayerSet::sHasCaches |= mCachedProcessedTexture.notNull();
+
+ mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
+ }
+
+ // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed.
+ mStaticImageRaw = NULL;
+ mStaticImageRaw = new LLImageRaw;
+ mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight);
+ mNeedsCreateTexture = true;
+ LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL;
+ }
+
+ if (mCachedProcessedTexture)
+ {
+ {
+ // Create the GL texture, and then hang onto it for future use.
+ if (mNeedsCreateTexture)
+ {
+ mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw);
+ mNeedsCreateTexture = false;
+ gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
+ mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
+ }
+
+ gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
+ gl_rect_2d_simple_tex(width, height);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ stop_glerror();
+ }
+ }
+
+ // Don't keep the cache for other people's avatars
+ // (It's not really a "cache" in that case, but the logic is the same)
+ if (!mAvatarAppearance->isSelf())
+ {
+ mCachedProcessedTexture = NULL;
+ }
+ }
+ else
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.color4f(0.f, 0.f, 0.f, effective_weight);
+ gl_rect_2d_simple(width, height);
+ }
+
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParamAlphaInfo
+//-----------------------------------------------------------------------------
+LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo() :
+ mMultiplyBlend(false),
+ mSkipIfZeroWeight(false),
+ mDomain(0.f)
+{
+}
+
+bool LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node)
+{
+ llassert(node->hasName("param") && node->getChildByName("param_alpha"));
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return false;
+
+ LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha");
+ if (!param_alpha_node)
+ {
+ return false;
+ }
+
+ static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
+ if (param_alpha_node->getFastAttributeString(tga_file_string, mStaticImageFileName))
+ {
+ // Don't load the image file until it's actually needed.
+ }
+// else
+// {
+// LL_WARNS() << "<param_alpha> element is missing tga_file attribute." << LL_ENDL;
+// }
+
+ static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend");
+ param_alpha_node->getFastAttributeBOOL(multiply_blend_string, mMultiplyBlend);
+
+ static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero");
+ param_alpha_node->getFastAttributeBOOL(skip_if_zero_string, mSkipIfZeroWeight);
+
+ static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain");
+ param_alpha_node->getFastAttributeF32(domain_string, mDomain);
+
+ return true;
+}
+
+
+
+
+LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer)
+ : LLTexLayerParam(layer),
+ mAvgDistortionVec(1.f, 1.f, 1.f)
+{
+}
+
+LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance)
+ : LLTexLayerParam(appearance),
+ mAvgDistortionVec(1.f, 1.f, 1.f)
+{
+}
+
+LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther)
+ : LLTexLayerParam(pOther),
+ mAvgDistortionVec(pOther.mAvgDistortionVec)
+{
+}
+
+LLTexLayerParamColor::~LLTexLayerParamColor()
+{
+}
+
+/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
+{
+ return new LLTexLayerParamColor(*this);
+}
+
+LLColor4 LLTexLayerParamColor::getNetColor() const
+{
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
+
+ llassert(info->mNumColors >= 1);
+
+ F32 effective_weight = (mAvatarAppearance && (mAvatarAppearance->getSex() & getSex())) ? mCurWeight : getDefaultWeight();
+
+ S32 index_last = info->mNumColors - 1;
+ F32 scaled_weight = effective_weight * index_last;
+ S32 index_start = (S32) scaled_weight;
+ S32 index_end = index_start + 1;
+ if (index_start == index_last)
+ {
+ return info->mColors[index_last];
+ }
+ else
+ {
+ F32 weight = scaled_weight - index_start;
+ const LLColor4 *start = &info->mColors[ index_start ];
+ const LLColor4 *end = &info->mColors[ index_end ];
+ return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX],
+ (1.f - weight) * start->mV[VY] + weight * end->mV[VY],
+ (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ],
+ (1.f - weight) * start->mV[VW] + weight * end->mV[VW]);
+ }
+}
+
+
+void LLTexLayerParamColor::setWeight(F32 weight)
+{
+ if (mIsAnimating)
+ {
+ return;
+ }
+
+ F32 min_weight = getMinWeight();
+ F32 max_weight = getMaxWeight();
+ F32 new_weight = llclamp(weight, min_weight, max_weight);
+ U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
+ U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
+ if (cur_u8 != new_u8)
+ {
+ mCurWeight = new_weight;
+
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
+
+ if (info->mNumColors <= 0)
+ {
+ // This will happen when we set the default weight the first time.
+ return;
+ }
+
+ if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
+ {
+ onGlobalColorChanged();
+ if (mTexLayer)
+ {
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+ }
+ }
+
+// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL;
+ }
+}
+
+void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
+{
+ // set value first then set interpolating flag to ignore further updates
+ mTargetWeight = target_value;
+ setWeight(target_value);
+ mIsAnimating = true;
+ if (mNext)
+ {
+ mNext->setAnimationTarget(target_value);
+ }
+}
+
+void LLTexLayerParamColor::animate(F32 delta)
+{
+ if (mNext)
+ {
+ mNext->animate(delta);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParamColorInfo
+//-----------------------------------------------------------------------------
+LLTexLayerParamColorInfo::LLTexLayerParamColorInfo() :
+ mOperation(LLTexLayerParamColor::OP_ADD),
+ mNumColors(0)
+{
+}
+
+bool LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node)
+{
+ llassert(node->hasName("param") && node->getChildByName("param_color"));
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return false;
+
+ LLXmlTreeNode* param_color_node = node->getChildByName("param_color");
+ if (!param_color_node)
+ {
+ return false;
+ }
+
+ std::string op_string;
+ static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation");
+ if (param_color_node->getFastAttributeString(operation_string, op_string))
+ {
+ LLStringUtil::toLower(op_string);
+ if (op_string == "add") mOperation = LLTexLayerParamColor::OP_ADD;
+ else if (op_string == "multiply") mOperation = LLTexLayerParamColor::OP_MULTIPLY;
+ else if (op_string == "blend") mOperation = LLTexLayerParamColor::OP_BLEND;
+ }
+
+ mNumColors = 0;
+
+ LLColor4U color4u;
+ for (LLXmlTreeNode* child = param_color_node->getChildByName("value");
+ child;
+ child = param_color_node->getNextNamedChild())
+ {
+ if ((mNumColors < MAX_COLOR_VALUES))
+ {
+ static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color");
+ if (child->getFastAttributeColor4U(color_string, color4u))
+ {
+ mColors[ mNumColors ].setVec(color4u);
+ mNumColors++;
+ }
+ }
+ }
+ if (!mNumColors)
+ {
+ LL_WARNS() << "<param_color> is missing <value> sub-elements" << LL_ENDL;
+ return false;
+ }
+
+ if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1))
+ {
+ LL_WARNS() << "<param_color> with operation\"blend\" must have exactly one <value>" << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index 3767a9627f..90c8c92557 100644
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -1,206 +1,206 @@
-/**
- * @file lltexlayerparams.h
- * @brief Texture layer parameters, used by lltexlayer.
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#ifndef LL_LLTEXLAYERPARAMS_H
-#define LL_LLTEXLAYERPARAMS_H
-
-#include "llpointer.h"
-#include "v4color.h"
-#include "llviewervisualparam.h"
-
-class LLAvatarAppearance;
-class LLImageRaw;
-class LLImageTGA;
-class LLTexLayer;
-class LLTexLayerInterface;
-class LLGLTexture;
-class LLWearable;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerParam
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLTexLayerParam : public LLViewerVisualParam
-{
-public:
- LLTexLayerParam(LLTexLayerInterface *layer);
- LLTexLayerParam(LLAvatarAppearance *appearance);
- /*virtual*/ bool setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance);
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
-
-protected:
- LLTexLayerParam(const LLTexLayerParam& pOther);
-
- LLTexLayerInterface* mTexLayer;
- LLAvatarAppearance* mAvatarAppearance;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerParamAlpha
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL_ALIGN_PREFIX(16)
-class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
-{
- LL_ALIGN_NEW
-public:
- LLTexLayerParamAlpha( LLTexLayerInterface* layer );
- LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
- /*virtual*/ ~LLTexLayerParamAlpha();
-
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
-
- // LLVisualParam Virtual functions
- ///*virtual*/ bool parseData(LLXmlTreeNode* node);
- /*virtual*/ void apply( ESex avatar_sex ) {}
- /*virtual*/ void setWeight(F32 weight);
- /*virtual*/ void setAnimationTarget(F32 target_value);
- /*virtual*/ void animate(F32 delta);
-
- // LLViewerVisualParam Virtual functions
- /*virtual*/ F32 getTotalDistortion() { return 1.f; }
- /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
- /*virtual*/ F32 getMaxDistortion() { return 3.f; }
- /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);}
- /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
- /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
-
- // New functions
- bool render( S32 x, S32 y, S32 width, S32 height );
- bool getSkip() const;
- void deleteCaches();
- bool getMultiplyBlend() const;
-
-private:
- LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther);
-
- LLPointer<LLGLTexture> mCachedProcessedTexture;
- LLPointer<LLImageTGA> mStaticImageTGA;
- LLPointer<LLImageRaw> mStaticImageRaw;
- std::atomic<bool> mNeedsCreateTexture;
- bool mStaticImageInvalid;
- LL_ALIGN_16(LLVector4a mAvgDistortionVec);
- F32 mCachedEffectiveWeight;
-
-public:
- // Global list of instances for gathering statistics
- static void dumpCacheByteCount();
- static void getCacheByteCount( S32* gl_bytes );
-
- typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t;
- static param_alpha_ptr_list_t sInstances;
-} LL_ALIGN_POSTFIX(16);
-class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo
-{
- friend class LLTexLayerParamAlpha;
-public:
- LLTexLayerParamAlphaInfo();
- /*virtual*/ ~LLTexLayerParamAlphaInfo() {};
-
- /*virtual*/ bool parseXml(LLXmlTreeNode* node);
-
-private:
- std::string mStaticImageFileName;
- bool mMultiplyBlend;
- bool mSkipIfZeroWeight;
- F32 mDomain;
-};
-//
-// LLTexLayerParamAlpha
-//-----------------------------------------------------------------------------
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLTexLayerParamColor
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
-{
- LL_ALIGN_NEW
-public:
- enum EColorOperation
- {
- OP_ADD = 0,
- OP_MULTIPLY = 1,
- OP_BLEND = 2,
- OP_COUNT = 3 // Number of operations
- };
-
- LLTexLayerParamColor( LLTexLayerInterface* layer );
- LLTexLayerParamColor( LLAvatarAppearance* appearance );
-
- /* virtual */ ~LLTexLayerParamColor();
-
- /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
-
- // LLVisualParam Virtual functions
- ///*virtual*/ bool parseData(LLXmlTreeNode* node);
- /*virtual*/ void apply( ESex avatar_sex ) {}
- /*virtual*/ void setWeight(F32 weight);
- /*virtual*/ void setAnimationTarget(F32 target_value);
- /*virtual*/ void animate(F32 delta);
-
-
- // LLViewerVisualParam Virtual functions
- /*virtual*/ F32 getTotalDistortion() { return 1.f; }
- /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
- /*virtual*/ F32 getMaxDistortion() { return 3.f; }
- /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); }
- /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
- /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
-
- // New functions
- LLColor4 getNetColor() const;
-protected:
- LLTexLayerParamColor(const LLTexLayerParamColor& pOther);
-
- virtual void onGlobalColorChanged() {}
-private:
- LLVector4a mAvgDistortionVec;
-};
-
-class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
-{
- friend class LLTexLayerParamColor;
-
-public:
- LLTexLayerParamColorInfo();
- virtual ~LLTexLayerParamColorInfo() {};
- bool parseXml( LLXmlTreeNode* node );
- LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; }
-private:
- enum { MAX_COLOR_VALUES = 20 };
- LLTexLayerParamColor::EColorOperation mOperation;
- LLColor4 mColors[MAX_COLOR_VALUES];
- S32 mNumColors;
-};
-
-typedef std::vector<LLTexLayerParamColor *> param_color_list_t;
-typedef std::vector<LLTexLayerParamAlpha *> param_alpha_list_t;
-typedef std::vector<LLTexLayerParamColorInfo *> param_color_info_list_t;
-typedef std::vector<LLTexLayerParamAlphaInfo *> param_alpha_info_list_t;
-
-#endif
+/**
+ * @file lltexlayerparams.h
+ * @brief Texture layer parameters, used by lltexlayer.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLTEXLAYERPARAMS_H
+#define LL_LLTEXLAYERPARAMS_H
+
+#include "llpointer.h"
+#include "v4color.h"
+#include "llviewervisualparam.h"
+
+class LLAvatarAppearance;
+class LLImageRaw;
+class LLImageTGA;
+class LLTexLayer;
+class LLTexLayerInterface;
+class LLGLTexture;
+class LLWearable;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerParam
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLTexLayerParam : public LLViewerVisualParam
+{
+public:
+ LLTexLayerParam(LLTexLayerInterface *layer);
+ LLTexLayerParam(LLAvatarAppearance *appearance);
+ /*virtual*/ bool setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance);
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
+
+protected:
+ LLTexLayerParam(const LLTexLayerParam& pOther);
+
+ LLTexLayerInterface* mTexLayer;
+ LLAvatarAppearance* mAvatarAppearance;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerParamAlpha
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL_ALIGN_PREFIX(16)
+class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
+{
+ LL_ALIGN_NEW
+public:
+ LLTexLayerParamAlpha( LLTexLayerInterface* layer );
+ LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
+ /*virtual*/ ~LLTexLayerParamAlpha();
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
+
+ // LLVisualParam Virtual functions
+ ///*virtual*/ bool parseData(LLXmlTreeNode* node);
+ /*virtual*/ void apply( ESex avatar_sex ) {}
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget(F32 target_value);
+ /*virtual*/ void animate(F32 delta);
+
+ // LLViewerVisualParam Virtual functions
+ /*virtual*/ F32 getTotalDistortion() { return 1.f; }
+ /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
+ /*virtual*/ F32 getMaxDistortion() { return 3.f; }
+ /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);}
+ /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
+ /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
+
+ // New functions
+ bool render( S32 x, S32 y, S32 width, S32 height );
+ bool getSkip() const;
+ void deleteCaches();
+ bool getMultiplyBlend() const;
+
+private:
+ LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther);
+
+ LLPointer<LLGLTexture> mCachedProcessedTexture;
+ LLPointer<LLImageTGA> mStaticImageTGA;
+ LLPointer<LLImageRaw> mStaticImageRaw;
+ std::atomic<bool> mNeedsCreateTexture;
+ bool mStaticImageInvalid;
+ LL_ALIGN_16(LLVector4a mAvgDistortionVec);
+ F32 mCachedEffectiveWeight;
+
+public:
+ // Global list of instances for gathering statistics
+ static void dumpCacheByteCount();
+ static void getCacheByteCount( S32* gl_bytes );
+
+ typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t;
+ static param_alpha_ptr_list_t sInstances;
+} LL_ALIGN_POSTFIX(16);
+class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo
+{
+ friend class LLTexLayerParamAlpha;
+public:
+ LLTexLayerParamAlphaInfo();
+ /*virtual*/ ~LLTexLayerParamAlphaInfo() {};
+
+ /*virtual*/ bool parseXml(LLXmlTreeNode* node);
+
+private:
+ std::string mStaticImageFileName;
+ bool mMultiplyBlend;
+ bool mSkipIfZeroWeight;
+ F32 mDomain;
+};
+//
+// LLTexLayerParamAlpha
+//-----------------------------------------------------------------------------
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerParamColor
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
+{
+ LL_ALIGN_NEW
+public:
+ enum EColorOperation
+ {
+ OP_ADD = 0,
+ OP_MULTIPLY = 1,
+ OP_BLEND = 2,
+ OP_COUNT = 3 // Number of operations
+ };
+
+ LLTexLayerParamColor( LLTexLayerInterface* layer );
+ LLTexLayerParamColor( LLAvatarAppearance* appearance );
+
+ /* virtual */ ~LLTexLayerParamColor();
+
+ /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
+
+ // LLVisualParam Virtual functions
+ ///*virtual*/ bool parseData(LLXmlTreeNode* node);
+ /*virtual*/ void apply( ESex avatar_sex ) {}
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget(F32 target_value);
+ /*virtual*/ void animate(F32 delta);
+
+
+ // LLViewerVisualParam Virtual functions
+ /*virtual*/ F32 getTotalDistortion() { return 1.f; }
+ /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
+ /*virtual*/ F32 getMaxDistortion() { return 3.f; }
+ /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); }
+ /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
+ /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
+
+ // New functions
+ LLColor4 getNetColor() const;
+protected:
+ LLTexLayerParamColor(const LLTexLayerParamColor& pOther);
+
+ virtual void onGlobalColorChanged() {}
+private:
+ LLVector4a mAvgDistortionVec;
+};
+
+class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
+{
+ friend class LLTexLayerParamColor;
+
+public:
+ LLTexLayerParamColorInfo();
+ virtual ~LLTexLayerParamColorInfo() {};
+ bool parseXml( LLXmlTreeNode* node );
+ LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; }
+private:
+ enum { MAX_COLOR_VALUES = 20 };
+ LLTexLayerParamColor::EColorOperation mOperation;
+ LLColor4 mColors[MAX_COLOR_VALUES];
+ S32 mNumColors;
+};
+
+typedef std::vector<LLTexLayerParamColor *> param_color_list_t;
+typedef std::vector<LLTexLayerParamAlpha *> param_alpha_list_t;
+typedef std::vector<LLTexLayerParamColorInfo *> param_color_info_list_t;
+typedef std::vector<LLTexLayerParamAlphaInfo *> param_alpha_info_list_t;
+
+#endif
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index 30a244be93..1b4916cce9 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -1,179 +1,179 @@
-/**
- * @file llviewervisualparam.cpp
- * @brief Implementation of LLViewerVisualParam class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llviewervisualparam.h"
-#include "llxmltree.h"
-#include "llwearable.h"
-
-//-----------------------------------------------------------------------------
-// LLViewerVisualParamInfo()
-//-----------------------------------------------------------------------------
-LLViewerVisualParamInfo::LLViewerVisualParamInfo()
- :
- mWearableType( LLWearableType::WT_INVALID ),
- mCrossWearable(false),
- mCamDist( 0.5f ),
- mCamAngle( 0.f ),
- mCamElevation( 0.f ),
- mEditGroupDisplayOrder( 0 ),
- mShowSimple(false),
- mSimpleMin(0.f),
- mSimpleMax(100.f)
-{
-}
-
-LLViewerVisualParamInfo::~LLViewerVisualParamInfo()
-{
-}
-
-//-----------------------------------------------------------------------------
-// parseXml()
-//-----------------------------------------------------------------------------
-bool LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
-{
- llassert( node->hasName( "param" ) );
-
- if (!LLVisualParamInfo::parseXml(node))
- return false;
-
- // VIEWER SPECIFIC PARAMS
-
- std::string wearable;
- static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
- if( node->getFastAttributeString( wearable_string, wearable) )
- {
- mWearableType = LLWearableType::getInstance()->typeNameToType( wearable );
- }
-
- static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
- if (!node->getFastAttributeString( edit_group_string, mEditGroup))
- {
- mEditGroup = "";
- }
-
- static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable");
- if (!node->getFastAttributeBOOL(cross_wearable_string, mCrossWearable))
- {
- mCrossWearable = false;
- }
-
- // Optional camera offsets from the current joint center. Used for generating "hints" (thumbnails).
- static LLStdStringHandle camera_distance_string = LLXmlTree::addAttributeString("camera_distance");
- node->getFastAttributeF32( camera_distance_string, mCamDist );
- static LLStdStringHandle camera_angle_string = LLXmlTree::addAttributeString("camera_angle");
- node->getFastAttributeF32( camera_angle_string, mCamAngle ); // in degrees
- static LLStdStringHandle camera_elevation_string = LLXmlTree::addAttributeString("camera_elevation");
- node->getFastAttributeF32( camera_elevation_string, mCamElevation );
-
- mCamAngle += 180;
-
- static S32 params_loaded = 0;
-
- // By default, parameters are displayed in the order in which they appear in the xml file.
- // "edit_group_order" overriddes.
- static LLStdStringHandle edit_group_order_string = LLXmlTree::addAttributeString("edit_group_order");
- if( !node->getFastAttributeF32( edit_group_order_string, mEditGroupDisplayOrder ) )
- {
- mEditGroupDisplayOrder = (F32)params_loaded;
- }
-
- params_loaded++;
-
- return true;
-}
-
-/*virtual*/ void LLViewerVisualParamInfo::toStream(std::ostream &out)
-{
- LLVisualParamInfo::toStream(out);
-
- out << mWearableType << "\t";
- out << mEditGroup << "\t";
- out << mEditGroupDisplayOrder << "\t";
-}
-
-//-----------------------------------------------------------------------------
-// LLViewerVisualParam()
-//-----------------------------------------------------------------------------
-LLViewerVisualParam::LLViewerVisualParam()
- : LLVisualParam()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLViewerVisualParam()
-//-----------------------------------------------------------------------------
-LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther)
- : LLVisualParam(pOther)
-{
-}
-
-//-----------------------------------------------------------------------------
-// ~LLViewerVisualParam()
-//-----------------------------------------------------------------------------
-LLViewerVisualParam::~LLViewerVisualParam()
-{
-}
-
-//-----------------------------------------------------------------------------
-// setInfo()
-//-----------------------------------------------------------------------------
-
-bool LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
-{
- llassert(mInfo == NULL);
- if (info->mID < 0)
- return false;
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight());
- return true;
-}
-
-/*
-//=============================================================================
-// These virtual functions should always be overridden,
-// but are included here for use as templates
-//=============================================================================
-
-//-----------------------------------------------------------------------------
-// parseData()
-//-----------------------------------------------------------------------------
-bool LLViewerVisualParam::parseData(LLXmlTreeNode *node)
-{
- LLViewerVisualParamInfo* info = new LLViewerVisualParamInfo;
-
- info->parseXml(node);
- if (!setInfo(info))
- return false;
-
- return true;
-}
-*/
+/**
+ * @file llviewervisualparam.cpp
+ * @brief Implementation of LLViewerVisualParam class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+
+#include "llviewervisualparam.h"
+#include "llxmltree.h"
+#include "llwearable.h"
+
+//-----------------------------------------------------------------------------
+// LLViewerVisualParamInfo()
+//-----------------------------------------------------------------------------
+LLViewerVisualParamInfo::LLViewerVisualParamInfo()
+ :
+ mWearableType( LLWearableType::WT_INVALID ),
+ mCrossWearable(false),
+ mCamDist( 0.5f ),
+ mCamAngle( 0.f ),
+ mCamElevation( 0.f ),
+ mEditGroupDisplayOrder( 0 ),
+ mShowSimple(false),
+ mSimpleMin(0.f),
+ mSimpleMax(100.f)
+{
+}
+
+LLViewerVisualParamInfo::~LLViewerVisualParamInfo()
+{
+}
+
+//-----------------------------------------------------------------------------
+// parseXml()
+//-----------------------------------------------------------------------------
+bool LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
+{
+ llassert( node->hasName( "param" ) );
+
+ if (!LLVisualParamInfo::parseXml(node))
+ return false;
+
+ // VIEWER SPECIFIC PARAMS
+
+ std::string wearable;
+ static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
+ if( node->getFastAttributeString( wearable_string, wearable) )
+ {
+ mWearableType = LLWearableType::getInstance()->typeNameToType( wearable );
+ }
+
+ static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
+ if (!node->getFastAttributeString( edit_group_string, mEditGroup))
+ {
+ mEditGroup = "";
+ }
+
+ static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable");
+ if (!node->getFastAttributeBOOL(cross_wearable_string, mCrossWearable))
+ {
+ mCrossWearable = false;
+ }
+
+ // Optional camera offsets from the current joint center. Used for generating "hints" (thumbnails).
+ static LLStdStringHandle camera_distance_string = LLXmlTree::addAttributeString("camera_distance");
+ node->getFastAttributeF32( camera_distance_string, mCamDist );
+ static LLStdStringHandle camera_angle_string = LLXmlTree::addAttributeString("camera_angle");
+ node->getFastAttributeF32( camera_angle_string, mCamAngle ); // in degrees
+ static LLStdStringHandle camera_elevation_string = LLXmlTree::addAttributeString("camera_elevation");
+ node->getFastAttributeF32( camera_elevation_string, mCamElevation );
+
+ mCamAngle += 180;
+
+ static S32 params_loaded = 0;
+
+ // By default, parameters are displayed in the order in which they appear in the xml file.
+ // "edit_group_order" overriddes.
+ static LLStdStringHandle edit_group_order_string = LLXmlTree::addAttributeString("edit_group_order");
+ if( !node->getFastAttributeF32( edit_group_order_string, mEditGroupDisplayOrder ) )
+ {
+ mEditGroupDisplayOrder = (F32)params_loaded;
+ }
+
+ params_loaded++;
+
+ return true;
+}
+
+/*virtual*/ void LLViewerVisualParamInfo::toStream(std::ostream &out)
+{
+ LLVisualParamInfo::toStream(out);
+
+ out << mWearableType << "\t";
+ out << mEditGroup << "\t";
+ out << mEditGroupDisplayOrder << "\t";
+}
+
+//-----------------------------------------------------------------------------
+// LLViewerVisualParam()
+//-----------------------------------------------------------------------------
+LLViewerVisualParam::LLViewerVisualParam()
+ : LLVisualParam()
+{
+}
+
+//-----------------------------------------------------------------------------
+// LLViewerVisualParam()
+//-----------------------------------------------------------------------------
+LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther)
+ : LLVisualParam(pOther)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLViewerVisualParam()
+//-----------------------------------------------------------------------------
+LLViewerVisualParam::~LLViewerVisualParam()
+{
+}
+
+//-----------------------------------------------------------------------------
+// setInfo()
+//-----------------------------------------------------------------------------
+
+bool LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
+{
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return false;
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight());
+ return true;
+}
+
+/*
+//=============================================================================
+// These virtual functions should always be overridden,
+// but are included here for use as templates
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// parseData()
+//-----------------------------------------------------------------------------
+bool LLViewerVisualParam::parseData(LLXmlTreeNode *node)
+{
+ LLViewerVisualParamInfo* info = new LLViewerVisualParamInfo;
+
+ info->parseXml(node);
+ if (!setInfo(info))
+ return false;
+
+ return true;
+}
+*/
diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h
index 42c32aa319..e384dce3ac 100644
--- a/indra/llappearance/llviewervisualparam.h
+++ b/indra/llappearance/llviewervisualparam.h
@@ -1,112 +1,112 @@
-/**
- * @file llviewervisualparam.h
- * @brief viewer side visual params (with data file parsing)
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLViewerVisualParam_H
-#define LL_LLViewerVisualParam_H
-
-#include "v3math.h"
-#include "llstring.h"
-#include "llvisualparam.h"
-
-class LLWearable;
-
-//-----------------------------------------------------------------------------
-// LLViewerVisualParamInfo
-//-----------------------------------------------------------------------------
-class LLViewerVisualParamInfo : public LLVisualParamInfo
-{
- friend class LLViewerVisualParam;
-public:
- LLViewerVisualParamInfo();
- /*virtual*/ ~LLViewerVisualParamInfo();
-
- /*virtual*/ bool parseXml(LLXmlTreeNode* node);
-
- /*virtual*/ void toStream(std::ostream &out);
-
-protected:
- S32 mWearableType;
- bool mCrossWearable;
- std::string mEditGroup;
- F32 mCamDist;
- F32 mCamAngle; // degrees
- F32 mCamElevation;
- F32 mEditGroupDisplayOrder;
- bool mShowSimple; // show edit controls when in "simple ui" mode?
- F32 mSimpleMin; // when in simple UI, apply this minimum, range 0.f to 100.f
- F32 mSimpleMax; // when in simple UI, apply this maximum, range 0.f to 100.f
-};
-
-//-----------------------------------------------------------------------------
-// LLViewerVisualParam
-// VIRTUAL CLASS
-// a viewer side interface class for a generalized parametric modification of the avatar mesh
-//-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLViewerVisualParam : public LLVisualParam
-{
-public:
- LLViewerVisualParam();
- virtual ~LLViewerVisualParam();
-
- // Special: These functions are overridden by child classes
- LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; };
- // This sets mInfo and calls initialization functions
- bool setInfo(LLViewerVisualParamInfo *info);
-
- virtual LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
-
- // LLVisualParam Virtual functions
- ///*virtual*/ bool parseData(LLXmlTreeNode* node);
-
- // New Virtual functions
- virtual F32 getTotalDistortion() = 0;
- virtual const LLVector4a& getAvgDistortion() = 0;
- virtual F32 getMaxDistortion() = 0;
- virtual LLVector4a getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0;
- virtual const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0;
- virtual const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0;
-
- // interface methods
- F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; }
- S32 getWearableType() const { return getInfo()->mWearableType; }
- const std::string& getEditGroup() const { return getInfo()->mEditGroup; }
-
- F32 getCameraDistance() const { return getInfo()->mCamDist; }
- F32 getCameraAngle() const { return getInfo()->mCamAngle; } // degrees
- F32 getCameraElevation() const { return getInfo()->mCamElevation; }
-
- bool getShowSimple() const { return getInfo()->mShowSimple; }
- F32 getSimpleMin() const { return getInfo()->mSimpleMin; }
- F32 getSimpleMax() const { return getInfo()->mSimpleMax; }
-
- bool getCrossWearable() const { return getInfo()->mCrossWearable; }
-
-protected:
- LLViewerVisualParam(const LLViewerVisualParam& pOther);
-} LL_ALIGN_POSTFIX(16);
-
-#endif // LL_LLViewerVisualParam_H
+/**
+ * @file llviewervisualparam.h
+ * @brief viewer side visual params (with data file parsing)
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLViewerVisualParam_H
+#define LL_LLViewerVisualParam_H
+
+#include "v3math.h"
+#include "llstring.h"
+#include "llvisualparam.h"
+
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+// LLViewerVisualParamInfo
+//-----------------------------------------------------------------------------
+class LLViewerVisualParamInfo : public LLVisualParamInfo
+{
+ friend class LLViewerVisualParam;
+public:
+ LLViewerVisualParamInfo();
+ /*virtual*/ ~LLViewerVisualParamInfo();
+
+ /*virtual*/ bool parseXml(LLXmlTreeNode* node);
+
+ /*virtual*/ void toStream(std::ostream &out);
+
+protected:
+ S32 mWearableType;
+ bool mCrossWearable;
+ std::string mEditGroup;
+ F32 mCamDist;
+ F32 mCamAngle; // degrees
+ F32 mCamElevation;
+ F32 mEditGroupDisplayOrder;
+ bool mShowSimple; // show edit controls when in "simple ui" mode?
+ F32 mSimpleMin; // when in simple UI, apply this minimum, range 0.f to 100.f
+ F32 mSimpleMax; // when in simple UI, apply this maximum, range 0.f to 100.f
+};
+
+//-----------------------------------------------------------------------------
+// LLViewerVisualParam
+// VIRTUAL CLASS
+// a viewer side interface class for a generalized parametric modification of the avatar mesh
+//-----------------------------------------------------------------------------
+LL_ALIGN_PREFIX(16)
+class LLViewerVisualParam : public LLVisualParam
+{
+public:
+ LLViewerVisualParam();
+ virtual ~LLViewerVisualParam();
+
+ // Special: These functions are overridden by child classes
+ LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; };
+ // This sets mInfo and calls initialization functions
+ bool setInfo(LLViewerVisualParamInfo *info);
+
+ virtual LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
+
+ // LLVisualParam Virtual functions
+ ///*virtual*/ bool parseData(LLXmlTreeNode* node);
+
+ // New Virtual functions
+ virtual F32 getTotalDistortion() = 0;
+ virtual const LLVector4a& getAvgDistortion() = 0;
+ virtual F32 getMaxDistortion() = 0;
+ virtual LLVector4a getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0;
+ virtual const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0;
+ virtual const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0;
+
+ // interface methods
+ F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; }
+ S32 getWearableType() const { return getInfo()->mWearableType; }
+ const std::string& getEditGroup() const { return getInfo()->mEditGroup; }
+
+ F32 getCameraDistance() const { return getInfo()->mCamDist; }
+ F32 getCameraAngle() const { return getInfo()->mCamAngle; } // degrees
+ F32 getCameraElevation() const { return getInfo()->mCamElevation; }
+
+ bool getShowSimple() const { return getInfo()->mShowSimple; }
+ F32 getSimpleMin() const { return getInfo()->mSimpleMin; }
+ F32 getSimpleMax() const { return getInfo()->mSimpleMax; }
+
+ bool getCrossWearable() const { return getInfo()->mCrossWearable; }
+
+protected:
+ LLViewerVisualParam(const LLViewerVisualParam& pOther);
+} LL_ALIGN_POSTFIX(16);
+
+#endif // LL_LLViewerVisualParam_H
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index 853b850fed..7f57d1c9c5 100644
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -1,773 +1,773 @@
-/**
- * @file llwearable.cpp
- * @brief LLWearable class implementation
- *
- * $LicenseInfo:firstyear=2002&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 "lllocaltextureobject.h"
-#include "lltexlayer.h"
-#include "lltexturemanagerbridge.h"
-#include "llvisualparam.h"
-#include "llavatarappearancedefines.h"
-#include "llwearable.h"
-#include "boost/bind.hpp"
-
-using namespace LLAvatarAppearanceDefines;
-
-// static
-S32 LLWearable::sCurrentDefinitionVersion = 1;
-
-// Private local functions
-static std::string terse_F32_to_string(F32 f);
-
-LLWearable::LLWearable()
- : mDefinitionVersion(-1),
- mName(),
- mDescription(),
- mPermissions(),
- mSaleInfo(),
- mType(LLWearableType::WT_NONE),
- mSavedVisualParamMap(),
- mVisualParamIndexMap(),
- mTEMap(),
- mSavedTEMap()
-{
-}
-
-// virtual
-LLWearable::~LLWearable()
-{
- for (visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- LLVisualParam* vp = vp_pair.second;
- vp->clearNextParam();
- delete vp;
- vp_pair.second = NULL;
- }
-
- destroyTextures();
-}
-
-const std::string& LLWearable::getTypeLabel() const
-{
- return LLWearableType::getInstance()->getTypeLabel(mType);
-}
-
-const std::string& LLWearable::getTypeName() const
-{
- return LLWearableType::getInstance()->getTypeName(mType);
-}
-
-LLAssetType::EType LLWearable::getAssetType() const
-{
- return LLWearableType::getInstance()->getAssetType(mType);
-}
-
-bool LLWearable::exportFile(const std::string& filename) const
-{
- llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
- return ofs.is_open() && exportStream(ofs);
-}
-
-// virtual
-bool LLWearable::exportStream( std::ostream& output_stream ) const
-{
- if (!output_stream.good()) return false;
-
- // header and version
- output_stream << "LLWearable version " << mDefinitionVersion << "\n";
- // name
- output_stream << mName << "\n";
- // description
- output_stream << mDescription << "\n";
-
- // permissions
- if( !mPermissions.exportLegacyStream( output_stream ) )
- {
- return false;
- }
-
- // sale info
- if( !mSaleInfo.exportLegacyStream( output_stream ) )
- {
- return false;
- }
-
- // wearable type
- output_stream << "type " << (S32) getType() << "\n";
-
- // parameters
- output_stream << "parameters " << mVisualParamIndexMap.size() << "\n";
-
- for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- S32 param_id = vp_pair.first;
- const LLVisualParam* param = vp_pair.second;
- F32 param_weight = param->getWeight();
- output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n";
- }
-
- // texture entries
- output_stream << "textures " << mTEMap.size() << "\n";
-
- for (const te_map_t::value_type& te_pair : mTEMap)
- {
- S32 te = te_pair.first;
- const LLUUID& image_id = te_pair.second->getID();
- output_stream << te << " " << image_id << "\n";
- }
- return true;
-}
-
-void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
-{
- for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
- {
- if (param->getWearableType() == mType)
- {
- LLVisualParam *clone_param = param->cloneParam(this);
- clone_param->setParamLocation(LOC_UNKNOWN);
- clone_param->setParamLocation(LOC_WEARABLE);
- addVisualParam(clone_param);
- }
- }
-
- // resync driver parameters to point to the newly cloned driven parameters
- for (visual_param_index_map_t::value_type& param_pair : mVisualParamIndexMap)
- {
- LLVisualParam* param = param_pair.second;
- LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam;
- // need this line to disambiguate between versions of LLCharacter::getVisualParam()
- LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
- param->resetDrivenParams();
- if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
- {
- if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
- {
- LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL;
- continue;
- }
- }
- }
-}
-
-void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
-{
- LLTexLayerSet *layer_set = NULL;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te);
- if (texture_dict && texture_dict->mIsUsedByBakedTexture)
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
-
- layer_set = avatarp->getAvatarLayerSet(baked_index);
- }
-
- if (layer_set)
- {
- layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
- }
- else
- {
- LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
- }
-}
-
-LLWearable::EImportResult LLWearable::importFile(const std::string& filename,
- LLAvatarAppearance* avatarp )
-{
- llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary);
- return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp);
-}
-
-// virtual
-LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
-{
- // *NOTE: changing the type or size of this buffer will require
- // changes in the fscanf() code below.
- // We are using a local max buffer size here to avoid issues
- // if MAX_STRING size changes.
- const U32 PARSE_BUFFER_SIZE = 2048;
- char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */
- char uuid_buffer[37]; /* Flawfinder: ignore */
-
- // This data is being generated on the viewer.
- // Impose some sane limits on parameter and texture counts.
- const S32 MAX_WEARABLE_ASSET_TEXTURES = 100;
- const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000;
-
- if(!avatarp)
- {
- return LLWearable::FAILURE;
- }
-
- // read header and version
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( 1 != sscanf( /* Flawfinder: ignore */
- buffer,
- "LLWearable version %d\n",
- &mDefinitionVersion ) )
- {
- return LLWearable::BAD_HEADER;
- }
-
- // Hack to allow wearables with definition version 24 to still load.
- // This should only affect lindens and NDA'd testers who have saved wearables in 2.0
- // the extra check for version == 24 can be removed before release, once internal testers
- // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
- // these wearables get re-saved with version definition 22.
- if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
- {
- LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // name may be empty
- if (!input_stream.good())
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading name" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- input_stream.getline(buffer, PARSE_BUFFER_SIZE);
- mName = buffer;
-
- // description may be empty
- if (!input_stream.good())
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading description" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- input_stream.getline(buffer, PARSE_BUFFER_SIZE);
- mDescription = buffer;
-
- // permissions may have extra empty lines before the correct line
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading permissions" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 perm_version = -1;
- if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) ||
- perm_version != 0 )
- {
- LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( !mPermissions.importLegacyStream( input_stream ) )
- {
- return LLWearable::FAILURE;
- }
-
- // sale info
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading sale info" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 sale_info_version = -1;
- if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) ||
- sale_info_version != 0 )
- {
- LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- // Sale info used to contain next owner perm. It is now in the
- // permissions. Thus, we read that out, and fix legacy
- // objects. It's possible this op would fail, but it should pick
- // up the vast majority of the tasks.
- bool has_perm_mask = false;
- U32 perm_mask = 0;
- if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) )
- {
- return LLWearable::FAILURE;
- }
- if(has_perm_mask)
- {
- // fair use fix.
- if(!(perm_mask & PERM_COPY))
- {
- perm_mask |= PERM_TRANSFER;
- }
- mPermissions.setMaskNext(perm_mask);
- }
-
- // wearable type
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading type" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 type = -1;
- if ( 1 != sscanf( buffer, "type %d\n", &type ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( 0 <= type && type < LLWearableType::WT_COUNT )
- {
- setType((LLWearableType::EType)type, avatarp);
- }
- else
- {
- mType = LLWearableType::WT_COUNT;
- LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // parameters header
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading parameters header" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 num_parameters = -1;
- if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) )
- {
- LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS )
- {
- LL_WARNS() << "Bad Wearable asset: too many parameters, "
- << num_parameters << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if( num_parameters != mVisualParamIndexMap.size() )
- {
- LL_WARNS() << "Wearable parameter mismatch. Reading in "
- << num_parameters << " from file, but created "
- << mVisualParamIndexMap.size()
- << " from avatar parameters. type: "
- << getType() << LL_ENDL;
- }
-
- // parameters
- S32 i;
- for( i = 0; i < num_parameters; i++ )
- {
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading parameter #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 param_id = 0;
- F32 param_weight = 0.f;
- if ( 2 != sscanf( buffer, "%d %f\n", &param_id, &param_weight ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- mSavedVisualParamMap[param_id] = param_weight;
- }
-
- // textures header
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading textures header" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 num_textures = -1;
- if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) )
- {
- LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL;
- return LLWearable::FAILURE;
- }
- if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES )
- {
- LL_WARNS() << "Bad Wearable asset: too many textures, "
- << num_textures << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- // textures
- for( i = 0; i < num_textures; i++ )
- {
- if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
- {
- LL_WARNS() << "Bad Wearable asset: early end of input stream "
- << "while reading textures #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
- S32 te = 0;
- if ( 2 != sscanf( /* Flawfinder: ignore */
- buffer,
- "%d %36s\n",
- &te, uuid_buffer) )
- {
- LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex
- {
- LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL;
- return LLWearable::FAILURE;
- }
-
- if( !LLUUID::validate( uuid_buffer ) )
- {
- LL_WARNS() << "Bad Wearable asset: bad texture uuid: "
- << uuid_buffer << LL_ENDL;
- return LLWearable::FAILURE;
- }
- LLUUID id = LLUUID(uuid_buffer);
- LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id );
- if( mTEMap.find(te) != mTEMap.end() )
- {
- delete mTEMap[te];
- }
- if( mSavedTEMap.find(te) != mSavedTEMap.end() )
- {
- delete mSavedTEMap[te];
- }
-
- LLUUID textureid(uuid_buffer);
- mTEMap[te] = new LLLocalTextureObject(image, textureid);
- mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
- createLayers(te, avatarp);
- }
-
- // copy all saved param values to working params
- revertValues();
-
- return LLWearable::SUCCESS;
-}
-
-bool LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size)
-{
- if (!input_stream.good())
- {
- return false;
- }
-
- do
- {
- input_stream.getline(buffer, buffer_size);
- }
- while (input_stream.good() && buffer[0]=='\0');
-
- return (buffer[0] != '\0');
-}
-
-
-void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
-{
- mType = type;
- createVisualParams(avatarp);
-}
-
-
-LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
-{
- te_map_t::iterator iter = mTEMap.find(index);
- if( iter != mTEMap.end() )
- {
- LLLocalTextureObject* lto = iter->second;
- return lto;
- }
- return NULL;
-}
-
-const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
-{
- te_map_t::const_iterator iter = mTEMap.find(index);
- if( iter != mTEMap.end() )
- {
- const LLLocalTextureObject* lto = iter->second;
- return lto;
- }
- return NULL;
-}
-
-std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
-{
- std::vector<LLLocalTextureObject*> result;
-
- for(te_map_t::value_type& te_pair : mTEMap)
- {
- LLLocalTextureObject* lto = te_pair.second;
- result.push_back(lto);
- }
-
- return result;
-}
-
-void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject &lto)
-{
- if( mTEMap.find(index) != mTEMap.end() )
- {
- mTEMap.erase(index);
- }
- mTEMap[index] = new LLLocalTextureObject(lto);
-}
-
-void LLWearable::revertValues()
-{
- // FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance.
-
- //update saved settings so wearable is no longer dirty
- // One loop should be necessary here
- for (param_map_t::value_type& vp_pair : mSavedVisualParamMap)
- {
- S32 id = vp_pair.first;
- LLVisualParam *param = getVisualParam(id);
- if(param)
- {
- F32 value = vp_pair.second;
- setVisualParamWeight(id, value);
- mSavedVisualParamMap[id] = param->getWeight();
- }
- }
-
- syncImages(mSavedTEMap, mTEMap);
-}
-
-void LLWearable::saveValues()
-{
- //update saved settings so wearable is no longer dirty
- mSavedVisualParamMap.clear();
- for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- S32 id = vp_pair.first;
- LLVisualParam *wearable_param = vp_pair.second;
- F32 value = wearable_param->getWeight();
- mSavedVisualParamMap[id] = value;
- }
-
- // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
- syncImages(mTEMap, mSavedTEMap);
-}
-
-void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
-{
- // Deep copy of src (copies only those tes that are current, filling in defaults where needed)
- for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
- {
- if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType)
- {
- te_map_t::const_iterator iter = src.find(te);
- LLUUID image_id;
- LLGLTexture *image = NULL;
- LLLocalTextureObject *lto = NULL;
- if(iter != src.end())
- {
- // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map.
- lto = iter->second;
- image = lto->getImage();
- image_id = lto->getID();
- }
- else
- {
- // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map.
- image_id = getDefaultTextureImageID((ETextureIndex) te);
- image = gTextureManagerBridgep->getFetchedTexture( image_id );
- }
-
- if( dst.find(te) != dst.end() )
- {
- // there's already an entry in the destination map for the texture. Just update its values.
- dst[te]->setImage(image);
- dst[te]->setID(image_id);
- }
- else
- {
- // no entry found in the destination map, we need to create a new Local Texture Object
- dst[te] = new LLLocalTextureObject(image, image_id);
- }
-
- if( lto )
- {
- // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map.
- dst[te]->setBakedReady(lto->getBakedReady());
- dst[te]->setDiscard(lto->getDiscard());
- }
- }
- }
-}
-
-void LLWearable::destroyTextures()
-{
- std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());
- mTEMap.clear();
-
- std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());
- mSavedTEMap.clear();
-}
-
-void LLWearable::addVisualParam(LLVisualParam *param)
-{
- if( mVisualParamIndexMap[param->getID()] )
- {
- delete mVisualParamIndexMap[param->getID()];
- }
- param->setIsDummy(false);
- param->setParamLocation(LOC_WEARABLE);
- mVisualParamIndexMap[param->getID()] = param;
- mSavedVisualParamMap[param->getID()] = param->getDefaultWeight();
-}
-
-
-void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
-{
- if( is_in_map(mVisualParamIndexMap, param_index ) )
- {
- LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
- wearable_param->setWeight(value);
- }
- else
- {
- LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
- }
-}
-
-F32 LLWearable::getVisualParamWeight(S32 param_index) const
-{
- if( is_in_map(mVisualParamIndexMap, param_index ) )
- {
- const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
- return wearable_param->getWeight();
- }
- else
- {
- LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
- }
- return (F32)-1.0;
-}
-
-LLVisualParam* LLWearable::getVisualParam(S32 index) const
-{
- visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index);
- return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second;
-}
-
-
-void LLWearable::getVisualParams(visual_param_vec_t &list)
-{
- // add all visual params to the passed-in vector
- for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- list.push_back(vp_pair.second);
- }
-}
-
-void LLWearable::animateParams(F32 delta)
-{
- for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
- {
- LLVisualParam *param = (LLVisualParam*)vp_pair.second;
- param->animate(delta);
- }
-}
-
-LLColor4 LLWearable::getClothesColor(S32 te) const
-{
- LLColor4 color;
- U32 param_name[3];
- if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
- {
- for( U8 index = 0; index < 3; index++ )
- {
- color.mV[index] = getVisualParamWeight(param_name[index]);
- }
- }
- return color;
-}
-
-void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
-{
- U32 param_name[3];
- if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
- {
- for( U8 index = 0; index < 3; index++ )
- {
- setVisualParamWeight(param_name[index], new_color.mV[index]);
- }
- }
-}
-
-void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
-{
- if (!avatarp) return;
-
- // Pull params
- for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
- {
- // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
- // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.
- if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) )
- {
- S32 param_id = param->getID();
- F32 weight = getVisualParamWeight(param_id);
-
- avatarp->setVisualParamWeight( param_id, weight);
- }
- }
-}
-
-
-std::string terse_F32_to_string(F32 f)
-{
- std::string r = llformat("%.2f", f);
- S32 len = r.length();
-
- // "1.20" -> "1.2"
- // "24.00" -> "24."
- while (len > 0 && ('0' == r[len - 1]))
- {
- r.erase(len-1, 1);
- len--;
- }
- if ('.' == r[len - 1])
- {
- // "24." -> "24"
- r.erase(len-1, 1);
- }
- else if (('-' == r[0]) && ('0' == r[1]))
- {
- // "-0.59" -> "-.59"
- r.erase(1, 1);
- }
- else if ('0' == r[0])
- {
- // "0.59" -> ".59"
- r.erase(0, 1);
- }
- return r;
-}
-
+/**
+ * @file llwearable.cpp
+ * @brief LLWearable class implementation
+ *
+ * $LicenseInfo:firstyear=2002&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 "lllocaltextureobject.h"
+#include "lltexlayer.h"
+#include "lltexturemanagerbridge.h"
+#include "llvisualparam.h"
+#include "llavatarappearancedefines.h"
+#include "llwearable.h"
+#include "boost/bind.hpp"
+
+using namespace LLAvatarAppearanceDefines;
+
+// static
+S32 LLWearable::sCurrentDefinitionVersion = 1;
+
+// Private local functions
+static std::string terse_F32_to_string(F32 f);
+
+LLWearable::LLWearable()
+ : mDefinitionVersion(-1),
+ mName(),
+ mDescription(),
+ mPermissions(),
+ mSaleInfo(),
+ mType(LLWearableType::WT_NONE),
+ mSavedVisualParamMap(),
+ mVisualParamIndexMap(),
+ mTEMap(),
+ mSavedTEMap()
+{
+}
+
+// virtual
+LLWearable::~LLWearable()
+{
+ for (visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
+ {
+ LLVisualParam* vp = vp_pair.second;
+ vp->clearNextParam();
+ delete vp;
+ vp_pair.second = NULL;
+ }
+
+ destroyTextures();
+}
+
+const std::string& LLWearable::getTypeLabel() const
+{
+ return LLWearableType::getInstance()->getTypeLabel(mType);
+}
+
+const std::string& LLWearable::getTypeName() const
+{
+ return LLWearableType::getInstance()->getTypeName(mType);
+}
+
+LLAssetType::EType LLWearable::getAssetType() const
+{
+ return LLWearableType::getInstance()->getAssetType(mType);
+}
+
+bool LLWearable::exportFile(const std::string& filename) const
+{
+ llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
+ return ofs.is_open() && exportStream(ofs);
+}
+
+// virtual
+bool LLWearable::exportStream( std::ostream& output_stream ) const
+{
+ if (!output_stream.good()) return false;
+
+ // header and version
+ output_stream << "LLWearable version " << mDefinitionVersion << "\n";
+ // name
+ output_stream << mName << "\n";
+ // description
+ output_stream << mDescription << "\n";
+
+ // permissions
+ if( !mPermissions.exportLegacyStream( output_stream ) )
+ {
+ return false;
+ }
+
+ // sale info
+ if( !mSaleInfo.exportLegacyStream( output_stream ) )
+ {
+ return false;
+ }
+
+ // wearable type
+ output_stream << "type " << (S32) getType() << "\n";
+
+ // parameters
+ output_stream << "parameters " << mVisualParamIndexMap.size() << "\n";
+
+ for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
+ {
+ S32 param_id = vp_pair.first;
+ const LLVisualParam* param = vp_pair.second;
+ F32 param_weight = param->getWeight();
+ output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n";
+ }
+
+ // texture entries
+ output_stream << "textures " << mTEMap.size() << "\n";
+
+ for (const te_map_t::value_type& te_pair : mTEMap)
+ {
+ S32 te = te_pair.first;
+ const LLUUID& image_id = te_pair.second->getID();
+ output_stream << te << " " << image_id << "\n";
+ }
+ return true;
+}
+
+void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
+{
+ for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
+ param;
+ param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
+ {
+ if (param->getWearableType() == mType)
+ {
+ LLVisualParam *clone_param = param->cloneParam(this);
+ clone_param->setParamLocation(LOC_UNKNOWN);
+ clone_param->setParamLocation(LOC_WEARABLE);
+ addVisualParam(clone_param);
+ }
+ }
+
+ // resync driver parameters to point to the newly cloned driven parameters
+ for (visual_param_index_map_t::value_type& param_pair : mVisualParamIndexMap)
+ {
+ LLVisualParam* param = param_pair.second;
+ LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam;
+ // need this line to disambiguate between versions of LLCharacter::getVisualParam()
+ LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
+ param->resetDrivenParams();
+ if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
+ {
+ if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
+ {
+ LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL;
+ continue;
+ }
+ }
+ }
+}
+
+void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
+{
+ LLTexLayerSet *layer_set = NULL;
+ const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te);
+ if (texture_dict && texture_dict->mIsUsedByBakedTexture)
+ {
+ const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+
+ layer_set = avatarp->getAvatarLayerSet(baked_index);
+ }
+
+ if (layer_set)
+ {
+ layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
+ }
+ else
+ {
+ LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
+ }
+}
+
+LLWearable::EImportResult LLWearable::importFile(const std::string& filename,
+ LLAvatarAppearance* avatarp )
+{
+ llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary);
+ return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp);
+}
+
+// virtual
+LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
+{
+ // *NOTE: changing the type or size of this buffer will require
+ // changes in the fscanf() code below.
+ // We are using a local max buffer size here to avoid issues
+ // if MAX_STRING size changes.
+ const U32 PARSE_BUFFER_SIZE = 2048;
+ char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */
+ char uuid_buffer[37]; /* Flawfinder: ignore */
+
+ // This data is being generated on the viewer.
+ // Impose some sane limits on parameter and texture counts.
+ const S32 MAX_WEARABLE_ASSET_TEXTURES = 100;
+ const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000;
+
+ if(!avatarp)
+ {
+ return LLWearable::FAILURE;
+ }
+
+ // read header and version
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if ( 1 != sscanf( /* Flawfinder: ignore */
+ buffer,
+ "LLWearable version %d\n",
+ &mDefinitionVersion ) )
+ {
+ return LLWearable::BAD_HEADER;
+ }
+
+ // Hack to allow wearables with definition version 24 to still load.
+ // This should only affect lindens and NDA'd testers who have saved wearables in 2.0
+ // the extra check for version == 24 can be removed before release, once internal testers
+ // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
+ // these wearables get re-saved with version definition 22.
+ if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
+ {
+ LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
+ // name may be empty
+ if (!input_stream.good())
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading name" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ input_stream.getline(buffer, PARSE_BUFFER_SIZE);
+ mName = buffer;
+
+ // description may be empty
+ if (!input_stream.good())
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading description" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ input_stream.getline(buffer, PARSE_BUFFER_SIZE);
+ mDescription = buffer;
+
+ // permissions may have extra empty lines before the correct line
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading permissions" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 perm_version = -1;
+ if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) ||
+ perm_version != 0 )
+ {
+ LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if( !mPermissions.importLegacyStream( input_stream ) )
+ {
+ return LLWearable::FAILURE;
+ }
+
+ // sale info
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading sale info" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 sale_info_version = -1;
+ if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) ||
+ sale_info_version != 0 )
+ {
+ LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ // Sale info used to contain next owner perm. It is now in the
+ // permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it should pick
+ // up the vast majority of the tasks.
+ bool has_perm_mask = false;
+ U32 perm_mask = 0;
+ if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) )
+ {
+ return LLWearable::FAILURE;
+ }
+ if(has_perm_mask)
+ {
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+
+ // wearable type
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading type" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 type = -1;
+ if ( 1 != sscanf( buffer, "type %d\n", &type ) )
+ {
+ LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if( 0 <= type && type < LLWearableType::WT_COUNT )
+ {
+ setType((LLWearableType::EType)type, avatarp);
+ }
+ else
+ {
+ mType = LLWearableType::WT_COUNT;
+ LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
+ // parameters header
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading parameters header" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 num_parameters = -1;
+ if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) )
+ {
+ LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS )
+ {
+ LL_WARNS() << "Bad Wearable asset: too many parameters, "
+ << num_parameters << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if( num_parameters != mVisualParamIndexMap.size() )
+ {
+ LL_WARNS() << "Wearable parameter mismatch. Reading in "
+ << num_parameters << " from file, but created "
+ << mVisualParamIndexMap.size()
+ << " from avatar parameters. type: "
+ << getType() << LL_ENDL;
+ }
+
+ // parameters
+ S32 i;
+ for( i = 0; i < num_parameters; i++ )
+ {
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading parameter #" << i << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 param_id = 0;
+ F32 param_weight = 0.f;
+ if ( 2 != sscanf( buffer, "%d %f\n", &param_id, &param_weight ) )
+ {
+ LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ mSavedVisualParamMap[param_id] = param_weight;
+ }
+
+ // textures header
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading textures header" << i << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 num_textures = -1;
+ if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) )
+ {
+ LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES )
+ {
+ LL_WARNS() << "Bad Wearable asset: too many textures, "
+ << num_textures << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
+ // textures
+ for( i = 0; i < num_textures; i++ )
+ {
+ if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
+ {
+ LL_WARNS() << "Bad Wearable asset: early end of input stream "
+ << "while reading textures #" << i << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ S32 te = 0;
+ if ( 2 != sscanf( /* Flawfinder: ignore */
+ buffer,
+ "%d %36s\n",
+ &te, uuid_buffer) )
+ {
+ LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
+ if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex
+ {
+ LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
+ if( !LLUUID::validate( uuid_buffer ) )
+ {
+ LL_WARNS() << "Bad Wearable asset: bad texture uuid: "
+ << uuid_buffer << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+ LLUUID id = LLUUID(uuid_buffer);
+ LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id );
+ if( mTEMap.find(te) != mTEMap.end() )
+ {
+ delete mTEMap[te];
+ }
+ if( mSavedTEMap.find(te) != mSavedTEMap.end() )
+ {
+ delete mSavedTEMap[te];
+ }
+
+ LLUUID textureid(uuid_buffer);
+ mTEMap[te] = new LLLocalTextureObject(image, textureid);
+ mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
+ createLayers(te, avatarp);
+ }
+
+ // copy all saved param values to working params
+ revertValues();
+
+ return LLWearable::SUCCESS;
+}
+
+bool LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size)
+{
+ if (!input_stream.good())
+ {
+ return false;
+ }
+
+ do
+ {
+ input_stream.getline(buffer, buffer_size);
+ }
+ while (input_stream.good() && buffer[0]=='\0');
+
+ return (buffer[0] != '\0');
+}
+
+
+void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
+{
+ mType = type;
+ createVisualParams(avatarp);
+}
+
+
+LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
+{
+ te_map_t::iterator iter = mTEMap.find(index);
+ if( iter != mTEMap.end() )
+ {
+ LLLocalTextureObject* lto = iter->second;
+ return lto;
+ }
+ return NULL;
+}
+
+const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
+{
+ te_map_t::const_iterator iter = mTEMap.find(index);
+ if( iter != mTEMap.end() )
+ {
+ const LLLocalTextureObject* lto = iter->second;
+ return lto;
+ }
+ return NULL;
+}
+
+std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
+{
+ std::vector<LLLocalTextureObject*> result;
+
+ for(te_map_t::value_type& te_pair : mTEMap)
+ {
+ LLLocalTextureObject* lto = te_pair.second;
+ result.push_back(lto);
+ }
+
+ return result;
+}
+
+void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject &lto)
+{
+ if( mTEMap.find(index) != mTEMap.end() )
+ {
+ mTEMap.erase(index);
+ }
+ mTEMap[index] = new LLLocalTextureObject(lto);
+}
+
+void LLWearable::revertValues()
+{
+ // FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance.
+
+ //update saved settings so wearable is no longer dirty
+ // One loop should be necessary here
+ for (param_map_t::value_type& vp_pair : mSavedVisualParamMap)
+ {
+ S32 id = vp_pair.first;
+ LLVisualParam *param = getVisualParam(id);
+ if(param)
+ {
+ F32 value = vp_pair.second;
+ param->setWeight(value);
+ mSavedVisualParamMap[id] = param->getWeight();
+ }
+ }
+
+ syncImages(mSavedTEMap, mTEMap);
+}
+
+void LLWearable::saveValues()
+{
+ //update saved settings so wearable is no longer dirty
+ mSavedVisualParamMap.clear();
+ for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
+ {
+ S32 id = vp_pair.first;
+ LLVisualParam *wearable_param = vp_pair.second;
+ F32 value = wearable_param->getWeight();
+ mSavedVisualParamMap[id] = value;
+ }
+
+ // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
+ syncImages(mTEMap, mSavedTEMap);
+}
+
+void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
+{
+ // Deep copy of src (copies only those tes that are current, filling in defaults where needed)
+ for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
+ {
+ if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType)
+ {
+ te_map_t::const_iterator iter = src.find(te);
+ LLUUID image_id;
+ LLGLTexture *image = NULL;
+ LLLocalTextureObject *lto = NULL;
+ if(iter != src.end())
+ {
+ // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map.
+ lto = iter->second;
+ image = lto->getImage();
+ image_id = lto->getID();
+ }
+ else
+ {
+ // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map.
+ image_id = getDefaultTextureImageID((ETextureIndex) te);
+ image = gTextureManagerBridgep->getFetchedTexture( image_id );
+ }
+
+ if( dst.find(te) != dst.end() )
+ {
+ // there's already an entry in the destination map for the texture. Just update its values.
+ dst[te]->setImage(image);
+ dst[te]->setID(image_id);
+ }
+ else
+ {
+ // no entry found in the destination map, we need to create a new Local Texture Object
+ dst[te] = new LLLocalTextureObject(image, image_id);
+ }
+
+ if( lto )
+ {
+ // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map.
+ dst[te]->setBakedReady(lto->getBakedReady());
+ dst[te]->setDiscard(lto->getDiscard());
+ }
+ }
+ }
+}
+
+void LLWearable::destroyTextures()
+{
+ std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());
+ mTEMap.clear();
+
+ std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());
+ mSavedTEMap.clear();
+}
+
+void LLWearable::addVisualParam(LLVisualParam *param)
+{
+ if( mVisualParamIndexMap[param->getID()] )
+ {
+ delete mVisualParamIndexMap[param->getID()];
+ }
+ param->setIsDummy(false);
+ param->setParamLocation(LOC_WEARABLE);
+ mVisualParamIndexMap[param->getID()] = param;
+ mSavedVisualParamMap[param->getID()] = param->getDefaultWeight();
+}
+
+
+void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
+{
+ if( is_in_map(mVisualParamIndexMap, param_index ) )
+ {
+ LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
+ wearable_param->setWeight(value);
+ }
+ else
+ {
+ LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
+ }
+}
+
+F32 LLWearable::getVisualParamWeight(S32 param_index) const
+{
+ if( is_in_map(mVisualParamIndexMap, param_index ) )
+ {
+ const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
+ return wearable_param->getWeight();
+ }
+ else
+ {
+ LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
+ }
+ return (F32)-1.0;
+}
+
+LLVisualParam* LLWearable::getVisualParam(S32 index) const
+{
+ visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index);
+ return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second;
+}
+
+
+void LLWearable::getVisualParams(visual_param_vec_t &list)
+{
+ // add all visual params to the passed-in vector
+ for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
+ {
+ list.push_back(vp_pair.second);
+ }
+}
+
+void LLWearable::animateParams(F32 delta)
+{
+ for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
+ {
+ LLVisualParam *param = (LLVisualParam*)vp_pair.second;
+ param->animate(delta);
+ }
+}
+
+LLColor4 LLWearable::getClothesColor(S32 te) const
+{
+ LLColor4 color;
+ U32 param_name[3];
+ if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
+ {
+ for( U8 index = 0; index < 3; index++ )
+ {
+ color.mV[index] = getVisualParamWeight(param_name[index]);
+ }
+ }
+ return color;
+}
+
+void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
+{
+ U32 param_name[3];
+ if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
+ {
+ for( U8 index = 0; index < 3; index++ )
+ {
+ setVisualParamWeight(param_name[index], new_color.mV[index]);
+ }
+ }
+}
+
+void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
+{
+ if (!avatarp) return;
+
+ // Pull params
+ for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
+ {
+ // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
+ // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.
+ if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) )
+ {
+ S32 param_id = param->getID();
+ F32 weight = getVisualParamWeight(param_id);
+
+ avatarp->setVisualParamWeight( param_id, weight);
+ }
+ }
+}
+
+
+std::string terse_F32_to_string(F32 f)
+{
+ std::string r = llformat("%.2f", f);
+ S32 len = r.length();
+
+ // "1.20" -> "1.2"
+ // "24.00" -> "24."
+ while (len > 0 && ('0' == r[len - 1]))
+ {
+ r.erase(len-1, 1);
+ len--;
+ }
+ if ('.' == r[len - 1])
+ {
+ // "24." -> "24"
+ r.erase(len-1, 1);
+ }
+ else if (('-' == r[0]) && ('0' == r[1]))
+ {
+ // "-0.59" -> "-.59"
+ r.erase(1, 1);
+ }
+ else if ('0' == r[0])
+ {
+ // "0.59" -> ".59"
+ r.erase(0, 1);
+ }
+ return r;
+}
+
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index ccdb3273f2..831b4bc07e 100644
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -1,138 +1,138 @@
-/**
- * @file llwearable.h
- * @brief LLWearable class header file
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#ifndef LL_LLWEARABLE_H
-#define LL_LLWEARABLE_H
-
-#include "llavatarappearancedefines.h"
-#include "llpermissions.h"
-#include "llsaleinfo.h"
-#include "llwearabletype.h"
-
-class LLVisualParam;
-class LLTexGlobalColorInfo;
-class LLTexGlobalColor;
-class LLLocalTextureObject;
-class LLAvatarAppearance;
-
-// Abstract class.
-class LLWearable
-{
- //--------------------------------------------------------------------
- // Constructors and destructors
- //--------------------------------------------------------------------
-public:
- LLWearable();
- virtual ~LLWearable();
-
- //--------------------------------------------------------------------
- // Accessors
- //--------------------------------------------------------------------
-public:
- LLWearableType::EType getType() const { return mType; }
- void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp);
- const std::string& getName() const { return mName; }
- void setName(const std::string& name) { mName = name; }
- const std::string& getDescription() const { return mDescription; }
- void setDescription(const std::string& desc) { mDescription = desc; }
- const LLPermissions& getPermissions() const { return mPermissions; }
- void setPermissions(const LLPermissions& p) { mPermissions = p; }
- const LLSaleInfo& getSaleInfo() const { return mSaleInfo; }
- void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; }
- const std::string& getTypeLabel() const;
- const std::string& getTypeName() const;
- LLAssetType::EType getAssetType() const;
- S32 getDefinitionVersion() const { return mDefinitionVersion; }
- void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; }
- static S32 getCurrentDefinitionVersion() { return LLWearable::sCurrentDefinitionVersion; }
-
-public:
- typedef std::vector<LLVisualParam*> visual_param_vec_t;
-
- virtual void writeToAvatar(LLAvatarAppearance* avatarp);
-
- enum EImportResult
- {
- FAILURE = 0,
- SUCCESS,
- BAD_HEADER
- };
- bool exportFile(const std::string& filename) const;
- EImportResult importFile(const std::string& filename, LLAvatarAppearance* avatarp );
- virtual bool exportStream( std::ostream& output_stream ) const;
- virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
-
- static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; }
- virtual LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const = 0;
-
- LLLocalTextureObject* getLocalTextureObject(S32 index);
- const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
- std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
-
- void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
- void addVisualParam(LLVisualParam *param);
- void setVisualParamWeight(S32 index, F32 value);
- F32 getVisualParamWeight(S32 index) const;
- LLVisualParam* getVisualParam(S32 index) const;
- void getVisualParams(visual_param_vec_t &list);
- void animateParams(F32 delta);
-
- LLColor4 getClothesColor(S32 te) const;
- void setClothesColor( S32 te, const LLColor4& new_color);
-
- virtual void revertValues();
- virtual void saveValues();
-
- // Something happened that requires the wearable to be updated (e.g. worn/unworn).
- virtual void setUpdated() const = 0;
-
- typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
- visual_param_index_map_t mVisualParamIndexMap;
-
-protected:
- typedef std::map<S32, LLLocalTextureObject*> te_map_t;
- void syncImages(te_map_t &src, te_map_t &dst);
- void destroyTextures();
- void createVisualParams(LLAvatarAppearance *avatarp);
- void createLayers(S32 te, LLAvatarAppearance *avatarp);
- bool getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size);
-
- static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml.
- S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created.
- std::string mName;
- std::string mDescription;
- LLPermissions mPermissions;
- LLSaleInfo mSaleInfo;
- LLWearableType::EType mType;
-
- typedef std::map<S32, F32> param_map_t;
- param_map_t mSavedVisualParamMap; // last saved version of visual params
-
- te_map_t mTEMap; // maps TE to LocalTextureObject
- te_map_t mSavedTEMap; // last saved version of TEMap
-};
-
-#endif // LL_LLWEARABLE_H
+/**
+ * @file llwearable.h
+ * @brief LLWearable class header file
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLWEARABLE_H
+#define LL_LLWEARABLE_H
+
+#include "llavatarappearancedefines.h"
+#include "llpermissions.h"
+#include "llsaleinfo.h"
+#include "llwearabletype.h"
+
+class LLVisualParam;
+class LLTexGlobalColorInfo;
+class LLTexGlobalColor;
+class LLLocalTextureObject;
+class LLAvatarAppearance;
+
+// Abstract class.
+class LLWearable
+{
+ //--------------------------------------------------------------------
+ // Constructors and destructors
+ //--------------------------------------------------------------------
+public:
+ LLWearable();
+ virtual ~LLWearable();
+
+ //--------------------------------------------------------------------
+ // Accessors
+ //--------------------------------------------------------------------
+public:
+ LLWearableType::EType getType() const { return mType; }
+ void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp);
+ const std::string& getName() const { return mName; }
+ void setName(const std::string& name) { mName = name; }
+ const std::string& getDescription() const { return mDescription; }
+ void setDescription(const std::string& desc) { mDescription = desc; }
+ const LLPermissions& getPermissions() const { return mPermissions; }
+ void setPermissions(const LLPermissions& p) { mPermissions = p; }
+ const LLSaleInfo& getSaleInfo() const { return mSaleInfo; }
+ void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; }
+ const std::string& getTypeLabel() const;
+ const std::string& getTypeName() const;
+ LLAssetType::EType getAssetType() const;
+ S32 getDefinitionVersion() const { return mDefinitionVersion; }
+ void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; }
+ static S32 getCurrentDefinitionVersion() { return LLWearable::sCurrentDefinitionVersion; }
+
+public:
+ typedef std::vector<LLVisualParam*> visual_param_vec_t;
+
+ virtual void writeToAvatar(LLAvatarAppearance* avatarp);
+
+ enum EImportResult
+ {
+ FAILURE = 0,
+ SUCCESS,
+ BAD_HEADER
+ };
+ bool exportFile(const std::string& filename) const;
+ EImportResult importFile(const std::string& filename, LLAvatarAppearance* avatarp );
+ virtual bool exportStream( std::ostream& output_stream ) const;
+ virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
+
+ static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; }
+ virtual LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const = 0;
+
+ LLLocalTextureObject* getLocalTextureObject(S32 index);
+ const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
+ std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
+
+ void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
+ void addVisualParam(LLVisualParam *param);
+ void setVisualParamWeight(S32 index, F32 value);
+ F32 getVisualParamWeight(S32 index) const;
+ LLVisualParam* getVisualParam(S32 index) const;
+ void getVisualParams(visual_param_vec_t &list);
+ void animateParams(F32 delta);
+
+ LLColor4 getClothesColor(S32 te) const;
+ void setClothesColor( S32 te, const LLColor4& new_color);
+
+ virtual void revertValues();
+ virtual void saveValues();
+
+ // Something happened that requires the wearable to be updated (e.g. worn/unworn).
+ virtual void setUpdated() const = 0;
+
+ typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
+ visual_param_index_map_t mVisualParamIndexMap;
+
+protected:
+ typedef std::map<S32, LLLocalTextureObject*> te_map_t;
+ void syncImages(te_map_t &src, te_map_t &dst);
+ void destroyTextures();
+ void createVisualParams(LLAvatarAppearance *avatarp);
+ void createLayers(S32 te, LLAvatarAppearance *avatarp);
+ bool getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size);
+
+ static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml.
+ S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created.
+ std::string mName;
+ std::string mDescription;
+ LLPermissions mPermissions;
+ LLSaleInfo mSaleInfo;
+ LLWearableType::EType mType;
+
+ typedef std::map<S32, F32> param_map_t;
+ param_map_t mSavedVisualParamMap; // last saved version of visual params
+
+ te_map_t mTEMap; // maps TE to LocalTextureObject
+ te_map_t mSavedTEMap; // last saved version of TEMap
+};
+
+#endif // LL_LLWEARABLE_H
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index db5c93352a..04f29ecf27 100644
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -1,344 +1,344 @@
-/**
- * @file llwearabledata.cpp
- * @brief LLWearableData class implementation
- *
- * $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 "llwearabledata.h"
-
-#include "llavatarappearance.h"
-#include "llavatarappearancedefines.h"
-#include "lldriverparam.h"
-
-LLWearableData::LLWearableData() :
- mAvatarAppearance(NULL)
-{
-}
-
-// virtual
-LLWearableData::~LLWearableData()
-{
-}
-
-using namespace LLAvatarAppearanceDefines;
-
-LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
-{
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return NULL;
- }
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
- {
- return NULL;
- }
- else
- {
- return wearable_vec[index];
- }
-}
-
-void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
-{
- LLWearable *old_wearable = getWearable(type,index);
- if (!old_wearable)
- {
- pushWearable(type,wearable);
- return;
- }
-
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- LL_WARNS() << "invalid type, type " << type << " index " << index << LL_ENDL;
- return;
- }
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
- {
- LL_WARNS() << "invalid index, type " << type << " index " << index << LL_ENDL;
- }
- else
- {
- wearable_vec[index] = wearable;
- old_wearable->setUpdated();
- const bool removed = false;
- wearableUpdated(wearable, removed);
- }
-}
-
-void LLWearableData::pushWearable(const LLWearableType::EType type,
- LLWearable *wearable,
- bool trigger_updated /* = true */)
-{
- if (wearable == NULL)
- {
- // no null wearables please!
- LL_WARNS() << "Null wearable sent for type " << type << LL_ENDL;
- }
- if (canAddWearable(type))
- {
- mWearableDatas[type].push_back(wearable);
- if (trigger_updated)
- {
- const bool removed = false;
- wearableUpdated(wearable, removed);
- }
- }
-}
-
-// virtual
-void LLWearableData::wearableUpdated(LLWearable *wearable, bool removed)
-{
- wearable->setUpdated();
- if (!removed)
- {
- pullCrossWearableValues(wearable->getType());
- }
-}
-
-void LLWearableData::eraseWearable(LLWearable *wearable)
-{
- if (wearable == NULL)
- {
- // nothing to do here. move along.
- return;
- }
-
- const LLWearableType::EType type = wearable->getType();
-
- U32 index;
- if (getWearableIndex(wearable,index))
- {
- eraseWearable(type, index);
- }
-}
-
-void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index)
-{
- LLWearable *wearable = getWearable(type, index);
- if (wearable)
- {
- mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
- const bool removed = true;
- wearableUpdated(wearable, removed);
- }
-}
-
-void LLWearableData::clearWearableType(const LLWearableType::EType type)
-{
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return;
- }
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- wearable_vec.clear();
-}
-
-bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
-{
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return false;
- }
-
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- // removed 0 > index_a and index_b comparisions - can never be true
- if (index_a >= wearable_vec.size()) return false;
- if (index_b >= wearable_vec.size()) return false;
-
- LLWearable* wearable = wearable_vec[index_a];
- wearable_vec[index_a] = wearable_vec[index_b];
- wearable_vec[index_b] = wearable;
- return true;
-}
-
-void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
-{
- llassert(mAvatarAppearance);
- // scan through all of the avatar's visual parameters
- for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam())
- {
- if( param )
- {
- LLDriverParam *driver_param = dynamic_cast<LLDriverParam*>(param);
- if(driver_param)
- {
- // parameter is a driver parameter, have it update its cross-driven params
- driver_param->updateCrossDrivenParams(type);
- }
- }
- }
-}
-
-
-bool LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_found) const
-{
- if (wearable == NULL)
- {
- return false;
- }
-
- const LLWearableType::EType type = wearable->getType();
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- LL_WARNS() << "tried to get wearable index with an invalid type!" << LL_ENDL;
- return false;
- }
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- for(U32 index = 0; index < wearable_vec.size(); index++)
- {
- if (wearable_vec[index] == wearable)
- {
- index_found = index;
- return true;
- }
- }
-
- return false;
-}
-
-U32 LLWearableData::getClothingLayerCount() const
-{
- U32 count = 0;
- LLWearableType *wr_inst = LLWearableType::getInstance();
- for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
- {
- LLWearableType::EType type = (LLWearableType::EType)i;
- if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
- {
- count += getWearableCount(type);
- }
- }
- return count;
-}
-
-bool LLWearableData::canAddWearable(const LLWearableType::EType type) const
-{
- LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
- if (a_type==LLAssetType::AT_CLOTHING)
- {
- return (getClothingLayerCount() < MAX_CLOTHING_LAYERS);
- }
- else if (a_type==LLAssetType::AT_BODYPART)
- {
- return (getWearableCount(type) < 1);
- }
- else
- {
- return false;
- }
-}
-
-bool LLWearableData::isOnTop(LLWearable* wearable) const
-{
- if (!wearable) return false;
- const LLWearableType::EType type = wearable->getType();
- return ( getTopWearable(type) == wearable );
-}
-
-const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const
-{
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return NULL;
- }
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
- {
- return NULL;
- }
- else
- {
- return wearable_vec[index];
- }
-}
-
-LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type)
-{
- U32 count = getWearableCount(type);
- if ( count == 0)
- {
- return NULL;
- }
-
- return getWearable(type, count-1);
-}
-
-const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const
-{
- U32 count = getWearableCount(type);
- if ( count == 0)
- {
- return NULL;
- }
-
- return getWearable(type, count-1);
-}
-
-LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type)
-{
- if (getWearableCount(type) == 0)
- {
- return NULL;
- }
-
- return getWearable(type, 0);
-}
-
-const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const
-{
- if (getWearableCount(type) == 0)
- {
- return NULL;
- }
-
- return getWearable(type, 0);
-}
-
-U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const
-{
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return 0;
- }
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- return wearable_vec.size();
-}
-
-U32 LLWearableData::getWearableCount(const U32 tex_index) const
-{
- const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
- return getWearableCount(wearable_type);
-}
+/**
+ * @file llwearabledata.cpp
+ * @brief LLWearableData class implementation
+ *
+ * $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 "llwearabledata.h"
+
+#include "llavatarappearance.h"
+#include "llavatarappearancedefines.h"
+#include "lldriverparam.h"
+
+LLWearableData::LLWearableData() :
+ mAvatarAppearance(NULL)
+{
+}
+
+// virtual
+LLWearableData::~LLWearableData()
+{
+}
+
+using namespace LLAvatarAppearanceDefines;
+
+LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return NULL;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ return wearable_vec[index];
+ }
+}
+
+void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
+{
+ LLWearable *old_wearable = getWearable(type,index);
+ if (!old_wearable)
+ {
+ pushWearable(type,wearable);
+ return;
+ }
+
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ LL_WARNS() << "invalid type, type " << type << " index " << index << LL_ENDL;
+ return;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ LL_WARNS() << "invalid index, type " << type << " index " << index << LL_ENDL;
+ }
+ else
+ {
+ wearable_vec[index] = wearable;
+ old_wearable->setUpdated();
+ const bool removed = false;
+ wearableUpdated(wearable, removed);
+ }
+}
+
+void LLWearableData::pushWearable(const LLWearableType::EType type,
+ LLWearable *wearable,
+ bool trigger_updated /* = true */)
+{
+ if (wearable == NULL)
+ {
+ // no null wearables please!
+ LL_WARNS() << "Null wearable sent for type " << type << LL_ENDL;
+ }
+ if (canAddWearable(type))
+ {
+ mWearableDatas[type].push_back(wearable);
+ if (trigger_updated)
+ {
+ const bool removed = false;
+ wearableUpdated(wearable, removed);
+ }
+ }
+}
+
+// virtual
+void LLWearableData::wearableUpdated(LLWearable *wearable, bool removed)
+{
+ wearable->setUpdated();
+ if (!removed)
+ {
+ pullCrossWearableValues(wearable->getType());
+ }
+}
+
+void LLWearableData::eraseWearable(LLWearable *wearable)
+{
+ if (wearable == NULL)
+ {
+ // nothing to do here. move along.
+ return;
+ }
+
+ const LLWearableType::EType type = wearable->getType();
+
+ U32 index;
+ if (getWearableIndex(wearable,index))
+ {
+ eraseWearable(type, index);
+ }
+}
+
+void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index)
+{
+ LLWearable *wearable = getWearable(type, index);
+ if (wearable)
+ {
+ mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
+ const bool removed = true;
+ wearableUpdated(wearable, removed);
+ }
+}
+
+void LLWearableData::clearWearableType(const LLWearableType::EType type)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return;
+ }
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ wearable_vec.clear();
+}
+
+bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
+{
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return false;
+ }
+
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ // removed 0 > index_a and index_b comparisions - can never be true
+ if (index_a >= wearable_vec.size()) return false;
+ if (index_b >= wearable_vec.size()) return false;
+
+ LLWearable* wearable = wearable_vec[index_a];
+ wearable_vec[index_a] = wearable_vec[index_b];
+ wearable_vec[index_b] = wearable;
+ return true;
+}
+
+void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
+{
+ llassert(mAvatarAppearance);
+ // scan through all of the avatar's visual parameters
+ for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam();
+ param;
+ param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam())
+ {
+ if( param )
+ {
+ LLDriverParam *driver_param = dynamic_cast<LLDriverParam*>(param);
+ if(driver_param)
+ {
+ // parameter is a driver parameter, have it update its cross-driven params
+ driver_param->updateCrossDrivenParams(type);
+ }
+ }
+ }
+}
+
+
+bool LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_found) const
+{
+ if (wearable == NULL)
+ {
+ return false;
+ }
+
+ const LLWearableType::EType type = wearable->getType();
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ LL_WARNS() << "tried to get wearable index with an invalid type!" << LL_ENDL;
+ return false;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ for(U32 index = 0; index < wearable_vec.size(); index++)
+ {
+ if (wearable_vec[index] == wearable)
+ {
+ index_found = index;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+U32 LLWearableData::getClothingLayerCount() const
+{
+ U32 count = 0;
+ LLWearableType *wr_inst = LLWearableType::getInstance();
+ for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
+ {
+ LLWearableType::EType type = (LLWearableType::EType)i;
+ if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
+ {
+ count += getWearableCount(type);
+ }
+ }
+ return count;
+}
+
+bool LLWearableData::canAddWearable(const LLWearableType::EType type) const
+{
+ LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
+ if (a_type==LLAssetType::AT_CLOTHING)
+ {
+ return (getClothingLayerCount() < MAX_CLOTHING_LAYERS);
+ }
+ else if (a_type==LLAssetType::AT_BODYPART)
+ {
+ return (getWearableCount(type) < 1);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool LLWearableData::isOnTop(LLWearable* wearable) const
+{
+ if (!wearable) return false;
+ const LLWearableType::EType type = wearable->getType();
+ return ( getTopWearable(type) == wearable );
+}
+
+const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const
+{
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return NULL;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (index>=wearable_vec.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ return wearable_vec[index];
+ }
+}
+
+LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type)
+{
+ U32 count = getWearableCount(type);
+ if ( count == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, count-1);
+}
+
+const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const
+{
+ U32 count = getWearableCount(type);
+ if ( count == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, count-1);
+}
+
+LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type)
+{
+ if (getWearableCount(type) == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, 0);
+}
+
+const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const
+{
+ if (getWearableCount(type) == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, 0);
+}
+
+U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const
+{
+ wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
+ if (wearable_iter == mWearableDatas.end())
+ {
+ return 0;
+ }
+ const wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ return wearable_vec.size();
+}
+
+U32 LLWearableData::getWearableCount(const U32 tex_index) const
+{
+ const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
+ return getWearableCount(wearable_type);
+}
diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h
index 2fe9ae2302..1396dda52c 100644
--- a/indra/llappearance/llwearabledata.h
+++ b/indra/llappearance/llwearabledata.h
@@ -1,102 +1,102 @@
-/**
- * @file llwearabledata.h
- * @brief LLWearableData class header file
- *
- * $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$
- */
-
-#ifndef LL_WEARABLEDATA_H
-#define LL_WEARABLEDATA_H
-
-#include "llavatarappearancedefines.h"
-#include "llwearable.h"
-#include "llerror.h"
-
-class LLAvatarAppearance;
-
-class LLWearableData
-{
- // *TODO: Figure out why this is causing compile error.
- //LOG_CLASS(LLWearableData);
-
- //--------------------------------------------------------------------
- // Constructors / destructors / Initializers
- //--------------------------------------------------------------------
-public:
- LLWearableData();
- virtual ~LLWearableData();
-
- void setAvatarAppearance(LLAvatarAppearance* appearance) { mAvatarAppearance = appearance; }
-
-protected:
- //--------------------------------------------------------------------
- // Accessors
- //--------------------------------------------------------------------
-public:
- LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/);
- const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
- LLWearable* getTopWearable(const LLWearableType::EType type);
- const LLWearable* getTopWearable(const LLWearableType::EType type) const;
- LLWearable* getBottomWearable(const LLWearableType::EType type);
- const LLWearable* getBottomWearable(const LLWearableType::EType type) const;
- U32 getWearableCount(const LLWearableType::EType type) const;
- U32 getWearableCount(const U32 tex_index) const;
- bool getWearableIndex(const LLWearable *wearable, U32& index) const;
- U32 getClothingLayerCount() const;
- bool canAddWearable(const LLWearableType::EType type) const;
-
- bool isOnTop(LLWearable* wearable) const;
-
- static const U32 MAX_CLOTHING_LAYERS = 60;
-
- //--------------------------------------------------------------------
- // Setters
- //--------------------------------------------------------------------
-protected:
- // Low-level data structure setter - public access is via setWearableItem, etc.
- void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
- void pushWearable(const LLWearableType::EType type, LLWearable *wearable,
- bool trigger_updated = true);
- virtual void wearableUpdated(LLWearable *wearable, bool removed);
- void eraseWearable(LLWearable *wearable);
- void eraseWearable(const LLWearableType::EType type, U32 index);
- void clearWearableType(const LLWearableType::EType type);
- bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
-
-private:
- void pullCrossWearableValues(const LLWearableType::EType type);
-
- //--------------------------------------------------------------------
- // Member variables
- //--------------------------------------------------------------------
-protected:
- LLAvatarAppearance* mAvatarAppearance;
- typedef std::vector<LLWearable*> wearableentry_vec_t; // all wearables of a certain type (EG all shirts)
- typedef std::map<LLWearableType::EType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
- wearableentry_map_t mWearableDatas;
-
-};
-
-
-
-#endif // LL_WEARABLEDATA_H
-
+/**
+ * @file llwearabledata.h
+ * @brief LLWearableData class header file
+ *
+ * $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$
+ */
+
+#ifndef LL_WEARABLEDATA_H
+#define LL_WEARABLEDATA_H
+
+#include "llavatarappearancedefines.h"
+#include "llwearable.h"
+#include "llerror.h"
+
+class LLAvatarAppearance;
+
+class LLWearableData
+{
+ // *TODO: Figure out why this is causing compile error.
+ //LOG_CLASS(LLWearableData);
+
+ //--------------------------------------------------------------------
+ // Constructors / destructors / Initializers
+ //--------------------------------------------------------------------
+public:
+ LLWearableData();
+ virtual ~LLWearableData();
+
+ void setAvatarAppearance(LLAvatarAppearance* appearance) { mAvatarAppearance = appearance; }
+
+protected:
+ //--------------------------------------------------------------------
+ // Accessors
+ //--------------------------------------------------------------------
+public:
+ LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/);
+ const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
+ LLWearable* getTopWearable(const LLWearableType::EType type);
+ const LLWearable* getTopWearable(const LLWearableType::EType type) const;
+ LLWearable* getBottomWearable(const LLWearableType::EType type);
+ const LLWearable* getBottomWearable(const LLWearableType::EType type) const;
+ U32 getWearableCount(const LLWearableType::EType type) const;
+ U32 getWearableCount(const U32 tex_index) const;
+ bool getWearableIndex(const LLWearable *wearable, U32& index) const;
+ U32 getClothingLayerCount() const;
+ bool canAddWearable(const LLWearableType::EType type) const;
+
+ bool isOnTop(LLWearable* wearable) const;
+
+ static const U32 MAX_CLOTHING_LAYERS = 60;
+
+ //--------------------------------------------------------------------
+ // Setters
+ //--------------------------------------------------------------------
+protected:
+ // Low-level data structure setter - public access is via setWearableItem, etc.
+ void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
+ void pushWearable(const LLWearableType::EType type, LLWearable *wearable,
+ bool trigger_updated = true);
+ virtual void wearableUpdated(LLWearable *wearable, bool removed);
+ void eraseWearable(LLWearable *wearable);
+ void eraseWearable(const LLWearableType::EType type, U32 index);
+ void clearWearableType(const LLWearableType::EType type);
+ bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
+
+private:
+ void pullCrossWearableValues(const LLWearableType::EType type);
+
+ //--------------------------------------------------------------------
+ // Member variables
+ //--------------------------------------------------------------------
+protected:
+ LLAvatarAppearance* mAvatarAppearance;
+ typedef std::vector<LLWearable*> wearableentry_vec_t; // all wearables of a certain type (EG all shirts)
+ typedef std::map<LLWearableType::EType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
+ wearableentry_map_t mWearableDatas;
+
+};
+
+
+
+#endif // LL_WEARABLEDATA_H
+
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index c561502a3d..0e870232e8 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -1,134 +1,134 @@
-/**
- * @file llwearabletype.cpp
- * @brief LLWearableType class implementation
- *
- * $LicenseInfo:firstyear=2002&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 "llwearabletype.h"
-#include "llinventorytype.h"
-#include "llinventorydefines.h"
-
-
-LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans)
-{
- addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, false, false));
- addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, false, false));
- addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, false, false));
- addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, false, false));
- addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, false, true));
- addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, false, true));
- addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, false, true));
- addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, false, true));
- addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, false, true));
- addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, false, true));
- addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, false, true));
- addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, false, true));
- addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, false, true));
- addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, false, true));
- addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, false, true));
- addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, false, true));
-
- addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, true, true));
-
- addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, false, false));
- addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, false, false));
-}
-
-
-// class LLWearableType
-
-LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans)
-: mDictionary(trans)
-{
-}
-
-LLWearableType::~LLWearableType()
-{
-}
-
-void LLWearableType::initSingleton()
-{
-}
-
-LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
-{
- const LLWearableType::EType wearable = mDictionary.lookup(type_name);
- return wearable;
-}
-
-const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return getTypeName(WT_INVALID);
- return entry->mName;
-}
-
-const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return getTypeDefaultNewName(WT_INVALID);
- return entry->mDefaultNewName;
-}
-
-const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return getTypeLabel(WT_INVALID);
- return entry->mLabel;
-}
-
-LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return getAssetType(WT_INVALID);
- return entry->mAssetType;
-}
-
-LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return getIconName(WT_INVALID);
- return entry->mIconName;
-}
-
-bool LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return false;
- return entry->mDisableCameraSwitch;
-}
-
-bool LLWearableType::getAllowMultiwear(LLWearableType::EType type)
-{
- const WearableEntry *entry = mDictionary.lookup(type);
- if (!entry) return false;
- return entry->mAllowMultiwear;
-}
-
-// static
-LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags)
-{
- return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK);
-}
-
+/**
+ * @file llwearabletype.cpp
+ * @brief LLWearableType class implementation
+ *
+ * $LicenseInfo:firstyear=2002&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 "llwearabletype.h"
+#include "llinventorytype.h"
+#include "llinventorydefines.h"
+
+
+LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans)
+{
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, false, false));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, false, false));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, false, false));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, false, false));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, false, true));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, false, true));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, false, true));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, false, true));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, false, true));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, false, true));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, false, true));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, false, true));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, false, true));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, false, true));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, false, true));
+ addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, false, true));
+
+ addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, true, true));
+
+ addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, false, false));
+ addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, false, false));
+}
+
+
+// class LLWearableType
+
+LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans)
+: mDictionary(trans)
+{
+}
+
+LLWearableType::~LLWearableType()
+{
+}
+
+void LLWearableType::initSingleton()
+{
+}
+
+LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
+{
+ const LLWearableType::EType wearable = mDictionary.lookup(type_name);
+ return wearable;
+}
+
+const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return getTypeName(WT_INVALID);
+ return entry->mName;
+}
+
+const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return getTypeDefaultNewName(WT_INVALID);
+ return entry->mDefaultNewName;
+}
+
+const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return getTypeLabel(WT_INVALID);
+ return entry->mLabel;
+}
+
+LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return getAssetType(WT_INVALID);
+ return entry->mAssetType;
+}
+
+LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return getIconName(WT_INVALID);
+ return entry->mIconName;
+}
+
+bool LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return false;
+ return entry->mDisableCameraSwitch;
+}
+
+bool LLWearableType::getAllowMultiwear(LLWearableType::EType type)
+{
+ const WearableEntry *entry = mDictionary.lookup(type);
+ if (!entry) return false;
+ return entry->mAllowMultiwear;
+}
+
+// static
+LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags)
+{
+ return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK);
+}
+
diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h
index 9a68dbe841..10238994ba 100644
--- a/indra/llappearance/llwearabletype.h
+++ b/indra/llappearance/llwearabletype.h
@@ -1,118 +1,118 @@
-/**
- * @file llwearabletype.h
- * @brief LLWearableType class header file
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#ifndef LL_LLWEARABLETYPE_H
-#define LL_LLWEARABLETYPE_H
-
-#include "llassettype.h"
-#include "lldictionary.h"
-#include "llinventorytype.h"
-#include "llsingleton.h"
-#include "llinvtranslationbrdg.h"
-
-class LLWearableType : public LLParamSingleton<LLWearableType>
-{
- LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
- ~LLWearableType();
- void initSingleton() override;
-public:
- enum EType
- {
- WT_SHAPE = 0,
- WT_SKIN = 1,
- WT_HAIR = 2,
- WT_EYES = 3,
- WT_SHIRT = 4,
- WT_PANTS = 5,
- WT_SHOES = 6,
- WT_SOCKS = 7,
- WT_JACKET = 8,
- WT_GLOVES = 9,
- WT_UNDERSHIRT = 10,
- WT_UNDERPANTS = 11,
- WT_SKIRT = 12,
- WT_ALPHA = 13,
- WT_TATTOO = 14,
- WT_PHYSICS = 15,
- WT_UNIVERSAL = 16,
- WT_COUNT = 17,
-
- WT_INVALID = 255,
- WT_NONE = -1,
- };
-
- // Most methods are wrappers for dictionary, but if LLWearableType is not initialized,
- // they will crash. Whole LLWearableType is just wrapper for convinient calls.
- const std::string& getTypeName(EType type);
- const std::string& getTypeDefaultNewName(EType type);
- const std::string& getTypeLabel(EType type);
- LLAssetType::EType getAssetType(EType type);
- EType typeNameToType(const std::string& type_name);
- LLInventoryType::EIconName getIconName(EType type);
- bool getDisableCameraSwitch(EType type);
- bool getAllowMultiwear(EType type);
-
- static EType inventoryFlagsToWearableType(U32 flags);
-
-private:
- struct WearableEntry : public LLDictionaryEntry
- {
- WearableEntry(LLTranslationBridge::ptr_t& trans,
- const std::string &name,
- const std::string& default_new_name,
- LLAssetType::EType assetType,
- LLInventoryType::EIconName iconName,
- bool disable_camera_switch = false,
- bool allow_multiwear = true) :
- LLDictionaryEntry(name),
- mAssetType(assetType),
- mDefaultNewName(default_new_name),
- mLabel(trans->getString(name)),
- mIconName(iconName),
- mDisableCameraSwitch(disable_camera_switch),
- mAllowMultiwear(allow_multiwear)
- {
-
- }
- const LLAssetType::EType mAssetType;
- const std::string mLabel;
- const std::string mDefaultNewName;
- LLInventoryType::EIconName mIconName;
- bool mDisableCameraSwitch;
- bool mAllowMultiwear;
- };
-
- class LLWearableDictionary : public LLDictionary<LLWearableType::EType, WearableEntry>
- {
- public:
- LLWearableDictionary(LLTranslationBridge::ptr_t& trans);
- ~LLWearableDictionary() {}
- };
-
- LLWearableDictionary mDictionary;
-};
-
-#endif // LL_LLWEARABLETYPE_H
+/**
+ * @file llwearabletype.h
+ * @brief LLWearableType class header file
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLWEARABLETYPE_H
+#define LL_LLWEARABLETYPE_H
+
+#include "llassettype.h"
+#include "lldictionary.h"
+#include "llinventorytype.h"
+#include "llsingleton.h"
+#include "llinvtranslationbrdg.h"
+
+class LLWearableType : public LLParamSingleton<LLWearableType>
+{
+ LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
+ ~LLWearableType();
+ void initSingleton() override;
+public:
+ enum EType
+ {
+ WT_SHAPE = 0,
+ WT_SKIN = 1,
+ WT_HAIR = 2,
+ WT_EYES = 3,
+ WT_SHIRT = 4,
+ WT_PANTS = 5,
+ WT_SHOES = 6,
+ WT_SOCKS = 7,
+ WT_JACKET = 8,
+ WT_GLOVES = 9,
+ WT_UNDERSHIRT = 10,
+ WT_UNDERPANTS = 11,
+ WT_SKIRT = 12,
+ WT_ALPHA = 13,
+ WT_TATTOO = 14,
+ WT_PHYSICS = 15,
+ WT_UNIVERSAL = 16,
+ WT_COUNT = 17,
+
+ WT_INVALID = 255,
+ WT_NONE = -1,
+ };
+
+ // Most methods are wrappers for dictionary, but if LLWearableType is not initialized,
+ // they will crash. Whole LLWearableType is just wrapper for convinient calls.
+ const std::string& getTypeName(EType type);
+ const std::string& getTypeDefaultNewName(EType type);
+ const std::string& getTypeLabel(EType type);
+ LLAssetType::EType getAssetType(EType type);
+ EType typeNameToType(const std::string& type_name);
+ LLInventoryType::EIconName getIconName(EType type);
+ bool getDisableCameraSwitch(EType type);
+ bool getAllowMultiwear(EType type);
+
+ static EType inventoryFlagsToWearableType(U32 flags);
+
+private:
+ struct WearableEntry : public LLDictionaryEntry
+ {
+ WearableEntry(LLTranslationBridge::ptr_t& trans,
+ const std::string &name,
+ const std::string& default_new_name,
+ LLAssetType::EType assetType,
+ LLInventoryType::EIconName iconName,
+ bool disable_camera_switch = false,
+ bool allow_multiwear = true) :
+ LLDictionaryEntry(name),
+ mAssetType(assetType),
+ mDefaultNewName(default_new_name),
+ mLabel(trans->getString(name)),
+ mIconName(iconName),
+ mDisableCameraSwitch(disable_camera_switch),
+ mAllowMultiwear(allow_multiwear)
+ {
+
+ }
+ const LLAssetType::EType mAssetType;
+ const std::string mLabel;
+ const std::string mDefaultNewName;
+ LLInventoryType::EIconName mIconName;
+ bool mDisableCameraSwitch;
+ bool mAllowMultiwear;
+ };
+
+ class LLWearableDictionary : public LLDictionary<LLWearableType::EType, WearableEntry>
+ {
+ public:
+ LLWearableDictionary(LLTranslationBridge::ptr_t& trans);
+ ~LLWearableDictionary() {}
+ };
+
+ LLWearableDictionary mDictionary;
+};
+
+#endif // LL_LLWEARABLETYPE_H