Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+86
View File
@@ -0,0 +1,86 @@
# -*- cmake -*-
project(llappearance)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLCoreHttp)
include(LLWindow)
include(Linking)
set(llappearance_SOURCE_FILES
llavatarappearance.cpp
llavatarjoint.cpp
llavatarjointmesh.cpp
lldriverparam.cpp
lllocaltextureobject.cpp
llpolyskeletaldistortion.cpp
llpolymesh.cpp
llpolymorph.cpp
lltexglobalcolor.cpp
lltexlayer.cpp
lltexlayerparams.cpp
llwearable.cpp
llwearabledata.cpp
llwearabletype.cpp
llviewervisualparam.cpp
llavatarappearancedefines.cpp
)
set(llappearance_HEADER_FILES
CMakeLists.txt
llavatarappearance.h
llavatarjoint.h
llavatarjointmesh.h
lldriverparam.h
lljointpickname.h
lllocaltextureobject.h
llpolyskeletaldistortion.h
llpolymesh.h
llpolymorph.h
lltexglobalcolor.h
lltexlayer.h
lltexlayerparams.h
llwearable.h
llwearabledata.h
llwearabletype.h
llviewervisualparam.h
llavatarappearancedefines.h
)
list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES})
add_library (llappearance ${llappearance_SOURCE_FILES})
target_link_libraries(llappearance
llcharacter
llinventory
llimage
llrender
llfilesystem
llmath
llxml
llmessage
llcorehttp
llcommon
)
target_include_directories( llappearance INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
if (BUILD_HEADLESS)
add_library (llappearanceheadless ${llappearance_SOURCE_FILES})
target_include_directories( llappearanceheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(llappearanceheadless
llcharacter
llinventory
llimage
llfilesystem
llmath
llxml
llmessage
llcorehttp
llcommon
)
endif (BUILD_HEADLESS)
File diff suppressed because it is too large Load Diff
+491
View File
@@ -0,0 +1,491 @@
/**
* @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{ 0 };
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; }
// <FS:Ansariel> [Legacy Bake]
virtual bool isUsingServerBakes() const = 0;
/** 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{ nullptr };
//<FS:Ansariel> Joint-lookup improvements
// typedef std::map<std::string, LLJoint*> joint_map_t;
typedef std::map<std::string, LLJoint*, std::less<>> 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, std::less<>> 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();
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
virtual F32 getAvatarOffset() /*const*/;
// [/RLVa:KB]
// <FS:Ansariel> [Legacy Bake]
virtual void bodySizeChanged() = 0;
bool setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
bool allocateCharacterJoints(S32 num);
bool buildSkeleton(const LLAvatarSkeletonInfo *info);
void clearSkeleton();
bool mIsBuilt{ false }; // 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{ 0.f };
//--------------------------------------------------------------------
// Cached pointers to well known joints
//--------------------------------------------------------------------
public:
LLJoint* mPelvisp{nullptr};
LLJoint* mTorsop{ nullptr };
LLJoint* mChestp{ nullptr };
LLJoint* mNeckp{ nullptr };
LLJoint* mHeadp{ nullptr };
LLJoint* mSkullp{ nullptr };
LLJoint* mEyeLeftp{ nullptr };
LLJoint* mEyeRightp{ nullptr };
LLJoint* mHipLeftp{ nullptr };
LLJoint* mHipRightp{ nullptr };
LLJoint* mKneeLeftp{ nullptr };
LLJoint* mKneeRightp{ nullptr };
LLJoint* mAnkleLeftp{ nullptr };
LLJoint* mAnkleRightp{ nullptr };
LLJoint* mFootLeftp{ nullptr };
LLJoint* mFootRightp{ nullptr };
LLJoint* mWristLeftp{ nullptr };
LLJoint* mWristRightp{ nullptr };
//--------------------------------------------------------------------
// XML parse tree
//--------------------------------------------------------------------
protected:
static LLAvatarSkeletonInfo* sAvatarSkeletonInfo;
static LLAvatarXmlInfo* sAvatarXmlInfo;
// <FS:Ansariel> Get attachment point name from ID
public:
static std::string getAttachmentPointName(S32 attachmentPointId);
// </FS:Ansariel>
/** Skeleton
** **
*******************************************************************************/
/********************************************************************************
** **
** RENDERING
**/
public:
bool mIsDummy{ false }; // 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:
// <FS:Ansariel> [Legacy Bake]
//virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
virtual void invalidateComposite(LLTexLayerSet* layerset, bool upload_result) = 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:
// <FS:Ansariel> [Legacy Bake]
//void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
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;
// <FS:Ansariel> [Legacy Bake]
//virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, bool upload_bake) = 0;
// </FS:Ansariel> [Legacy Bake]
protected:
LLTexGlobalColor* mTexSkinColor{ nullptr };
LLTexGlobalColor* mTexHairColor{ nullptr };
LLTexGlobalColor* mTexEyeColor{ nullptr };
//--------------------------------------------------------------------
// 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{ nullptr };
/********************************************************************************
** **
** 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{ nullptr }; // Only exists for self
bool mIsLoaded{ false };
bool mIsUsed{ false };
LLAvatarAppearanceDefines::ETextureIndex mTextureIndex{ LLAvatarAppearanceDefines::ETextureIndex::TEX_INVALID };
U32 mMaskTexName{ 0 };
// 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{ 0 };
S32 mNumCollisionVolumes{ 0 };
LLAvatarJointCollisionVolume* mCollisionVolumes{ nullptr };
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
@@ -0,0 +1,415 @@
/**
* @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 = 2048;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 2048;
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);
}
va_end(argp);
}
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
{
auto* tex = getTexture(index);
return tex ? tex->mWearableType : LLWearableType::WT_INVALID;
}
// 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;
}
@@ -0,0 +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
+316
View File
@@ -0,0 +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
+140
View File
@@ -0,0 +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
+390
View File
@@ -0,0 +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
+141
View File
@@ -0,0 +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
+657
View File
@@ -0,0 +1,657 @@
/**
* @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;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false );
return true;
}
/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
{
llassert(wearable);
return new LLDriverParam(*this);
}
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setWeight(F32 weight)
void LLDriverParam::setWeight(F32 weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
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;
}
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight,upload_bake);
// </FS:Ansariel> [Legacy Bake]
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;
}
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight,upload_bake);
// </FS:Ansariel> [Legacy Bake]
continue;
}
}
driven_weight = getDrivenWeight(drivenp, mCurWeight);
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight, upload_bake);
}
}
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 static_cast<S32>(mDriven.size());
}
const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
{
if (0 > index || index >= mDriven.size())
{
return NULL;
}
return mDriven[index].mParam;
}
//-----------------------------------------------------------------------------
// setAnimationTarget()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setAnimationTarget( F32 target_value)
//{
// LLVisualParam::setAnimationTarget(target_value);
void LLDriverParam::setAnimationTarget( F32 target_value, bool upload_bake )
{
LLVisualParam::setAnimationTarget(target_value, upload_bake);
// </FS:Ansariel> [Legacy Bake]
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
// <FS:Ansariel> [Legacy Bake]
//drivenp->mParam->setAnimationTarget(driven_weight);
drivenp->mParam->setAnimationTarget(driven_weight, upload_bake);
// </FS:Ansariel> [Legacy Bake]
}
}
//-----------------------------------------------------------------------------
// stopAnimating()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::stopAnimating()
//{
// LLVisualParam::stopAnimating();
void LLDriverParam::stopAnimating(bool upload_bake)
{
LLVisualParam::stopAnimating(upload_bake);
// </FS:Ansariel> [Legacy Bake]
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)
{
// <FS:Ansariel> [Legacy Bake]
//wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
}
}
}
//-----------------------------------------------------------------------------
// 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;
}
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
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
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake);
}
else
{
// <FS:Ansariel> [Legacy Bake]
//driven->mParam->setWeight( driven_weight);
driven->mParam->setWeight( driven_weight, upload_bake);
}
}
+147
View File
@@ -0,0 +1,147 @@
/**
* @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.
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void stopAnimating();
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void stopAnimating(bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
/*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);
// <FS:Ansariel> [Legacy Bake]
//void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
entry_list_t mDriven;
LLViewerVisualParam* mCurrentDistortionParam{ nullptr };
// Backlink only; don't make this an LLPointer.
LLAvatarAppearance* mAvatarAppearance{ nullptr };
LLWearable* mWearablep{ nullptr };
};
#endif // LL_LLDRIVERPARAM_H
+49
View File
@@ -0,0 +1,49 @@
/**
* @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$
*/
#ifndef LL_LLJOINTPICKNAME_H
#define LL_LLJOINTPICKNAME_H
class LLAvatarJointMesh;
// Sets the OpenGL selection stack name that is pushed and popped
// with this joint state. The default value indicates that no name
// 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
};
typedef std::vector<LLAvatarJointMesh*> avatar_joint_mesh_list_t;
#endif // LL_LLJOINTPICKNAME_H
+212
View File
@@ -0,0 +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 static_cast<U32>(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;
}
+84
View File
@@ -0,0 +1,84 @@
/**
* @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 "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 diff suppressed because it is too large Load Diff
+368
View File
@@ -0,0 +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
+846
View File
@@ -0,0 +1,846 @@
/**
* @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;
size_t 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;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
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";
auto pos = morph_param_name.find(driven_tag);
if (pos != std::string::npos && 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
if (llisnan(mCurWeight))
{
mCurWeight = 0.f;
}
if (llisnan(mLastWeight))
{
mLastWeight = mCurWeight+.001f;
}
// 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;
}
+193
View File
@@ -0,0 +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
@@ -0,0 +1,293 @@
/**
* @file llpolyskeletaldistortion.cpp
* @brief Implementation of LLPolySkeletalDistortion classes
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "llpreprocessor.h"
#include "llerror.h"
#include "llavatarappearance.h"
#include "llavatarjoint.h"
#include "llpolymorph.h"
#include "llwearable.h"
#include "llfasttimer.h"
#include "llpolyskeletaldistortion.h"
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortionInfo()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
{
}
bool LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
{
llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
if (!LLViewerVisualParamInfo::parseXml(node))
return false;
LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
if (NULL == skeletalParam)
{
LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")"
<< LL_ENDL;
return false;
}
for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
{
if (bone->hasName("bone"))
{
std::string name;
LLVector3 scale;
LLVector3 pos;
bool haspos = false;
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if (!bone->getFastAttributeString(name_string, name))
{
LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL;
continue;
}
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
if (!bone->getFastAttributeVector3(scale_string, scale))
{
LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL;
continue;
}
// optional offset deformation (translation)
static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
if (bone->getFastAttributeVector3(offset_string, pos))
{
haspos = true;
}
mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
}
else
{
LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL;
continue;
}
}
return true;
}
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
: LLViewerVisualParam(),
mDefaultVec(),
mJointScales(),
mJointOffsets(),
mAvatar(avatarp)
{
mDefaultVec.splat(0.001f);
}
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther)
: LLViewerVisualParam(pOther),
mDefaultVec(pOther.mDefaultVec),
mJointScales(pOther.mJointScales),
mJointOffsets(pOther.mJointOffsets),
mAvatar(pOther.mAvatar)
{
}
//-----------------------------------------------------------------------------
// ~LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
{
}
bool LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
{
if (info->mID < 0)
{
return false;
}
mInfo = info;
mID = info->mID;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
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 );
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
@@ -0,0 +1,130 @@
/**
* @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);}
// <FS:ND> This functions probably do not want to clear the argument, but the arguments content.
// /*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;};
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return &mDefaultVec; };
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return NULL; };
// </FS:ND>
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
+170
View File
@@ -0,0 +1,170 @@
/**
* @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);
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexParamGlobalColor::onGlobalColorChanged()
//{
// mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
{
mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
// </FS:Ansariel> [Legacy Bake]
}
//-----------------------------------------------------------------------------
// 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;
}
+88
View File
@@ -0,0 +1,88 @@
/**
* @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);
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void onGlobalColorChanged();
/*virtual*/ void onGlobalColorChanged(bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
private:
LLTexGlobalColor* mTexGlobalColor;
};
#endif
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
/**
* @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();
// <FS:Ansariel> [Legacy Bake]
//virtual void midRenderTexLayerSet(bool success) {}
virtual void midRenderTexLayerSet(bool success, LLRenderTarget* bound_target) {}
// </FS:Ansariel> [Legacy Bake]
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
+628
View File
@@ -0,0 +1,628 @@
/**
* @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;
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::setWeight(F32 weight)
void LLTexLayerParamAlpha::setWeight(F32 weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
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.
{
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
// <FS:Ansariel> [Legacy Bake]
mTexLayer->invalidateMorphMasks();
}
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, bool upload_bake)
{
// do not animate dummy parameters
if (mIsDummy)
{
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
return;
}
mTargetWeight = target_value;
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
mIsAnimating = true;
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setAnimationTarget(target_value);
mNext->setAnimationTarget(target_value, upload_bake);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::animate(F32 delta)
void LLTexLayerParamAlpha::animate(F32 delta, bool upload_bake)
{
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->animate(delta);
mNext->animate(delta, upload_bake);
}
}
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[VRED] + weight * end->mV[VRED],
(1.f - weight) * start->mV[VGREEN] + weight * end->mV[VGREEN],
(1.f - weight) * start->mV[VBLUE] + weight * end->mV[VBLUE],
(1.f - weight) * start->mV[VALPHA] + weight * end->mV[VALPHA]);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::setWeight(F32 weight)
void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake)
{
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.
{
// <FS:Ansariel> [Legacy Bake]
//onGlobalColorChanged();
onGlobalColorChanged(upload_bake);
if (mTexLayer)
{
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
}
}
// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL;
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
void LLTexLayerParamColor::setAnimationTarget(F32 target_value, bool upload_bake)
{
// set value first then set interpolating flag to ignore further updates
mTargetWeight = target_value;
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
mIsAnimating = true;
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setAnimationTarget(target_value);
mNext->setAnimationTarget(target_value, upload_bake);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::animate(F32 delta)
void LLTexLayerParamColor::animate(F32 delta, bool upload_bake)
{
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->animate(delta);
mNext->animate(delta, upload_bake);
}
}
//-----------------------------------------------------------------------------
// 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;
}
+224
View File
@@ -0,0 +1,224 @@
/**
* @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 ) {}
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void animate(F32 delta);
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void animate(F32 delta, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
// 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);}
// <FS:ND> This functions probably do not want to clear the argument, but the arguments content.
// /*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;};
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return &mAvgDistortionVec; };
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return NULL; };
// </FS:ND>
// 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 ) {}
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void animate(F32 delta);
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void animate(F32 delta, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
// 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);
// <FS:Ansariel> [Legacy Bake]
//virtual void onGlobalColorChanged() {}
virtual void onGlobalColorChanged(bool upload_bake) {}
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
+181
View File
@@ -0,0 +1,181 @@
/**
* @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;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
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;
}
*/
+112
View File
@@ -0,0 +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
+793
View File
@@ -0,0 +1,793 @@
/**
* @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 (std::set< LLWearableObserver* >::iterator itr = mObservers.begin(); itr != mObservers.end(); ++itr )
(*itr)->onDestroyed( this );
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;
// <FS:Ansariel> [Legacy Bake]
//setVisualParamWeight(id, value);
setVisualParamWeight(id, value, true);
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();
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
void LLWearable::setVisualParamWeight(S32 param_index, F32 value, bool upload_bake)
{
visual_param_index_map_t::iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
LLVisualParam *wearable_param = found->second;
// <FS:Ansariel> [Legacy Bake]
//wearable_param->setWeight(value);
wearable_param->setWeight(value, upload_bake);
}
else
{
LL_WARNS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
}
}
F32 LLWearable::getVisualParamWeight(S32 param_index) const
{
visual_param_index_map_t::const_iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
return found->second->getWeight();
}
else
{
LL_WARNS() << "LLWearable::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);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::animateParams(F32 delta)
void LLWearable::animateParams(F32 delta, bool upload_bake)
{
for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
LLVisualParam *param = (LLVisualParam*)vp_pair.second;
// <FS:Ansariel> [Legacy Bake]
//param->animate(delta);
param->animate(delta, upload_bake);
}
}
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;
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake)
{
U32 param_name[3];
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
{
for( U8 index = 0; index < 3; index++ )
{
// <FS:Ansariel> [Legacy Bake]
//setVisualParamWeight(param_name[index], new_color.mV[index]);
setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
}
}
}
void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
{
if (!avatarp) return;
// Pull params
for( const 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);
// <FS:Ansariel> [Legacy Bake]
//avatarp->setVisualParamWeight( param_id, weight);
avatarp->setVisualParamWeight( param_id, weight, false);
}
}
}
std::string terse_F32_to_string(F32 f)
{
std::string r = llformat("%.2f", f);
auto 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;
}
+164
View File
@@ -0,0 +1,164 @@
/**
* @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 LLMD5; // <FS:Ansariel> [Legacy Bake]
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLLocalTextureObject;
class LLAvatarAppearance;
// Abstract class.
class LLWearable
{
// <FS:ND> Try to see if this fixes the crash in LLPanelEditWearable::isDirty, that is the wearable dets destroyed before the panel
public:
class LLWearableObserver
{
public:
virtual void onDestroyed(LLWearable const * ) = 0;
};
public:
void registerObserver(LLWearableObserver *aObserver){ mObservers.insert(aObserver); }
void unregisterObserver(LLWearableObserver *aObserver){ mObservers.erase(aObserver); }
private:
std::set< LLWearableObserver* > mObservers;
// </FS:ND>
//--------------------------------------------------------------------
// 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);
// <FS:Ansariel> [Legacy Bake]
//void setVisualParamWeight(S32 index, F32 value);
void setVisualParamWeight(S32 index, F32 value, bool upload_bake);
F32 getVisualParamWeight(S32 index) const;
LLVisualParam* getVisualParam(S32 index) const;
void getVisualParams(visual_param_vec_t &list);
// <FS:Ansariel> [Legacy Bake]
//void animateParams(F32 delta);
void animateParams(F32 delta, bool upload_bake);
LLColor4 getClothesColor(S32 te) const;
// <FS:Ansariel> [Legacy Bake]
//void setClothesColor( S32 te, const LLColor4& new_color);
void setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake);
virtual void revertValues();
virtual void saveValues();
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
virtual void setUpdated() const = 0;
// <FS:Ansariel> [Legacy Bake]
// Update the baked texture hash.
virtual void addToBakedTextureHash(LLMD5& hash) 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
+397
View File
@@ -0,0 +1,397 @@
/**
* @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"
#include "llmd5.h" // <FS:Ansariel> [Legacy Bake]
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;
// <FS:Ansariel> Prevent adding null wearables
return;
}
if (canAddWearable(type))
{
// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0)
// Don't add the same wearable twice
U32 idxWearable = 0;
if (!getWearableIndex(wearable, idxWearable))
mWearableDatas[type].push_back(wearable);
else
llassert(false); // pushWearable() on an already added wearable is a bug *somewhere*
// [/RLVa:KB]
// mWearableDatas[type].push_back(wearable); 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)
{
if (type == LLWearableType::WT_PHYSICS) return (getWearableCount(type) < 1); // <FS:Ansariel> Don't add physics layer
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 static_cast<U32>(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);
}
// <FS:Ansariel> [Legacy Bake]
LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
bool generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
{
LLUUID hash_id;
bool hash_computed = false;
LLMD5 hash;
const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index);
for (U8 i=0; i < baked_dict->mWearables.size(); i++)
{
const LLWearableType::EType baked_type = baked_dict->mWearables[i];
const U32 num_wearables = getWearableCount(baked_type);
for (U32 index = 0; index < num_wearables; ++index)
{
const LLWearable* wearable = getWearable(baked_type,index);
if (wearable)
{
wearable->addToBakedTextureHash(hash);
hash_computed = true;
}
}
}
if (hash_computed)
{
hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
if (!generate_valid_hash)
{
invalidateBakedTextureHash(hash);
}
hash.finalize();
hash.raw_digest(hash_id.mData);
}
return hash_id;
}
// </FS:Ansariel> [Legacy Bake]
+113
View File
@@ -0,0 +1,113 @@
/**
* @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);
// <FS:Ansariel> [Legacy Bake]
//--------------------------------------------------------------------
// Server Communication
//--------------------------------------------------------------------
public:
LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
bool generate_valid_hash = true);
protected:
virtual void invalidateBakedTextureHash(LLMD5& hash) const {}
// </FS:Ansariel> [Legacy Bake]
//--------------------------------------------------------------------
// 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
+137
View File
@@ -0,0 +1,137 @@
/**
* @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));
// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6)
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, true, false));
// [/SL:KB]
// 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);
}
+124
View File
@@ -0,0 +1,124 @@
/**
* @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() {}
// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
protected:
// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
// [/RLVa:KB]
};
LLWearableDictionary mDictionary;
};
#endif // LL_LLWEARABLETYPE_H