summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/cmake/00-Common.cmake6
-rwxr-xr-xindra/llappearance/llavatarappearance.cpp176
-rwxr-xr-xindra/llappearance/llavatarappearance.h18
-rw-r--r--indra/llappearance/llavatarjoint.cpp13
-rw-r--r--indra/llappearance/llavatarjointmesh.cpp96
-rw-r--r--indra/llappearance/llpolymorph.cpp1
-rw-r--r--indra/llappearance/llpolyskeletaldistortion.cpp1
-rwxr-xr-xindra/llcharacter/CMakeLists.txt16
-rwxr-xr-xindra/llcharacter/llbvhloader.cpp461
-rwxr-xr-xindra/llcharacter/llbvhloader.h14
-rwxr-xr-xindra/llcharacter/lleditingmotion.cpp6
-rwxr-xr-xindra/llcharacter/lljoint.cpp97
-rwxr-xr-xindra/llcharacter/lljoint.h63
-rwxr-xr-xindra/llcharacter/llkeyframemotion.cpp107
-rwxr-xr-xindra/llcharacter/llkeyframemotion.h1
-rwxr-xr-xindra/llcharacter/llkeyframestandmotion.cpp4
-rwxr-xr-xindra/llcharacter/llmotion.cpp14
-rwxr-xr-xindra/llcharacter/llmotion.h2
-rwxr-xr-xindra/llcharacter/llmotioncontroller.cpp12
-rwxr-xr-xindra/llcharacter/llmotioncontroller.h2
-rwxr-xr-xindra/llcharacter/llpose.cpp3
-rwxr-xr-xindra/llcharacter/llvisualparam.h1
-rwxr-xr-xindra/llcharacter/tests/lljoint_test.cpp2
-rwxr-xr-xindra/llcommon/CMakeLists.txt4
-rw-r--r--indra/llcommon/StackWalker.cpp1388
-rw-r--r--indra/llcommon/StackWalker.h226
-rw-r--r--indra/llcommon/llcallstack.cpp186
-rw-r--r--indra/llcommon/llcallstack.h80
-rwxr-xr-xindra/llcommon/llstl.h1
-rwxr-xr-xindra/llmath/llvolume.cpp1
-rwxr-xr-xindra/llmath/llvolume.h4
-rw-r--r--indra/llprimitive/lldaeloader.cpp109
-rw-r--r--indra/llprimitive/lldaeloader.h14
-rwxr-xr-xindra/llprimitive/llmodel.cpp1
-rwxr-xr-xindra/llprimitive/llmodel.h2
-rw-r--r--indra/llprimitive/llmodelloader.cpp277
-rw-r--r--indra/llprimitive/llmodelloader.h34
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rwxr-xr-xindra/newview/app_settings/anim.ini85
-rwxr-xr-xindra/newview/app_settings/settings.xml22
-rwxr-xr-xindra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl13
-rwxr-xr-xindra/newview/character/avatar_lad.xml817
-rwxr-xr-xindra/newview/character/avatar_skeleton.xml299
-rwxr-xr-xindra/newview/llagent.cpp6
-rwxr-xr-xindra/newview/llagentcamera.cpp3
-rwxr-xr-xindra/newview/llappviewer.cpp4
-rwxr-xr-xindra/newview/lldrawpoolavatar.cpp122
-rwxr-xr-xindra/newview/llfloaterbvhpreview.cpp20
-rwxr-xr-xindra/newview/llfloaterbvhpreview.h4
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp139
-rwxr-xr-xindra/newview/llfloatermodelpreview.h8
-rwxr-xr-xindra/newview/llfloaterpreference.cpp19
-rwxr-xr-xindra/newview/llfloaterpreference.h2
-rwxr-xr-xindra/newview/llpreviewanim.cpp1
-rw-r--r--indra/newview/llskinningutil.cpp357
-rw-r--r--indra/newview/llskinningutil.h50
-rwxr-xr-xindra/newview/llspatialpartition.cpp11
-rwxr-xr-xindra/newview/llstartup.cpp5
-rwxr-xr-xindra/newview/lltoolbarview.cpp6
-rwxr-xr-xindra/newview/llviewercontrol.cpp16
-rwxr-xr-xindra/newview/llviewerjoint.cpp7
-rwxr-xr-xindra/newview/llviewerjoint.h3
-rwxr-xr-xindra/newview/llviewerjointattachment.cpp1
-rwxr-xr-xindra/newview/llviewerjointmesh.cpp2
-rwxr-xr-xindra/newview/llviewermenu.cpp17
-rwxr-xr-xindra/newview/llviewermenu.h4
-rwxr-xr-xindra/newview/llviewershadermgr.cpp8
-rwxr-xr-xindra/newview/llvoavatar.cpp341
-rwxr-xr-xindra/newview/llvoavatar.h8
-rwxr-xr-xindra/newview/llvoavatarself.cpp18
-rwxr-xr-xindra/newview/llvoavatarself.h11
-rwxr-xr-xindra/newview/llvovolume.cpp61
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_preferences.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_attachment_other.xml9
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_attachment_self.xml7
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_avatar_other.xml9
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_avatar_self.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml10
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml15
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_notification.xml1
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_graphics1.xml19
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_privacy.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_sound.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml18
85 files changed, 4751 insertions, 1292 deletions
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 86fc2dfff5..bde1eb453e 100755
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -136,12 +136,14 @@ if (LINUX)
# Hacks to work around gcc 4.1 TC build pool machines which can't process pragma warning disables
# This is pure rubbish; I wish there was another way.
#
+ set(CMAKE_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-unused-local-typedefs -Wno-maybe-uninitialized")
+
if(${CXX_VERSION_NUMBER} LESS 420)
- set(CMAKE_CXX_FLAGS "-Wno-deprecated -Wno-uninitialized -Wno-unused-variable -Wno-unused-function ${CMAKE_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS "-Wno-deprecated -Wno-uninitialized ${CMAKE_CXX_FLAGS}")
endif (${CXX_VERSION_NUMBER} LESS 420)
if(${CXX_VERSION_NUMBER} GREATER 459)
- set(CMAKE_CXX_FLAGS "-Wno-deprecated -Wno-unused-but-set-variable -Wno-unused-variable ${CMAKE_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS "-Wno-deprecated -Wno-unused-but-set-variable ${CMAKE_CXX_FLAGS}")
endif (${CXX_VERSION_NUMBER} GREATER 459)
# gcc 4.3 and above don't like the LL boost and also
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index d1eb389013..9b9657b4c8 100755
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -44,6 +44,7 @@
#include "lltexglobalcolor.h"
#include "llwearabledata.h"
#include "boost/bind.hpp"
+#include "boost/tokenizer.hpp"
#if LL_MSVC
@@ -87,8 +88,11 @@ public:
private:
std::string mName;
+ std::string mSupport;
+ std::string mAliases;
BOOL mIsJoint;
LLVector3 mPos;
+ LLVector3 mEnd;
LLVector3 mRot;
LLVector3 mScale;
LLVector3 mPivot;
@@ -118,6 +122,7 @@ public:
private:
S32 mNumBones;
S32 mNumCollisionVolumes;
+ LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
bone_info_list_t mBoneInfoList;
};
@@ -323,36 +328,49 @@ LLAvatarAppearance::~LLAvatarAppearance()
//static
void LLAvatarAppearance::initClass()
{
- std::string xmlFile;
+ initClass("","");
+}
- xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
- BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
+//static
+void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg)
+{
+ std::string avatar_file_name;
+
+ if (!avatar_file_name_arg.empty())
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg);
+ }
+ else
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml");
+ }
+ BOOL success = sXMLTree.parseFile( avatar_file_name, FALSE );
if (!success)
{
- LL_ERRS() << "Problem reading avatar configuration file:" << xmlFile << LL_ENDL;
+ LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL;
}
// now sanity check xml file
LLXmlTreeNode* root = sXMLTree.getRoot();
if (!root)
{
- LL_ERRS() << "No root node found in avatar configuration file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL;
return;
}
//-------------------------------------------------------------------------
- // <linden_avatar version="1.0"> (root)
+ // <linden_avatar version="2.0"> (root)
//-------------------------------------------------------------------------
if( !root->hasName( "linden_avatar" ) )
{
- LL_ERRS() << "Invalid avatar file header: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL;
}
std::string version;
static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
{
- LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL;
}
S32 wearable_def_version = 1;
@@ -365,16 +383,19 @@ void LLAvatarAppearance::initClass()
LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
if (!skeleton_node)
{
- LL_ERRS() << "No skeleton in avatar configuration file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL;
return;
}
-
- std::string skeleton_file_name;
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
- {
- LL_ERRS() << "No file name in skeleton node in avatar config file: " << xmlFile << LL_ENDL;
- }
+
+ std::string skeleton_file_name = skeleton_file_name_arg;
+ if (skeleton_file_name.empty())
+ {
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+ {
+ LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL;
+ }
+ }
std::string skeleton_path;
skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
@@ -536,7 +557,7 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename)
std::string version;
static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
{
LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL;
return FALSE;
@@ -552,6 +573,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
{
LLJoint* joint = NULL;
+ LL_DEBUGS("BVH") << "bone info: name " << info->mName
+ << " isJoint " << info->mIsJoint
+ << " volume_num " << volume_num
+ << " joint_num " << joint_num
+ << LL_ENDL;
+
if (info->mIsJoint)
{
joint = getCharacterJoint(joint_num);
@@ -579,10 +606,13 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
parent->addChild( joint );
}
+ // SL-315
joint->setPosition(info->mPos);
joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
info->mRot.mV[VZ], LLQuaternion::XYZ));
joint->setScale(info->mScale);
+ joint->setSupport(info->mSupport);
+ joint->setEnd(info->mEnd);
if (info->mIsJoint)
{
@@ -613,12 +643,11 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num )
{
- clearSkeleton();
-
- for(S32 joint_num = 0; joint_num < (S32)num; joint_num++)
- {
- mSkeleton.push_back(createAvatarJoint(joint_num));
- }
+ if (mSkeleton.size() != num)
+ {
+ clearSkeleton();
+ mSkeleton = avatar_joint_list_t(num,NULL);
+ }
return TRUE;
}
@@ -629,6 +658,7 @@ BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num )
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
{
+ LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
//-------------------------------------------------------------------------
// allocate joints
//-------------------------------------------------------------------------
@@ -655,8 +685,8 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
{
- LLAvatarBoneInfo *info = *iter;
- if (!setupBone(info, NULL, current_volume_num, current_joint_num))
+ LLAvatarBoneInfo *bone_info = *iter;
+ if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num))
{
LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL;
return FALSE;
@@ -820,6 +850,7 @@ void LLAvatarAppearance::buildCharacter()
//-------------------------------------------------------------------------
// initialize the pelvis
//-------------------------------------------------------------------------
+ // SL-315
mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
mIsBuilt = TRUE;
@@ -1240,6 +1271,11 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
{
return NULL;
}
+ if (!mSkeleton[num])
+ {
+ mSkeleton[num] = createAvatarJoint();
+ mSkeleton[num]->setJointNum(num);
+ }
return mSkeleton[num];
}
@@ -1476,16 +1512,19 @@ LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_in
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
{
- delete_and_clear_array(mCollisionVolumes);
- mNumCollisionVolumes = 0;
-
- mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
- if (!mCollisionVolumes)
- {
- return FALSE;
- }
-
- mNumCollisionVolumes = num;
+ if (mNumCollisionVolumes !=num)
+ {
+ delete_and_clear_array(mCollisionVolumes);
+ mNumCollisionVolumes = 0;
+
+ mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
+ if (!mCollisionVolumes)
+ {
+ return FALSE;
+ }
+
+ mNumCollisionVolumes = num;
+ }
return TRUE;
}
@@ -1503,6 +1542,9 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
LL_WARNS() << "Bone without name" << LL_ENDL;
return FALSE;
}
+
+ static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases");
+ node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required.
}
else if (node->hasName("collision_volume"))
{
@@ -1540,6 +1582,20 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
return FALSE;
}
+ static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end");
+ if (!node->getFastAttributeVector3(end_string, mEnd))
+ {
+ LL_WARNS() << "Bone without end " << mName << LL_ENDL;
+ mEnd = LLVector3(0.0f, 0.0f, 0.0f);
+ }
+
+ static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support");
+ if (!node->getFastAttributeString(support_string,mSupport))
+ {
+ LL_WARNS() << "Bone without support " << mName << LL_ENDL;
+ mSupport = "base";
+ }
+
if (mIsJoint)
{
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
@@ -1595,6 +1651,54 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
return TRUE;
}
+//Make aliases for joint and push to map.
+void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
+{
+ if (! bone_info->mIsJoint )
+ {
+ return;
+ }
+
+ std::string bone_name = bone_info->mName;
+ mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias.
+
+ std::string aliases = bone_info->mAliases;
+
+ boost::char_separator<char> sep(" ");
+ boost::tokenizer<boost::char_separator<char> > tok(aliases, sep);
+ for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i)
+ {
+ if ( mJointAliasMap.find(*i) != mJointAliasMap.end() )
+ {
+ LL_WARNS() << "avatar skeleton: Joint alias \"" << *i << "\" remapped from " << mJointAliasMap[*i] << " to " << bone_name << LL_ENDL;
+ }
+ mJointAliasMap[*i] = bone_name;
+ }
+
+ LLAvatarBoneInfo::child_list_t::const_iterator iter;
+ for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter)
+ {
+ makeJointAliases( *iter );
+ }
+}
+
+const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases ()
+{
+ LLAvatarAppearance::joint_alias_map_t alias_map;
+ if (mJointAliasMap.empty())
+ {
+
+ LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
+ for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter)
+ {
+ //LLAvatarBoneInfo *bone_info = *iter;
+ makeJointAliases( *iter );
+ }
+ }
+
+ return mJointAliasMap;
+}
+
//-----------------------------------------------------------------------------
// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index a0ef49b7cb..3865da7098 100755
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -66,7 +66,8 @@ public:
LLAvatarAppearance(LLWearableData* wearable_data);
virtual ~LLAvatarAppearance();
- static void initClass(); // initializes static members
+ 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.
virtual BOOL loadSkeletonNode();
@@ -124,8 +125,11 @@ public:
protected:
virtual LLAvatarJoint* createAvatarJoint() = 0;
- virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 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; }
@@ -138,6 +142,12 @@ public:
void computeBodySize();
+public:
+ typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
+ const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
+ typedef std::map<std::string, std::string> joint_alias_map_t;
+ const joint_alias_map_t& getJointAliases();
+
protected:
static BOOL parseSkeletonFile(const std::string& filename);
@@ -147,12 +157,12 @@ protected:
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
BOOL allocateCharacterJoints(U32 num);
BOOL buildSkeleton(const LLAvatarSkeletonInfo *info);
-protected:
+
void clearSkeleton();
BOOL mIsBuilt; // state of deferred character building
- typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
avatar_joint_list_t mSkeleton;
LLPosOverrideMap mPelvisFixups;
+ joint_alias_map_t mJointAliasMap;
//--------------------------------------------------------------------
// Pelvis height adjustment members.
diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp
index 2ee3c65a01..29642be099 100644
--- a/indra/llappearance/llavatarjoint.cpp
+++ b/indra/llappearance/llavatarjoint.cpp
@@ -52,19 +52,18 @@ LLAvatarJoint::LLAvatarJoint() :
init();
}
-LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
- LLJoint(name, parent)
+LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
+ LLJoint(joint_num)
{
- init();
+ init();
}
-
-LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
- LLJoint(joint_num)
+
+LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
+ LLJoint(name, parent)
{
init();
}
-
void LLAvatarJoint::init()
{
mValid = FALSE;
diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp
index 520ad775db..7ca0928171 100644
--- a/indra/llappearance/llavatarjointmesh.cpp
+++ b/indra/llappearance/llavatarjointmesh.cpp
@@ -33,22 +33,7 @@
#include "llavatarjointmesh.h"
#include "llavatarappearance.h"
-//#include "llapr.h"
-//#include "llbox.h"
-//#include "lldrawable.h"
-//#include "lldrawpoolavatar.h"
-//#include "lldrawpoolbump.h"
-//#include "lldynamictexture.h"
-//#include "llface.h"
-//#include "llgldbg.h"
-//#include "llglheaders.h"
#include "lltexlayer.h"
-//#include "llviewercamera.h"
-//#include "llviewercontrol.h"
-//#include "llviewertexturelist.h"
-//#include "llsky.h"
-//#include "pipeline.h"
-//#include "llviewershadermgr.h"
#include "llmath.h"
#include "v4math.h"
#include "m3math.h"
@@ -56,6 +41,41 @@
#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
@@ -92,18 +112,12 @@ BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
}
// compute the inverse root skin matrix
- mRootToJointSkinOffset.clearVec();
-
- LLVector3 rootSkinOffset;
- while (joint)
- {
- rootSkinOffset += joint->getSkinOffset();
- joint = (LLAvatarJoint*)joint->getParent();
- }
+ mRootToJointSkinOffset = totalSkinOffset(joint);
+ mRootToJointSkinOffset = -mRootToJointSkinOffset;
- mRootToJointSkinOffset = -rootSkinOffset;
- mRootToParentJointSkinOffset = mRootToJointSkinOffset;
- mRootToParentJointSkinOffset += mJoint->getSkinOffset();
+ //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
+ mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(joint));
+ mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
return TRUE;
}
@@ -289,6 +303,7 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
}
// acquire the transform from the mesh object
+ // SL-315
setPosition( mMesh->getPosition() );
setRotation( mMesh->getRotation() );
setScale( mMesh->getScale() );
@@ -314,9 +329,9 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
if (!mMesh->isLOD())
{
setupJoint((LLAvatarJoint*)getRoot());
+ LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
- LL_DEBUGS() << "joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
//-----------------------------------------------------------------------------
@@ -324,9 +339,6 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
{
- LL_DEBUGS() << "Mesh: " << getName() << LL_ENDL;
-
- S32 joint_count = 0;
U32 sj;
for (sj=0; sj<mNumSkinJoints; sj++)
@@ -339,22 +351,30 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
}
// 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?
- if(mMesh->mJointRenderData.size() && mMesh->mJointRenderData[mMesh->mJointRenderData.size() - 1]->mWorldMatrix == &current_joint->getParent()->getWorldMatrix())
+
+ 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;
- mMesh->mJointRenderData.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
- LL_DEBUGS() << "joint " << joint_count++ << js.mJoint->getName() << LL_ENDL;
+ jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
+ LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
}
- // otherwise add our parent and ourselves
+ // otherwise add our ancestor and ourselves
else
{
- mMesh->mJointRenderData.push_back(new LLJointRenderData(&current_joint->getParent()->getWorldMatrix(), NULL));
- LL_DEBUGS() << "joint " << joint_count++ << current_joint->getParent()->getName() << LL_ENDL;
- mMesh->mJointRenderData.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
- LL_DEBUGS() << "joint " << joint_count++ << current_joint->getName() << LL_ENDL;
+ 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;
}
}
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index e3992a080e..80e81936fb 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -647,6 +647,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
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);
}
}
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index fbc312c426..722965af28 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -225,6 +225,7 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
LLVector3 newPosition = joint->getPosition();
LLVector3 positionDelta = iter->second;
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+ // SL-315
joint->setPosition(newPosition);
}
diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt
index 2573417b26..a17a5b0aa6 100755
--- a/indra/llcharacter/CMakeLists.txt
+++ b/indra/llcharacter/CMakeLists.txt
@@ -91,12 +91,12 @@ target_link_libraries(
# Add tests
-if (LL_TESTS)
- include(LLAddBuildTest)
- # UNIT TESTS
- SET(llcharacter_TEST_SOURCE_FILES
- lljoint.cpp
- )
- LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}")
-endif (LL_TESTS)
+#if (LL_TESTS)
+# include(LLAddBuildTest)
+# # UNIT TESTS
+# SET(llcharacter_TEST_SOURCE_FILES
+# lljoint.cpp
+# )
+# LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}")
+#endif (LL_TESTS)
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index 0d558aeaa2..e906d81ce1 100755
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -11,7 +11,7 @@
* 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,
+ * This library is distributed in the hope that it will be useful,7
* 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.
@@ -29,6 +29,7 @@
#include "llbvhloader.h"
#include <boost/tokenizer.hpp>
+#include <boost/lexical_cast.hpp>
#include "lldatapacker.h"
#include "lldir.h"
@@ -36,6 +37,7 @@
#include "llquantize.h"
#include "llstl.h"
#include "llapr.h"
+#include "llsdserialize.h"
using namespace std;
@@ -121,52 +123,16 @@ LLQuaternion::Order bvhStringToOrder( char *str )
// LLBVHLoader()
//-----------------------------------------------------------------------------
-/*
- LLBVHLoader::LLBVHLoader(const char* buffer)
-{
- reset();
-
- mStatus = loadTranslationTable("anim.ini");
-
- if (mStatus == LLBVHLoader::ST_NO_XLT_FILE)
- {
- LL_WARNS() << "NOTE: No translation table found." << LL_ENDL;
- return;
- }
- else
- {
- if (mStatus != LLBVHLoader::ST_OK)
- {
- LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
- return;
- }
- }
-
- char error_text[128]; // Flawfinder: ignore
- S32 error_line;
- mStatus = loadBVHFile(buffer, error_text, error_line);
- if (mStatus != LLBVHLoader::ST_OK)
- {
- LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
- return;
- }
-
- applyTranslations();
- optimize();
-
- mInitialized = TRUE;
-}
-*/
-LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine)
+LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map )
{
reset();
errorLine = 0;
mStatus = loadTranslationTable("anim.ini");
loadStatus = mStatus;
- LL_INFOS()<<"Load Status 00 : "<< loadStatus << LL_ENDL;
+ LL_INFOS("BVH") << "Load Status 00 : " << loadStatus << LL_ENDL;
if (mStatus == E_ST_NO_XLT_FILE)
{
- //LL_WARNS() << "NOTE: No translation table found." << LL_ENDL;
+ LL_WARNS("BVH") << "NOTE: No translation table found." << LL_ENDL;
loadStatus = mStatus;
return;
}
@@ -174,28 +140,43 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error
{
if (mStatus != E_ST_OK)
{
- //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
+ LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
errorLine = getLineNumber();
loadStatus = mStatus;
return;
}
}
+
+ // Recognize all names we've been told are legal.
+ std::map<std::string, std::string>::iterator iter;
+ for (iter = joint_alias_map.begin(); iter != joint_alias_map.end(); iter++)
+ {
+ makeTranslation( iter->first , iter->second );
+ }
char error_text[128]; /* Flawfinder: ignore */
S32 error_line;
- mStatus = loadBVHFile(buffer, error_text, error_line);
+ mStatus = loadBVHFile(buffer, error_text, error_line); //Reads all joints in BVH file.
+
+ LL_DEBUGS("BVH") << "============================================================" << LL_ENDL;
+ LL_DEBUGS("BVH") << "Raw data from file" << LL_ENDL;
+ dumpBVHInfo();
if (mStatus != E_ST_OK)
{
- //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
+ LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
loadStatus = mStatus;
errorLine = getLineNumber();
return;
}
- applyTranslations();
+ applyTranslations(); //Maps between joints found in file and the aliased names.
optimize();
+ LL_DEBUGS("BVH") << "============================================================" << LL_ENDL;
+ LL_DEBUGS("BVH") << "After translations and optimize" << LL_ENDL;
+ dumpBVHInfo();
+
mInitialized = TRUE;
}
@@ -211,10 +192,6 @@ LLBVHLoader::~LLBVHLoader()
//------------------------------------------------------------------------
ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
{
- mLineNumber = 0;
- mTranslations.clear();
- mConstraints.clear();
-
//--------------------------------------------------------------------
// open file
//--------------------------------------------------------------------
@@ -226,7 +203,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
if (!fp)
return E_ST_NO_XLT_FILE;
- LL_INFOS() << "NOTE: Loading translation table: " << fileName << LL_ENDL;
+ LL_INFOS("BVH") << "NOTE: Loading translation table: " << fileName << LL_ENDL;
//--------------------------------------------------------------------
// register file to be closed on function exit
@@ -244,7 +221,6 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
// load data one line at a time
//--------------------------------------------------------------------
BOOL loadingGlobals = FALSE;
- Translation *trans = NULL;
while ( getLine(fp) )
{
//----------------------------------------------------------------
@@ -271,13 +247,6 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
loadingGlobals = TRUE;
continue;
}
- else
- {
- loadingGlobals = FALSE;
- Translation &newTrans = mTranslations[ name ];
- trans = &newTrans;
- continue;
- }
}
//----------------------------------------------------------------
@@ -499,174 +468,102 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
mConstraints.push_back(constraint);
continue;
}
+ }
+ infile.close() ;
+ return E_ST_OK;
+}
+void LLBVHLoader::makeTranslation(std::string alias_name, std::string joint_name)
+{
+ //Translation &newTrans = (foomap.insert(value_type(alias_name, Translation()))).first();
+ Translation &newTrans = mTranslations[ alias_name ]; //Uses []'s implicit call to ctor.
+
+ newTrans.mOutName = joint_name;
+ LLMatrix3 fm;
+ LLVector3 vect1(0, 1, 0);
+ LLVector3 vect2(0, 0, 1);
+ LLVector3 vect3(1, 0, 0);
+ fm.setRows(vect1, vect2, vect3);
+
+ newTrans.mFrameMatrix = fm;
+
+if (joint_name == "mPelvis")
+ {
+ newTrans.mRelativePositionKey = TRUE;
+ newTrans.mRelativeRotationKey = TRUE;
+ }
- //----------------------------------------------------------------
- // at this point there must be a valid trans pointer
- //----------------------------------------------------------------
- if ( ! trans )
- return E_ST_NO_XLT_NAME;
-
- //----------------------------------------------------------------
- // check for ignore flag
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "ignore")==0 )
- {
- char trueFalse[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %127s", trueFalse) != 1 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_IGNORE;
-
- trans->mIgnore = (LLStringUtil::compareInsensitive(trueFalse, "true")==0);
- continue;
- }
-
- //----------------------------------------------------------------
- // check for relativepos flag
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "relativepos")==0 )
- {
- F32 x, y, z;
- char relpos[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %f %f %f", &x, &y, &z) == 3 )
- {
- trans->mRelativePosition.setVec( x, y, z );
- }
- else if ( sscanf(mLine, " %*s = %127s", relpos) == 1 ) /* Flawfinder: ignore */
- {
- if ( LLStringUtil::compareInsensitive(relpos, "firstkey")==0 )
- {
- trans->mRelativePositionKey = TRUE;
- }
- else
- {
- return E_ST_NO_XLT_RELATIVE;
- }
- }
- else
- {
- return E_ST_NO_XLT_RELATIVE;
- }
-
- continue;
- }
-
- //----------------------------------------------------------------
- // check for relativerot flag
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "relativerot")==0 )
- {
- //F32 x, y, z;
- char relpos[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %127s", relpos) == 1 ) /* Flawfinder: ignore */
- {
- if ( LLStringUtil::compareInsensitive(relpos, "firstkey")==0 )
- {
- trans->mRelativeRotationKey = TRUE;
- }
- else
- {
- return E_ST_NO_XLT_RELATIVE;
- }
- }
- else
- {
- return E_ST_NO_XLT_RELATIVE;
- }
-
- continue;
- }
-
- //----------------------------------------------------------------
- // check for outname value
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "outname")==0 )
- {
- char outName[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %127s", outName) != 1 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_OUTNAME;
-
- trans->mOutName = outName;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for frame matrix value
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "frame")==0 )
- {
- LLMatrix3 fm;
- if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
- &fm.mMatrix[0][0], &fm.mMatrix[0][1], &fm.mMatrix[0][2],
- &fm.mMatrix[1][0], &fm.mMatrix[1][1], &fm.mMatrix[1][2],
- &fm.mMatrix[2][0], &fm.mMatrix[2][1], &fm.mMatrix[2][2] ) != 9 )
- return E_ST_NO_XLT_MATRIX;
-
- trans->mFrameMatrix = fm;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for offset matrix value
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "offset")==0 )
- {
- LLMatrix3 om;
- if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
- &om.mMatrix[0][0], &om.mMatrix[0][1], &om.mMatrix[0][2],
- &om.mMatrix[1][0], &om.mMatrix[1][1], &om.mMatrix[1][2],
- &om.mMatrix[2][0], &om.mMatrix[2][1], &om.mMatrix[2][2] ) != 9 )
- return E_ST_NO_XLT_MATRIX;
-
- trans->mOffsetMatrix = om;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for mergeparent value
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "mergeparent")==0 )
- {
- char mergeParentName[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %127s", mergeParentName) != 1 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_MERGEPARENT;
-
- trans->mMergeParentName = mergeParentName;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for mergechild value
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "mergechild")==0 )
- {
- char mergeChildName[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %127s", mergeChildName) != 1 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_MERGECHILD;
+}
- trans->mMergeChildName = mergeChildName;
- continue;
- }
+ELoadStatus LLBVHLoader::loadAliases(const char * filename)
+{
+ LLSD aliases_sd;
+
+ std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,filename);
+
+ llifstream input_stream;
+ input_stream.open(fullpath.c_str(), std::ios::in | std::ios::binary);
+
+ if(input_stream.is_open())
+ {
+ if ( LLSDSerialize::fromXML(aliases_sd, input_stream) )
+ {
+ for(LLSD::map_iterator alias_iter = aliases_sd.beginMap();
+ alias_iter != aliases_sd.endMap();
+ ++alias_iter)
+ {
+ LLSD::String alias_name = alias_iter->first;
+ LLSD::String joint_name = alias_iter->second;
+ makeTranslation(alias_name, joint_name);
+
+ }
+ }
+ else
+ {
+ return E_ST_NO_XLT_HEADER;
+ }
+ input_stream.close();
+ }
+ else
+ {
+ LL_WARNS("BVH") << "Can't open joint alias file " << fullpath << LL_ENDL;
+ return E_ST_NO_XLT_FILE;
+ }
+
+ return E_ST_OK;
+}
- //----------------------------------------------------------------
- // check for per-joint priority
- //----------------------------------------------------------------
- if ( LLStringUtil::compareInsensitive(token, "priority")==0 )
+void LLBVHLoader::dumpBVHInfo()
+{
+ for (U32 j=0; j<mJoints.size(); j++)
+ {
+ Joint *joint = mJoints[j];
+ LL_DEBUGS("BVH") << joint->mName << LL_ENDL;
+ for (S32 i=0; i<mNumFrames; i++)
{
- S32 priority;
- if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
- return E_ST_NO_XLT_PRIORITY;
-
- trans->mPriorityModifier = priority;
- continue;
+ if (i<joint->mKeys.size()) // Check this in case file load failed.
+ {
+ Key &prevkey = joint->mKeys[llmax(i-1,0)];
+ Key &key = joint->mKeys[i];
+ if ((i==0) ||
+ (key.mPos[0] != prevkey.mPos[0]) ||
+ (key.mPos[1] != prevkey.mPos[1]) ||
+ (key.mPos[2] != prevkey.mPos[2]) ||
+ (key.mRot[0] != prevkey.mRot[0]) ||
+ (key.mRot[1] != prevkey.mRot[1]) ||
+ (key.mRot[2] != prevkey.mRot[2])
+ )
+ {
+ LL_DEBUGS("BVH") << "FRAME " << i
+ << " POS " << key.mPos[0] << "," << key.mPos[1] << "," << key.mPos[2]
+ << " ROT " << key.mRot[0] << "," << key.mRot[1] << "," << key.mRot[2] << LL_ENDL;
+ }
+ }
}
-
}
- infile.close() ;
- return E_ST_OK;
}
-
//------------------------------------------------------------------------
// LLBVHLoader::loadBVHFile()
//------------------------------------------------------------------------
@@ -746,6 +643,7 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
{
iter++; // {
iter++; // OFFSET
+ iter++; // }
S32 depth = 0;
for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
{
@@ -777,12 +675,19 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
//---------------------------------------------------------------
// we require the root joint be "hip" - DEV-26188
//---------------------------------------------------------------
- const char* FORCED_ROOT_NAME = "hip";
- if ( (mJoints.size() == 0 ) && ( !strstr(jointName, FORCED_ROOT_NAME) ) )
- {
- strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
- return E_ST_BAD_ROOT;
- }
+ if (mJoints.size() == 0 )
+ {
+ //The root joint of the BVH file must be hip (mPelvis) or an alias of mPelvis.
+ const char* FORCED_ROOT_NAME = "hip";
+
+ TranslationMap::iterator hip_joint = mTranslations.find( FORCED_ROOT_NAME );
+ TranslationMap::iterator root_joint = mTranslations.find( jointName );
+ if ( hip_joint == mTranslations.end() || root_joint == mTranslations.end() || root_joint->second.mOutName != hip_joint->second.mOutName )
+ {
+ strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
+ return E_ST_BAD_ROOT;
+ }
+ }
//----------------------------------------------------------------
@@ -790,11 +695,14 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
//----------------------------------------------------------------
mJoints.push_back( new Joint( jointName ) );
Joint *joint = mJoints.back();
+ LL_DEBUGS("BVH") << "Created joint " << jointName << LL_ENDL;
+ LL_DEBUGS("BVH") << "- index " << mJoints.size()-1 << LL_ENDL;
S32 depth = 1;
for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
{
Joint *pjoint = mJoints[parent_joints[j]];
+ LL_DEBUGS("BVH") << "- ancestor " << pjoint->mName << LL_ENDL;
if (depth > pjoint->mChildTreeMaxDepth)
{
pjoint->mChildTreeMaxDepth = depth;
@@ -863,6 +771,21 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
return E_ST_NO_CHANNELS;
}
+ // Animating position (via mNumChannels = 6) is only supported for mPelvis.
+ int res = sscanf(line.c_str(), " CHANNELS %d", &joint->mNumChannels);
+ if ( res != 1 )
+ {
+ // Assume default if not otherwise specified.
+ if (mJoints.size()==1)
+ {
+ joint->mNumChannels = 6;
+ }
+ else
+ {
+ joint->mNumChannels = 3;
+ }
+ }
+
//----------------------------------------------------------------
// get rotation order
//----------------------------------------------------------------
@@ -961,57 +884,49 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &
line = (*(iter++));
err_line++;
- // read and store values
- const char *p = line.c_str();
+ // Split line into a collection of floats.
+ std::deque<F32> floats;
+ boost::char_separator<char> whitespace_sep("\t ");
+ tokenizer float_tokens(line, whitespace_sep);
+ tokenizer::iterator float_token_iter = float_tokens.begin();
+ while (float_token_iter != float_tokens.end())
+ {
+ try
+ {
+ F32 val = boost::lexical_cast<float>(*float_token_iter);
+ floats.push_back(val);
+ }
+ catch (const boost::bad_lexical_cast&)
+ {
+ strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
+ return E_ST_NO_POS;
+ }
+ float_token_iter++;
+ }
+ LL_DEBUGS("BVH") << "Got " << floats.size() << " floats " << LL_ENDL;
for (U32 j=0; j<mJoints.size(); j++)
{
Joint *joint = mJoints[j];
joint->mKeys.push_back( Key() );
Key &key = joint->mKeys.back();
- // get 3 pos values for root joint only
- if (j==0)
+ if (floats.size() < joint->mNumChannels)
{
- if ( sscanf(p, "%f %f %f", key.mPos, key.mPos+1, key.mPos+2) != 3 )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_POS;
- }
+ strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
+ return E_ST_NO_POS;
}
- // skip to next 3 values in the line
- p = find_next_whitespace(p);
- if (!p)
+ // assume either numChannels == 6, in which case we have pos + rot,
+ // or numChannels == 3, in which case we have only rot.
+ if (joint->mNumChannels == 6)
{
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_ROT;
+ key.mPos[0] = floats.front(); floats.pop_front();
+ key.mPos[1] = floats.front(); floats.pop_front();
+ key.mPos[2] = floats.front(); floats.pop_front();
}
- p = find_next_whitespace(++p);
- if (!p)
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_ROT;
- }
- p = find_next_whitespace(++p);
- if (!p)
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_ROT;
- }
-
- // get 3 rot values for joint
- F32 rot[3];
- if ( sscanf(p, " %f %f %f", rot, rot+1, rot+2) != 3 )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_ROT;
- }
-
- p++;
-
- key.mRot[ joint->mOrder[0]-'X' ] = rot[0];
- key.mRot[ joint->mOrder[1]-'X' ] = rot[1];
- key.mRot[ joint->mOrder[2]-'X' ] = rot[2];
+ key.mRot[ joint->mOrder[0]-'X' ] = floats.front(); floats.pop_front();
+ key.mRot[ joint->mOrder[1]-'X' ] = floats.front(); floats.pop_front();
+ key.mRot[ joint->mOrder[2]-'X' ] = floats.front(); floats.pop_front();
}
}
@@ -1045,7 +960,7 @@ void LLBVHLoader::applyTranslations()
//----------------------------------------------------------------
if ( trans.mIgnore )
{
- //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL;
+ //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL;
joint->mIgnore = TRUE;
continue;
}
@@ -1059,13 +974,12 @@ void LLBVHLoader::applyTranslations()
joint->mOutName = trans.mOutName;
}
- //----------------------------------------------------------------
- // Set the ignorepos flag if necessary
- //----------------------------------------------------------------
- if ( joint->mOutName == std::string("mPelvis") )
- {
- joint->mIgnorePositions = FALSE;
- }
+ //Allow joint position changes as of SL-318
+ joint->mIgnorePositions = FALSE;
+ if (joint->mNumChannels == 3)
+ {
+ joint->mIgnorePositions = TRUE;
+ }
//----------------------------------------------------------------
// Set the relativepos flags if necessary
@@ -1334,6 +1248,9 @@ void LLBVHLoader::reset()
mInitialized = FALSE;
mEmoteName = "";
+ mLineNumber = 0;
+ mTranslations.clear();
+ mConstraints.clear();
}
//------------------------------------------------------------------------
@@ -1508,8 +1425,8 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
frame++;
}
- // output position keys (only for 1st joint)
- if ( ji == mJoints.begin() && !joint->mIgnorePositions )
+ // output position keys if joint has motion.
+ if ( !joint->mIgnorePositions )
{
dp.packS32(joint->mNumPosKeys, "num_pos_keys");
@@ -1539,6 +1456,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
outPos *= INCHES_TO_METERS;
+ //SL-318 Pelvis position can only move 5m. Limiting all joint position offsets to this dist.
outPos -= relPos;
outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
@@ -1586,5 +1504,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)
dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop");
}
+
return TRUE;
}
diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h
index f816b76277..47fe409047 100755
--- a/indra/llcharacter/llbvhloader.h
+++ b/indra/llcharacter/llbvhloader.h
@@ -102,6 +102,7 @@ struct Joint
mNumRotKeys = 0;
mChildTreeMaxDepth = 0;
mPriority = 0;
+ mNumChannels = 3;
}
// Include aligned members first
@@ -123,6 +124,7 @@ struct Joint
S32 mNumRotKeys;
S32 mChildTreeMaxDepth;
S32 mPriority;
+ S32 mNumChannels;
};
@@ -225,8 +227,7 @@ class LLBVHLoader
friend class LLKeyframeMotion;
public:
// Constructor
-// LLBVHLoader(const char* buffer);
- LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine);
+ LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map );
~LLBVHLoader();
/*
@@ -265,13 +266,22 @@ public:
static const char *ST_NO_XLT_EMOTE;
static const char *ST_BAD_ROOT;
*/
+
// Loads the specified translation table.
ELoadStatus loadTranslationTable(const char *fileName);
+ //Create a new joint alias
+ void makeTranslation(std::string key, std::string value);
+
+ // Loads joint aliases from XML file.
+ ELoadStatus loadAliases(const char * filename);
+
// Load the specified BVH file.
// Returns status code.
ELoadStatus loadBVHFile(const char *buffer, char *error_text, S32 &error_line);
+ void dumpBVHInfo();
+
// Applies translations to BVH data loaded.
void applyTranslations();
diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp
index f4a37a139a..ddf89f30f2 100755
--- a/indra/llcharacter/lleditingmotion.cpp
+++ b/indra/llcharacter/lleditingmotion.cpp
@@ -117,6 +117,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte
addJointState( mWristState );
// propagate joint positions to kinematic chain
+ // SL-315
mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
@@ -143,6 +144,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte
BOOL LLEditingMotion::onActivate()
{
// propagate joint positions to kinematic chain
+ // SL-315
mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
@@ -181,6 +183,7 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
focus_pt += mCharacter->getCharacterPosition();
// propagate joint positions to kinematic chain
+ // SL-315
mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
@@ -217,7 +220,8 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
" and focus point " << focus_pt << LL_ENDL;
target.setVec(1.f, 1.f, 1.f);
}
-
+
+ // SL-315
mTarget.setPosition( target + mParentJoint.getPosition());
// LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL;
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index 8fa08a2a6c..4d83b409a0 100755
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -32,6 +32,8 @@
#include "lljoint.h"
#include "llmath.h"
+#include "llcallstack.h"
+#include <boost/algorithm/string.hpp>
S32 LLJoint::sNumUpdates = 0;
S32 LLJoint::sNumTouches = 0;
@@ -108,6 +110,8 @@ void LLJoint::init()
mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
mUpdateXform = TRUE;
+ mSupport = SUPPORT_BASE;
+ mEnd = LLVector3(0.0f, 0.0f, 0.0f);
}
LLJoint::LLJoint() :
@@ -124,13 +128,12 @@ LLJoint::LLJoint(S32 joint_num) :
touch();
}
-
//-----------------------------------------------------------------------------
// LLJoint()
// Class Constructor
//-----------------------------------------------------------------------------
LLJoint::LLJoint(const std::string &name, LLJoint *parent) :
- mJointNum(0)
+ mJointNum(-2)
{
init();
mUpdateXform = FALSE;
@@ -170,6 +173,27 @@ void LLJoint::setup(const std::string &name, LLJoint *parent)
}
//-----------------------------------------------------------------------------
+// setSupport()
+//-----------------------------------------------------------------------------
+void LLJoint::setSupport(const std::string& support_name)
+{
+ if (support_name == "extended")
+ {
+ setSupport(SUPPORT_EXTENDED);
+ }
+ else if (support_name == "base")
+ {
+ setSupport(SUPPORT_BASE);
+ }
+ else
+ {
+ LL_WARNS() << "unknown support string " << support_name << LL_ENDL;
+ setSupport(SUPPORT_BASE);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
// touch()
// Sets all dirty flags for all children, recursively.
//-----------------------------------------------------------------------------
@@ -195,6 +219,18 @@ void LLJoint::touch(U32 flags)
}
//-----------------------------------------------------------------------------
+// setJointNum()
+//-----------------------------------------------------------------------------
+void LLJoint::setJointNum(S32 joint_num)
+{
+ mJointNum = joint_num;
+ if (mJointNum + 2 >= LL_CHARACTER_MAX_ANIMATED_JOINTS)
+ {
+ LL_INFOS() << "Does LL_CHARACTER_MAX_ANIMATED_JOINTS need to be increased?" << LL_ENDL;
+ LL_ERRS() << "joint_num " << joint_num << " too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL;
+ }
+}
+//-----------------------------------------------------------------------------
// getRoot()
//-----------------------------------------------------------------------------
LLJoint *LLJoint::getRoot()
@@ -290,7 +326,11 @@ const LLVector3& LLJoint::getPosition()
bool do_debug_joint(const std::string& name)
{
- return false;
+ if (std::find(LLJoint::s_debugJointNames.begin(), LLJoint::s_debugJointNames.end(),name) != LLJoint::s_debugJointNames.end())
+ {
+ return true;
+ }
+ return false;
}
//--------------------------------------------------------------------
@@ -298,12 +338,14 @@ bool do_debug_joint(const std::string& name)
//--------------------------------------------------------------------
void LLJoint::setPosition( const LLVector3& pos )
{
- if (pos != getPosition())
+ if ((pos != getPosition()) && do_debug_joint(getName()))
{
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
- }
+ LLScopedContextString str("setPosition");
+ LLCallStack cs;
+ LLContextStatus con_status;
+ LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
+ LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << "====================" << LL_ENDL;
+ LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
}
mXform.setPosition(pos);
touch(MATRIX_DIRTY | POSITION_DIRTY);
@@ -393,17 +435,40 @@ void LLJoint::updatePos(const std::string& av_info)
LLUUID mesh_id;
if (m_attachmentOverrides.findActiveOverride(mesh_id,found_pos))
{
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL;
+ if (do_debug_joint(getName()))
+ {
+ LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL;
+ }
pos = found_pos;
}
else
{
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL;
+ if (do_debug_joint(getName()))
+ {
+ LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL;
+ }
pos = m_posBeforeOverrides;
}
setPosition(pos);
}
+// init static
+LLJoint::debug_joint_name_t LLJoint::s_debugJointNames = debug_joint_name_t();
+
+//--------------------------------------------------------------------
+// setDebugJointNames
+//--------------------------------------------------------------------
+void LLJoint::setDebugJointNames(const debug_joint_name_t& names)
+{
+ s_debugJointNames = names;
+}
+void LLJoint::setDebugJointNames(const std::string& names_string)
+{
+ debug_joint_name_t names;
+ boost::split(names, names_string, boost::is_any_of(" :,"));
+ setDebugJointNames(names);
+}
+
//--------------------------------------------------------------------
// getWorldPosition()
//--------------------------------------------------------------------
@@ -531,11 +596,17 @@ const LLVector3& LLJoint::getScale()
//--------------------------------------------------------------------
void LLJoint::setScale( const LLVector3& scale )
{
-// if (mXform.getScale() != scale)
+ if ((mXform.getScale() != scale) && do_debug_joint(getName()))
{
- mXform.setScale(scale);
- touch();
+ LLScopedContextString str("setScale");
+ LLCallStack cs;
+ LLContextStatus con_status;
+ LL_DEBUGS("Avatar") << " joint " << getName() << " set scale " << scale << LL_ENDL;
+ LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << LL_ENDL;
+ LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
}
+ mXform.setScale(scale);
+ touch();
}
diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h
index 2abe1d6db1..61592363f5 100755
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -40,9 +40,15 @@
#include "xform.h"
const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
-const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4!
-const U32 LL_HAND_JOINT_NUM = 31;
-const U32 LL_FACE_JOINT_NUM = 30;
+// BENTO JOINT COUNT LIMIT - need to set this to final skeleton size
+// (bones + attachments) + 2, rounded to next multiple of 4.
+const U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 180; // must be divisible by 4!
+const U32 LL_MAX_JOINTS_PER_MESH_OBJECT = 110;
+
+// These should be higher than the joint_num of any
+// other joint, to avoid conflicts in updateMotionsByType()
+const U32 LL_HAND_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-1);
+const U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2);
const S32 LL_CHARACTER_MAX_PRIORITY = 7;
const F32 LL_MAX_PELVIS_OFFSET = 5.f;
@@ -86,9 +92,17 @@ public:
POSITION_DIRTY = 0x1 << 2,
ALL_DIRTY = 0x7
};
+public:
+ enum SupportCategory
+ {
+ SUPPORT_BASE,
+ SUPPORT_EXTENDED
+ };
protected:
std::string mName;
+ SupportCategory mSupport;
+
// parent joint
LLJoint *mParent;
@@ -104,6 +118,10 @@ public:
// describes the skin binding pose
LLVector3 mSkinOffset;
+ // Endpoint of the bone, if applicable. This is only relevant for
+ // external programs like Blender, and for diagnostic display.
+ LLVector3 mEnd;
+
S32 mJointNum;
// child joints
@@ -113,6 +131,10 @@ public:
// debug statics
static S32 sNumTouches;
static S32 sNumUpdates;
+ typedef std::set<std::string> debug_joint_name_t;
+ static debug_joint_name_t s_debugJointNames;
+ static void setDebugJointNames(const debug_joint_name_t& names);
+ static void setDebugJointNames(const std::string& names_string);
LLPosOverrideMap m_attachmentOverrides;
LLVector3 m_posBeforeOverrides;
@@ -121,7 +143,22 @@ public:
public:
LLJoint();
- LLJoint(S32 joint_num);
+
+ // Note: these joint_num constructors are a bad idea because there
+ // are only a couple of places in the code where it is useful to
+ // have a joint num for a joint (for joints that are used in
+ // animations), and including them as part of the constructor then
+ // forces us to maintain an alternate path through the entire
+ // large-ish class hierarchy of joint types. The only reason they
+ // are still here now is to avoid breaking the baking service
+ // (appearanceutility) builds; these constructors are not used in
+ // the viewer. Once the appearance utility is updated to remove
+ // these joint num references, which it shouldn't ever need, from
+ // its own classes, we can also remove all the joint_num
+ // constructors from LLJoint, LLViewerJoint, LLAvatarJoint, and
+ // createAvatarJoint.
+ LLJoint(S32 joint_num);
+
// *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
LLJoint( const std::string &name, LLJoint *parent=NULL );
virtual ~LLJoint();
@@ -139,6 +176,19 @@ public:
const std::string& getName() const { return mName; }
void setName( const std::string &name ) { mName = name; }
+ // joint num
+ S32 getJointNum() const { return mJointNum; }
+ void setJointNum(S32 joint_num);
+
+ // get/set support
+ SupportCategory getSupport() const { return mSupport; }
+ void setSupport( const SupportCategory& support) { mSupport = support; }
+ void setSupport( const std::string& support_string);
+
+ // get/set end point
+ void setEnd( const LLVector3& end) { mEnd = end; }
+ const LLVector3& getEnd() const { return mEnd; }
+
// getParent
LLJoint *getParent() { return mParent; }
@@ -156,7 +206,8 @@ public:
// get/set local position
const LLVector3& getPosition();
void setPosition( const LLVector3& pos );
-
+
+ // BENTO - history? Not implemented or used.
void setDefaultPosition( const LLVector3& pos );
// get/set world position
@@ -198,8 +249,6 @@ public:
virtual BOOL isAnimatable() const { return TRUE; }
- S32 getJointNum() const { return mJointNum; }
-
void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info );
void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info );
bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const;
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index cd201a65b4..052ca3be58 100755
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1380,7 +1380,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
LL_WARNS() << "no joints in animation" << LL_ENDL;
return FALSE;
}
- else if (num_motions > LL_CHARACTER_MAX_JOINTS)
+ else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS)
{
LL_WARNS() << "too many joints in animation" << LL_ENDL;
return FALSE;
@@ -1419,7 +1419,14 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
LLJoint *joint = mCharacter->getJoint( joint_name );
if (joint)
{
+ S32 joint_num = joint->getJointNum();
// LL_INFOS() << " joint: " << joint_name << LL_ENDL;
+ if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
+ {
+ LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num << " is outside of legal range [0-"
+ << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() << LL_ENDL;
+ joint = NULL;
+ }
}
else
{
@@ -1603,6 +1610,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (old_version)
{
success = dp.unpackVector3(pos_key.mPosition, "pos");
+
+ //MAINT-6162
+ pos_key.mPosition.mV[VX] = llclamp( pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mPosition.mV[VY] = llclamp( pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mPosition.mV[VZ] = llclamp( pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+
}
else
{
@@ -1868,6 +1881,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
{
BOOL success = TRUE;
+ LL_DEBUGS("BVH") << "serializing" << LL_ENDL;
+
success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version");
success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority");
@@ -1881,6 +1896,19 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose");
success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints");
+ LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL;
+ LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL;
+ LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL;
+ LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL;
+ LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL;
+ LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL;
+
for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
{
JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
@@ -1888,6 +1916,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
+ LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL;
for (RotationCurve::key_map_t::iterator iter = joint_motionp->mRotationCurve.mKeys.begin();
iter != joint_motionp->mRotationCurve.mKeys.end(); ++iter)
{
@@ -1905,6 +1934,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU16(x, "rot_angle_x");
success &= dp.packU16(y, "rot_angle_y");
success &= dp.packU16(z, "rot_angle_z");
+
+ LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
}
success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
@@ -1923,37 +1954,54 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU16(x, "pos_x");
success &= dp.packU16(y, "pos_y");
success &= dp.packU16(z, "pos_z");
+
+ LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mPosition.mV[VX] <<","<< pos_key.mPosition.mV[VY] <<","<< pos_key.mPosition.mV[VZ] << LL_ENDL;
}
}
success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints");
+ LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL;
for (JointMotionList::constraint_list_t::const_iterator iter = mJointMotionList->mConstraints.begin();
iter != mJointMotionList->mConstraints.end(); ++iter)
{
JointConstraintSharedData* shared_constraintp = *iter;
success &= dp.packU8(shared_constraintp->mChainLength, "chain_length");
success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type");
- char volume_name[16]; /* Flawfinder: ignore */
- snprintf(volume_name, sizeof(volume_name), "%s", /* Flawfinder: ignore */
+ char source_volume[16]; /* Flawfinder: ignore */
+ snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */
mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str());
- success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "source_volume");
+
+ success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume");
success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset");
+ char target_volume[16]; /* Flawfinder: ignore */
if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND)
{
- snprintf(volume_name,sizeof(volume_name), "%s", "GROUND"); /* Flawfinder: ignore */
+ snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */
}
else
{
- snprintf(volume_name, sizeof(volume_name),"%s", /* Flawfinder: ignore */
+ snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */
mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str());
}
- success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "target_volume");
+ success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume");
success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset");
success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir");
success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start");
success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop");
success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start");
success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop");
+
+ LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL;
+ LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL;
+ LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL;
+ LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL;
}
return success;
@@ -1972,6 +2020,51 @@ U32 LLKeyframeMotion::getFileSize()
}
//-----------------------------------------------------------------------------
+// dumpToFile()
+//-----------------------------------------------------------------------------
+void LLKeyframeMotion::dumpToFile(const std::string& name)
+{
+ if (isLoaded())
+ {
+ std::string outfile_base;
+ if (!name.empty())
+ {
+ outfile_base = name;
+ }
+ else if (!getName().empty())
+ {
+ outfile_base = getName();
+ }
+ else
+ {
+ const LLUUID& id = getID();
+ outfile_base = id.asString();
+ }
+ std::string outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base + ".anim");
+ if (LLFile::isfile(outfilename))
+ {
+ return;
+ }
+
+ S32 file_size = getFileSize();
+ U8* buffer = new U8[file_size];
+
+ LL_DEBUGS("BVH") << "Dumping " << outfilename << LL_ENDL;
+ LLDataPackerBinaryBuffer dp(buffer, file_size);
+ if (serialize(dp))
+ {
+ LLAPRFile outfile;
+ outfile.open(outfilename, LL_APR_WPB);
+ if (outfile.getFileHandle())
+ {
+ outfile.write(buffer, file_size);
+ }
+ }
+ delete [] buffer;
+ }
+}
+
+//-----------------------------------------------------------------------------
// getPelvisBBox()
//-----------------------------------------------------------------------------
const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox()
diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h
index b1422b2b90..f1fa56d731 100755
--- a/indra/llcharacter/llkeyframemotion.h
+++ b/indra/llcharacter/llkeyframemotion.h
@@ -153,6 +153,7 @@ public:
BOOL serialize(LLDataPacker& dp) const;
BOOL deserialize(LLDataPacker& dp);
BOOL isLoaded() { return mJointMotionList != NULL; }
+ void dumpToFile(const std::string& name);
// setters for modifying a keyframe animation
diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp
index fdeddf55e1..02c1d3cdbd 100755
--- a/indra/llcharacter/llkeyframestandmotion.cpp
+++ b/indra/llcharacter/llkeyframestandmotion.cpp
@@ -201,10 +201,12 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
//-------------------------------------------------------------------------
// propagate joint positions to internal versions
//-------------------------------------------------------------------------
+ // SL-315
mPelvisJoint.setPosition(
root_world_pos +
mPelvisState->getPosition() );
+ // SL-315
mHipLeftJoint.setPosition( mHipLeftState->getJoint()->getPosition() );
mKneeLeftJoint.setPosition( mKneeLeftState->getJoint()->getPosition() );
mAnkleLeftJoint.setPosition( mAnkleLeftState->getJoint()->getPosition() );
@@ -213,6 +215,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
mKneeLeftJoint.setScale( mKneeLeftState->getJoint()->getScale() );
mAnkleLeftJoint.setScale( mAnkleLeftState->getJoint()->getScale() );
+ // SL-315
mHipRightJoint.setPosition( mHipRightState->getJoint()->getPosition() );
mKneeRightJoint.setPosition( mKneeRightState->getJoint()->getPosition() );
mAnkleRightJoint.setPosition( mAnkleRightState->getJoint()->getPosition() );
@@ -265,6 +268,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
mCharacter->getGround( mAnkleLeftJoint.getWorldPosition(), mPositionLeft, mNormalLeft);
mCharacter->getGround( mAnkleRightJoint.getWorldPosition(), mPositionRight, mNormalRight);
+ // SL-315
mTargetLeft.setPosition( mPositionLeft );
mTargetRight.setPosition( mPositionRight );
}
diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp
index 4803f855de..697efc8157 100755
--- a/indra/llcharacter/llmotion.cpp
+++ b/indra/llcharacter/llmotion.cpp
@@ -55,7 +55,7 @@ LLMotion::LLMotion( const LLUUID &id ) :
mDeactivateCallbackUserData(NULL)
{
for (S32 i=0; i<3; ++i)
- memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
}
//-----------------------------------------------------------------------------
@@ -111,9 +111,15 @@ void LLMotion::addJointState(const LLPointer<LLJointState>& jointState)
U32 usage = jointState->getUsage();
// for now, usage is everything
- mJointSignature[0][jointState->getJoint()->getJointNum()] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[1][jointState->getJoint()->getJointNum()] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[2][jointState->getJoint()->getJointNum()] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
+ S32 joint_num = jointState->getJoint()->getJointNum();
+ if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
+ {
+ LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL;
+ return;
+ }
+ mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
+ mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
+ mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
}
void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata )
diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h
index 5e37f094b8..2dfc3afc7f 100755
--- a/indra/llcharacter/llmotion.h
+++ b/indra/llcharacter/llmotion.h
@@ -181,7 +181,7 @@ protected:
F32 mSendStopTimestamp; // time when simulator should be told to stop this motion
F32 mResidualWeight; // blend weight at beginning of stop motion phase
F32 mFadeWeight; // for fading in and out based on LOD
- U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority
+ U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority
void (*mDeactivateCallback)(void* data);
void* mDeactivateCallbackUserData;
};
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index e02b139608..d8185aa693 100755
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -37,7 +37,8 @@
#include "llanimationstates.h"
#include "llstl.h"
-const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4;
+// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4.
+const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4;
const U32 MAX_MOTION_INSTANCES = 32;
//-----------------------------------------------------------------------------
@@ -488,8 +489,8 @@ void LLMotionController::updateAdditiveMotions()
//-----------------------------------------------------------------------------
void LLMotionController::resetJointSignatures()
{
- memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
- memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
+ memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
}
//-----------------------------------------------------------------------------
@@ -553,9 +554,9 @@ static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate");
void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
{
BOOL update_result = TRUE;
- U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS];
+ U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
- memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
// iterate through active motions in chronological order
for (motion_list_t::iterator iter = mActiveMotions.begin();
@@ -576,7 +577,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
}
else
{
- // NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4
for (S32 i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++)
{
U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]);
diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h
index 2bd5271c4f..72de331694 100755
--- a/indra/llcharacter/llmotioncontroller.h
+++ b/indra/llcharacter/llmotioncontroller.h
@@ -223,7 +223,7 @@ protected:
S32 mTimeStepCount;
F32 mLastInterp;
- U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
+ U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS];
};
//-----------------------------------------------------------------------------
diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp
index b1a7ebb159..fc95fafd61 100755
--- a/indra/llcharacter/llpose.cpp
+++ b/indra/llcharacter/llpose.cpp
@@ -386,6 +386,7 @@ void LLJointStateBlender::blendJointStates(BOOL apply_now)
}
// apply transforms
+ // SL-315
target_joint->setPosition(blended_pos + added_pos);
target_joint->setScale(blended_scale + added_scale);
target_joint->setRotation(added_rot * blended_rot);
@@ -417,6 +418,7 @@ void LLJointStateBlender::interpolate(F32 u)
return;
}
+ // SL-315
target_joint->setPosition(lerp(target_joint->getPosition(), mJointCache.getPosition(), u));
target_joint->setScale(lerp(target_joint->getScale(), mJointCache.getScale(), u));
target_joint->setRotation(nlerp(u, target_joint->getRotation(), mJointCache.getRotation()));
@@ -444,6 +446,7 @@ void LLJointStateBlender::resetCachedJoint()
return;
}
LLJoint* source_joint = mJointStates[0]->getJoint();
+ // SL-315
mJointCache.setPosition(source_joint->getPosition());
mJointCache.setScale(source_joint->getScale());
mJointCache.setRotation(source_joint->getRotation());
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index c6b97d7e8b..0ad063fd1e 100755
--- a/indra/llcharacter/llvisualparam.h
+++ b/indra/llcharacter/llvisualparam.h
@@ -150,6 +150,7 @@ public:
F32 getWeight() const { return mIsAnimating ? mTargetWeight : mCurWeight; }
F32 getCurrentWeight() const { return mCurWeight; }
F32 getLastWeight() const { return mLastWeight; }
+ void setLastWeight(F32 val) { mLastWeight = val; }
BOOL isAnimating() const { return mIsAnimating; }
BOOL isTweakable() const { return (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) || (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT); }
diff --git a/indra/llcharacter/tests/lljoint_test.cpp b/indra/llcharacter/tests/lljoint_test.cpp
index da151808f2..617f31b0e4 100755
--- a/indra/llcharacter/tests/lljoint_test.cpp
+++ b/indra/llcharacter/tests/lljoint_test.cpp
@@ -88,6 +88,7 @@ namespace tut
{
LLJoint lljoint;
LLVector3 vec3(2.3f,30.f,10.f);
+ // SL-315
lljoint.setPosition(vec3);
LLVector3 pos = lljoint.getPosition();
ensure("setPosition()/getPosition() failed ", (vec3 == pos));
@@ -98,6 +99,7 @@ namespace tut
{
LLJoint lljoint;
LLVector3 vec3(2.3f,30.f,10.f);
+ // SL-315
lljoint.setWorldPosition(vec3);
LLVector3 pos = lljoint.getWorldPosition();
ensure("1:setWorldPosition()/getWorldPosition() failed ", (vec3 == pos));
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 5863310162..635344bc4b 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -38,6 +38,7 @@ set(llcommon_SOURCE_FILES
llbase64.cpp
llbitpack.cpp
llcallbacklist.cpp
+ llcallstack.cpp
llcommon.cpp
llcommonutils.cpp
llcoros.cpp
@@ -111,6 +112,7 @@ set(llcommon_SOURCE_FILES
llworkerthread.cpp
timing.cpp
u64.cpp
+ StackWalker.cpp
)
set(llcommon_HEADER_FILES
@@ -131,6 +133,7 @@ set(llcommon_HEADER_FILES
llbitpack.h
llboost.h
llcallbacklist.h
+ llcallstack.h
llcommon.h
llcommonutils.h
llcoros.h
@@ -231,6 +234,7 @@ set(llcommon_HEADER_FILES
stringize.h
timer.h
u64.h
+ StackWalker.h
)
set_source_files_properties(${llcommon_HEADER_FILES}
diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp
new file mode 100644
index 0000000000..c0d3104099
--- /dev/null
+++ b/indra/llcommon/StackWalker.cpp
@@ -0,0 +1,1388 @@
+/**********************************************************************
+ *
+ * StackWalker.cpp
+ * http://stackwalker.codeplex.com/
+ *
+ *
+ * $LicenseInfo:firstyear=2016&license=bsd$
+ *
+ * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/
+ *
+ * History:
+ * 2005-07-27 v1 - First public release on http://www.codeproject.com/
+ * http://www.codeproject.com/threads/StackWalker.asp
+ * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack
+ * (to simplify the usage)
+ * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL
+ * (should also be enough)
+ * - Changed to compile correctly with the PSDK of VC7.0
+ * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:
+ * it uses LPSTR instead of LPCSTR as first paremeter)
+ * - Added declarations to support VC5/6 without using 'dbghelp.h'
+ * - Added a 'pUserData' member to the ShowCallstack function and the
+ * PReadProcessMemoryRoutine declaration (to pass some user-defined data,
+ * which can be used in the readMemoryFunction-callback)
+ * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default
+ * - Added example for doing an exception-callstack-walking in main.cpp
+ * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)
+ * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!
+ * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag
+ * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx
+ * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN"
+ * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx
+ * Fixed Bug: Compiling with "/Wall"
+ * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx
+ * Fixed Bug: Now checking SymUseSymSrv
+ * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx
+ * Fixed Bug: Support for recursive function calls
+ * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx
+ * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32"
+ * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx
+ * Fixed Bug: SymDia is number 7, not 9!
+ * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8!
+ * Thanks to Teajay which reported the bug...
+ * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx
+ * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory
+ * Thanks to Luiz Salamon which reported this "bug"...
+ * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx
+ * 2009-04-10 v9 License slihtly corrected (<ORGANIZATION> replaced)
+ * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/
+ * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available
+ * 2010-04-15 v12 Added support for VS2010 RTM
+ * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon:
+ * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx
+ * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed:
+ * http://stackwalker.codeplex.com/workitem/10511
+ *
+ *
+ * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Copyright (c) 2005-2013, Jochen Kalmbach
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of Jochen Kalmbach nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ **********************************************************************/
+#if LL_WINDOWS
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <stdlib.h>
+#pragma comment(lib, "version.lib") // for "VerQueryValue"
+#pragma warning(disable:4826)
+
+#include "StackWalker.h"
+
+
+// If VC7 and later, then use the shipped 'dbghelp.h'-file
+#pragma pack(push,8)
+#if _MSC_VER >= 1300
+#include <dbghelp.h>
+#else
+// inline the important dbghelp.h-declarations...
+typedef enum {
+ SymNone = 0,
+ SymCoff,
+ SymCv,
+ SymPdb,
+ SymExport,
+ SymDeferred,
+ SymSym,
+ SymDia,
+ SymVirtual,
+ NumSymTypes
+} SYM_TYPE;
+typedef struct _IMAGEHLP_LINE64 {
+ DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)
+ PVOID Key; // internal
+ DWORD LineNumber; // line number in file
+ PCHAR FileName; // full filename
+ DWORD64 Address; // first instruction of line
+} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
+typedef struct _IMAGEHLP_MODULE64 {
+ DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
+ DWORD64 BaseOfImage; // base load address of module
+ DWORD ImageSize; // virtual size of the loaded module
+ DWORD TimeDateStamp; // date/time stamp from pe header
+ DWORD CheckSum; // checksum from the pe header
+ DWORD NumSyms; // number of symbols in the symbol table
+ SYM_TYPE SymType; // type of symbols loaded
+ CHAR ModuleName[32]; // module name
+ CHAR ImageName[256]; // image name
+ CHAR LoadedImageName[256]; // symbol file name
+} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
+typedef struct _IMAGEHLP_SYMBOL64 {
+ DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64)
+ DWORD64 Address; // virtual address including dll base address
+ DWORD Size; // estimated size of symbol, can be zero
+ DWORD Flags; // info about the symbols, see the SYMF defines
+ DWORD MaxNameLength; // maximum size of symbol name in 'Name'
+ CHAR Name[1]; // symbol name (null terminated string)
+} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
+typedef enum {
+ AddrMode1616,
+ AddrMode1632,
+ AddrModeReal,
+ AddrModeFlat
+} ADDRESS_MODE;
+typedef struct _tagADDRESS64 {
+ DWORD64 Offset;
+ WORD Segment;
+ ADDRESS_MODE Mode;
+} ADDRESS64, *LPADDRESS64;
+typedef struct _KDHELP64 {
+ DWORD64 Thread;
+ DWORD ThCallbackStack;
+ DWORD ThCallbackBStore;
+ DWORD NextCallback;
+ DWORD FramePointer;
+ DWORD64 KiCallUserMode;
+ DWORD64 KeUserCallbackDispatcher;
+ DWORD64 SystemRangeStart;
+ DWORD64 Reserved[8];
+} KDHELP64, *PKDHELP64;
+typedef struct _tagSTACKFRAME64 {
+ ADDRESS64 AddrPC; // program counter
+ ADDRESS64 AddrReturn; // return address
+ ADDRESS64 AddrFrame; // frame pointer
+ ADDRESS64 AddrStack; // stack pointer
+ ADDRESS64 AddrBStore; // backing store pointer
+ PVOID FuncTableEntry; // pointer to pdata/fpo or NULL
+ DWORD64 Params[4]; // possible arguments to the function
+ BOOL Far; // WOW far call
+ BOOL Virtual; // is this a virtual frame?
+ DWORD64 Reserved[3];
+ KDHELP64 KdHelp;
+} STACKFRAME64, *LPSTACKFRAME64;
+typedef
+BOOL
+(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
+ HANDLE hProcess,
+ DWORD64 qwBaseAddress,
+ PVOID lpBuffer,
+ DWORD nSize,
+ LPDWORD lpNumberOfBytesRead
+ );
+typedef
+PVOID
+(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
+ HANDLE hProcess,
+ DWORD64 AddrBase
+ );
+typedef
+DWORD64
+(__stdcall *PGET_MODULE_BASE_ROUTINE64)(
+ HANDLE hProcess,
+ DWORD64 Address
+ );
+typedef
+DWORD64
+(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPADDRESS64 lpaddr
+ );
+#define SYMOPT_CASE_INSENSITIVE 0x00000001
+#define SYMOPT_UNDNAME 0x00000002
+#define SYMOPT_DEFERRED_LOADS 0x00000004
+#define SYMOPT_NO_CPP 0x00000008
+#define SYMOPT_LOAD_LINES 0x00000010
+#define SYMOPT_OMAP_FIND_NEAREST 0x00000020
+#define SYMOPT_LOAD_ANYTHING 0x00000040
+#define SYMOPT_IGNORE_CVREC 0x00000080
+#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
+#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
+#define SYMOPT_EXACT_SYMBOLS 0x00000400
+#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
+#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
+#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
+#define SYMOPT_PUBLICS_ONLY 0x00004000
+#define SYMOPT_NO_PUBLICS 0x00008000
+#define SYMOPT_AUTO_PUBLICS 0x00010000
+#define SYMOPT_NO_IMAGE_SEARCH 0x00020000
+#define SYMOPT_SECURE 0x00040000
+#define SYMOPT_DEBUG 0x80000000
+#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration
+#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration;
+#endif // _MSC_VER < 1300
+#pragma pack(pop)
+
+// Some missing defines (for VC5/6):
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+
+
+// secure-CRT_functions are only available starting with VC8
+#if _MSC_VER < 1400
+#define strcpy_s(dst, len, src) strcpy(dst, src)
+#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
+#define strcat_s(dst, len, src) strcat(dst, src)
+#define _snprintf_s _snprintf
+#define _tcscat_s _tcscat
+#endif
+
+static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
+{
+ if (nMaxDestSize <= 0) return;
+ strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
+ szDest[nMaxDestSize-1] = 0; // INFO: _TRUNCATE will ensure that it is nul-terminated; but with older compilers (<1400) it uses "strncpy" and this does not!)
+} // MyStrCpy
+
+// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
+#define USED_CONTEXT_FLAGS CONTEXT_FULL
+
+
+class StackWalkerInternal
+{
+public:
+ StackWalkerInternal(StackWalker *parent, HANDLE hProcess)
+ {
+ m_parent = parent;
+ m_hDbhHelp = NULL;
+ pSC = NULL;
+ m_hProcess = hProcess;
+ m_szSymPath = NULL;
+ pSFTA = NULL;
+ pSGLFA = NULL;
+ pSGMB = NULL;
+ pSGMI = NULL;
+ pSGO = NULL;
+ pSGSFA = NULL;
+ pSI = NULL;
+ pSLM = NULL;
+ pSSO = NULL;
+ pSW = NULL;
+ pUDSN = NULL;
+ pSGSP = NULL;
+ }
+ ~StackWalkerInternal()
+ {
+ if (pSC != NULL)
+ pSC(m_hProcess); // SymCleanup
+ if (m_hDbhHelp != NULL)
+ FreeLibrary(m_hDbhHelp);
+ m_hDbhHelp = NULL;
+ m_parent = NULL;
+ if(m_szSymPath != NULL)
+ free(m_szSymPath);
+ m_szSymPath = NULL;
+ }
+ BOOL Init(LPCSTR szSymPath)
+ {
+ if (m_parent == NULL)
+ return FALSE;
+ // Dynamically load the Entry-Points for dbghelp.dll:
+ // First try to load the newsest one from
+ TCHAR szTemp[4096];
+ // But before wqe do this, we first check if the ".local" file exists
+ if (GetModuleFileName(NULL, szTemp, 4096) > 0)
+ {
+ _tcscat_s(szTemp, _T(".local"));
+ if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
+ {
+ // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
+ // Ok, first try the new path according to the archtitecture:
+#ifdef _M_IX86
+ if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+ {
+ _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll"));
+ // now check if the file exists:
+ if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+ {
+ m_hDbhHelp = LoadLibrary(szTemp);
+ }
+ }
+#elif _M_X64
+ if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+ {
+ _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll"));
+ // now check if the file exists:
+ if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+ {
+ m_hDbhHelp = LoadLibrary(szTemp);
+ }
+ }
+#elif _M_IA64
+ if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+ {
+ _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll"));
+ // now check if the file exists:
+ if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+ {
+ m_hDbhHelp = LoadLibrary(szTemp);
+ }
+ }
+#endif
+ // If still not found, try the old directories...
+ if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+ {
+ _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
+ // now check if the file exists:
+ if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+ {
+ m_hDbhHelp = LoadLibrary(szTemp);
+ }
+ }
+#if defined _M_X64 || defined _M_IA64
+ // Still not found? Then try to load the (old) 64-Bit version:
+ if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+ {
+ _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
+ if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+ {
+ m_hDbhHelp = LoadLibrary(szTemp);
+ }
+ }
+#endif
+ }
+ }
+ if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one
+ m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );
+ if (m_hDbhHelp == NULL)
+ return FALSE;
+ pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );
+ pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );
+
+ pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );
+ pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );
+ pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );
+
+ pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
+ pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
+ pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
+ pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
+ pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
+ pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
+ pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );
+ pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );
+
+ if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
+ pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
+ pSW == NULL || pUDSN == NULL || pSLM == NULL )
+ {
+ FreeLibrary(m_hDbhHelp);
+ m_hDbhHelp = NULL;
+ pSC = NULL;
+ return FALSE;
+ }
+
+ // SymInitialize
+ if (szSymPath != NULL)
+ m_szSymPath = _strdup(szSymPath);
+ if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
+ this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
+
+ DWORD symOptions = this->pSGO(); // SymGetOptions
+ symOptions |= SYMOPT_LOAD_LINES;
+ symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
+ //symOptions |= SYMOPT_NO_PROMPTS;
+ // SymSetOptions
+ symOptions = this->pSSO(symOptions);
+
+ char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
+ if (this->pSGSP != NULL)
+ {
+ if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
+ this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
+ }
+ char szUserName[1024] = {0};
+ DWORD dwSize = 1024;
+ GetUserNameA(szUserName, &dwSize);
+ this->m_parent->OnSymInit(buf, symOptions, szUserName);
+
+ return TRUE;
+ }
+
+ StackWalker *m_parent;
+
+ HMODULE m_hDbhHelp;
+ HANDLE m_hProcess;
+ LPSTR m_szSymPath;
+
+#pragma pack(push,8)
+typedef struct IMAGEHLP_MODULE64_V3 {
+ DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
+ DWORD64 BaseOfImage; // base load address of module
+ DWORD ImageSize; // virtual size of the loaded module
+ DWORD TimeDateStamp; // date/time stamp from pe header
+ DWORD CheckSum; // checksum from the pe header
+ DWORD NumSyms; // number of symbols in the symbol table
+ SYM_TYPE SymType; // type of symbols loaded
+ CHAR ModuleName[32]; // module name
+ CHAR ImageName[256]; // image name
+ CHAR LoadedImageName[256]; // symbol file name
+ // new elements: 07-Jun-2002
+ CHAR LoadedPdbName[256]; // pdb file name
+ DWORD CVSig; // Signature of the CV record in the debug directories
+ CHAR CVData[MAX_PATH * 3]; // Contents of the CV record
+ DWORD PdbSig; // Signature of PDB
+ GUID PdbSig70; // Signature of PDB (VC 7 and up)
+ DWORD PdbAge; // DBI age of pdb
+ BOOL PdbUnmatched; // loaded an unmatched pdb
+ BOOL DbgUnmatched; // loaded an unmatched dbg
+ BOOL LineNumbers; // we have line number information
+ BOOL GlobalSymbols; // we have internal symbol information
+ BOOL TypeInfo; // we have type information
+ // new elements: 17-Dec-2003
+ BOOL SourceIndexed; // pdb supports source server
+ BOOL Publics; // contains public symbols
+};
+
+typedef struct IMAGEHLP_MODULE64_V2 {
+ DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
+ DWORD64 BaseOfImage; // base load address of module
+ DWORD ImageSize; // virtual size of the loaded module
+ DWORD TimeDateStamp; // date/time stamp from pe header
+ DWORD CheckSum; // checksum from the pe header
+ DWORD NumSyms; // number of symbols in the symbol table
+ SYM_TYPE SymType; // type of symbols loaded
+ CHAR ModuleName[32]; // module name
+ CHAR ImageName[256]; // image name
+ CHAR LoadedImageName[256]; // symbol file name
+};
+#pragma pack(pop)
+
+
+ // SymCleanup()
+ typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
+ tSC pSC;
+
+ // SymFunctionTableAccess64()
+ typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );
+ tSFTA pSFTA;
+
+ // SymGetLineFromAddr64()
+ typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+ OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
+ tSGLFA pSGLFA;
+
+ // SymGetModuleBase64()
+ typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );
+ tSGMB pSGMB;
+
+ // SymGetModuleInfo64()
+ typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );
+ tSGMI pSGMI;
+
+ // SymGetOptions()
+ typedef DWORD (__stdcall *tSGO)( VOID );
+ tSGO pSGO;
+
+ // SymGetSymFromAddr64()
+ typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+ OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
+ tSGSFA pSGSFA;
+
+ // SymInitialize()
+ typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
+ tSI pSI;
+
+ // SymLoadModule64()
+ typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
+ IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );
+ tSLM pSLM;
+
+ // SymSetOptions()
+ typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
+ tSSO pSSO;
+
+ // StackWalk64()
+ typedef BOOL (__stdcall *tSW)(
+ DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord,
+ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
+ tSW pSW;
+
+ // UnDecorateSymbolName()
+ typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
+ DWORD UndecoratedLength, DWORD Flags );
+ tUDSN pUDSN;
+
+ typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
+ tSGSP pSGSP;
+
+
+private:
+ // **************************************** ToolHelp32 ************************
+ #define MAX_MODULE_NAME32 255
+ #define TH32CS_SNAPMODULE 0x00000008
+ #pragma pack( push, 8 )
+ typedef struct tagMODULEENTRY32
+ {
+ DWORD dwSize;
+ DWORD th32ModuleID; // This module
+ DWORD th32ProcessID; // owning process
+ DWORD GlblcntUsage; // Global usage count on the module
+ DWORD ProccntUsage; // Module usage count in th32ProcessID's context
+ BYTE * modBaseAddr; // Base address of module in th32ProcessID's context
+ DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
+ HMODULE hModule; // The hModule of this module in th32ProcessID's context
+ char szModule[MAX_MODULE_NAME32 + 1];
+ char szExePath[MAX_PATH];
+ } MODULEENTRY32;
+ typedef MODULEENTRY32 * PMODULEENTRY32;
+ typedef MODULEENTRY32 * LPMODULEENTRY32;
+ #pragma pack( pop )
+
+ BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
+ {
+ // CreateToolhelp32Snapshot()
+ typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
+ // Module32First()
+ typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+ // Module32Next()
+ typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+
+ // try both dlls...
+ const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };
+ HINSTANCE hToolhelp = NULL;
+ tCT32S pCT32S = NULL;
+ tM32F pM32F = NULL;
+ tM32N pM32N = NULL;
+
+ HANDLE hSnap;
+ MODULEENTRY32 me;
+ me.dwSize = sizeof(me);
+ BOOL keepGoing;
+ size_t i;
+
+ for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ )
+ {
+ hToolhelp = LoadLibrary( dllname[i] );
+ if (hToolhelp == NULL)
+ continue;
+ pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
+ pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");
+ pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");
+ if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )
+ break; // found the functions!
+ FreeLibrary(hToolhelp);
+ hToolhelp = NULL;
+ }
+
+ if (hToolhelp == NULL)
+ return FALSE;
+
+ hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
+ if (hSnap == (HANDLE) -1)
+ {
+ FreeLibrary(hToolhelp);
+ return FALSE;
+ }
+
+ keepGoing = !!pM32F( hSnap, &me );
+ int cnt = 0;
+ while (keepGoing)
+ {
+ this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);
+ cnt++;
+ keepGoing = !!pM32N( hSnap, &me );
+ }
+ CloseHandle(hSnap);
+ FreeLibrary(hToolhelp);
+ if (cnt <= 0)
+ return FALSE;
+ return TRUE;
+ } // GetModuleListTH32
+
+ // **************************************** PSAPI ************************
+ typedef struct _MODULEINFO {
+ LPVOID lpBaseOfDll;
+ DWORD SizeOfImage;
+ LPVOID EntryPoint;
+ } MODULEINFO, *LPMODULEINFO;
+
+ BOOL GetModuleListPSAPI(HANDLE hProcess)
+ {
+ // EnumProcessModules()
+ typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
+ // GetModuleFileNameEx()
+ typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+ // GetModuleBaseName()
+ typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+ // GetModuleInformation()
+ typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
+
+ HINSTANCE hPsapi;
+ tEPM pEPM;
+ tGMFNE pGMFNE;
+ tGMBN pGMBN;
+ tGMI pGMI;
+
+ DWORD i;
+ //ModuleEntry e;
+ DWORD cbNeeded;
+ MODULEINFO mi;
+ HMODULE *hMods = 0;
+ char *tt = NULL;
+ char *tt2 = NULL;
+ const SIZE_T TTBUFLEN = 8096;
+ int cnt = 0;
+
+ hPsapi = LoadLibrary( _T("psapi.dll") );
+ if (hPsapi == NULL)
+ return FALSE;
+
+ pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
+ pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
+ pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
+ pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
+ if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) )
+ {
+ // we couldn´t find all functions
+ FreeLibrary(hPsapi);
+ return FALSE;
+ }
+
+ hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
+ tt = (char*) malloc(sizeof(char) * TTBUFLEN);
+ tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
+ if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
+ goto cleanup;
+
+ if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )
+ {
+ //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
+ goto cleanup;
+ }
+
+ if ( cbNeeded > TTBUFLEN )
+ {
+ //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
+ goto cleanup;
+ }
+
+ for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ )
+ {
+ // base address, size
+ pGMI(hProcess, hMods[i], &mi, sizeof(mi));
+ // image file name
+ tt[0] = 0;
+ pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
+ // module name
+ tt2[0] = 0;
+ pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );
+
+ DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);
+ if (dwRes != ERROR_SUCCESS)
+ this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
+ cnt++;
+ }
+
+ cleanup:
+ if (hPsapi != NULL) FreeLibrary(hPsapi);
+ if (tt2 != NULL) free(tt2);
+ if (tt != NULL) free(tt);
+ if (hMods != NULL) free(hMods);
+
+ return cnt != 0;
+ } // GetModuleListPSAPI
+
+ DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
+ {
+ CHAR *szImg = _strdup(img);
+ CHAR *szMod = _strdup(mod);
+ DWORD result = ERROR_SUCCESS;
+ if ( (szImg == NULL) || (szMod == NULL) )
+ result = ERROR_NOT_ENOUGH_MEMORY;
+ else
+ {
+ if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
+ result = GetLastError();
+ }
+ ULONGLONG fileVersion = 0;
+ if ( (m_parent != NULL) && (szImg != NULL) )
+ {
+ // try to retrive the file-version:
+ if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)
+ {
+ VS_FIXEDFILEINFO *fInfo = NULL;
+ DWORD dwHandle;
+ DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
+ if (dwSize > 0)
+ {
+ LPVOID vData = malloc(dwSize);
+ if (vData != NULL)
+ {
+ if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
+ {
+ UINT len;
+ TCHAR szSubBlock[] = _T("\\");
+ if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)
+ fInfo = NULL;
+ else
+ {
+ fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
+ }
+ }
+ free(vData);
+ }
+ }
+ }
+
+ // Retrive some additional-infos about the module
+ IMAGEHLP_MODULE64_V3 Module;
+ const char *szSymType = "-unknown-";
+ if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
+ {
+ switch(Module.SymType)
+ {
+ case SymNone:
+ szSymType = "-nosymbols-";
+ break;
+ case SymCoff: // 1
+ szSymType = "COFF";
+ break;
+ case SymCv: // 2
+ szSymType = "CV";
+ break;
+ case SymPdb: // 3
+ szSymType = "PDB";
+ break;
+ case SymExport: // 4
+ szSymType = "-exported-";
+ break;
+ case SymDeferred: // 5
+ szSymType = "-deferred-";
+ break;
+ case SymSym: // 6
+ szSymType = "SYM";
+ break;
+ case 7: // SymDia:
+ szSymType = "DIA";
+ break;
+ case 8: //SymVirtual:
+ szSymType = "Virtual";
+ break;
+ }
+ }
+ LPCSTR pdbName = Module.LoadedImageName;
+ if (Module.LoadedPdbName[0] != 0)
+ pdbName = Module.LoadedPdbName;
+ this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion);
+ }
+ if (szImg != NULL) free(szImg);
+ if (szMod != NULL) free(szMod);
+ return result;
+ }
+public:
+ BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
+ {
+ // first try toolhelp32
+ if (GetModuleListTH32(hProcess, dwProcessId))
+ return true;
+ // then try psapi
+ return GetModuleListPSAPI(hProcess);
+ }
+
+
+ BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo)
+ {
+ memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
+ if(this->pSGMI == NULL)
+ {
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ return FALSE;
+ }
+ // First try to use the larger ModuleInfo-Structure
+ pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
+ void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
+ if (pData == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3));
+ static bool s_useV3Version = true;
+ if (s_useV3Version)
+ {
+ if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
+ {
+ // only copy as much memory as is reserved...
+ memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
+ pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
+ free(pData);
+ return TRUE;
+ }
+ s_useV3Version = false; // to prevent unneccessarry calls with the larger struct...
+ }
+
+ // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
+ pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
+ memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
+ if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
+ {
+ // only copy as much memory as is reserved...
+ memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
+ pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
+ free(pData);
+ return TRUE;
+ }
+ free(pData);
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ return FALSE;
+ }
+};
+
+// #############################################################
+StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
+{
+ this->m_verbose = true;
+ this->m_options = OptionsAll;
+ this->m_modulesLoaded = FALSE;
+ this->m_hProcess = hProcess;
+ this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
+ this->m_dwProcessId = dwProcessId;
+ this->m_szSymPath = NULL;
+ this->m_MaxRecursionCount = 1000;
+}
+StackWalker::StackWalker(bool verbose, int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
+{
+ this->m_verbose = verbose;
+ this->m_options = options;
+ this->m_modulesLoaded = FALSE;
+ this->m_hProcess = hProcess;
+ this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
+ this->m_dwProcessId = dwProcessId;
+ if (szSymPath != NULL)
+ {
+ this->m_szSymPath = _strdup(szSymPath);
+ this->m_options |= SymBuildPath;
+ }
+ else
+ this->m_szSymPath = NULL;
+ this->m_MaxRecursionCount = 1000;
+}
+
+StackWalker::~StackWalker()
+{
+ if (m_szSymPath != NULL)
+ free(m_szSymPath);
+ m_szSymPath = NULL;
+ if (this->m_sw != NULL)
+ delete this->m_sw;
+ this->m_sw = NULL;
+}
+
+BOOL StackWalker::LoadModules()
+{
+ if (this->m_sw == NULL)
+ {
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ return FALSE;
+ }
+ if (m_modulesLoaded != FALSE)
+ return TRUE;
+
+ // Build the sym-path:
+ char *szSymPath = NULL;
+ if ( (this->m_options & SymBuildPath) != 0)
+ {
+ const size_t nSymPathLen = 4096;
+ szSymPath = (char*) malloc(nSymPathLen);
+ if (szSymPath == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ szSymPath[0] = 0;
+ // Now first add the (optional) provided sympath:
+ if (this->m_szSymPath != NULL)
+ {
+ strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+
+ strcat_s(szSymPath, nSymPathLen, ".;");
+
+ const size_t nTempLen = 1024;
+ char szTemp[nTempLen];
+ // Now add the current directory:
+ if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+
+ // Now add the path for the main-module:
+ if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)
+ {
+ // locate the rightmost path separator
+ if ( (*p == '\\') || (*p == '/') || (*p == ':') )
+ {
+ *p = 0;
+ break;
+ }
+ } // for (search for path separator...)
+ if (strlen(szTemp) > 0)
+ {
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+ }
+ if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+ if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+ if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ // also add the "system32"-directory:
+ strcat_s(szTemp, nTempLen, "\\system32");
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, ";");
+ }
+
+ if ( (this->m_options & SymUseSymSrv) != 0)
+ {
+ if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
+ {
+ szTemp[nTempLen-1] = 0;
+ strcat_s(szSymPath, nSymPathLen, "SRV*");
+ strcat_s(szSymPath, nSymPathLen, szTemp);
+ strcat_s(szSymPath, nSymPathLen, "\\websymbols");
+ strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
+ }
+ else
+ strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
+ }
+ } // if SymBuildPath
+
+ // First Init the whole stuff...
+ BOOL bRet = this->m_sw->Init(szSymPath);
+ if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;
+ if (bRet == FALSE)
+ {
+ this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ return FALSE;
+ }
+
+ bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
+ if (bRet != FALSE)
+ m_modulesLoaded = TRUE;
+ return bRet;
+}
+
+
+// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
+// This has to be done due to a problem with the "hProcess"-parameter in x64...
+// Because this class is in no case multi-threading-enabled (because of the limitations
+// of dbghelp.dll) it is "safe" to use a static-variable
+static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
+static LPVOID s_readMemoryFunction_UserData = NULL;
+
+BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)
+{
+ m_verbose = verbose;
+ CONTEXT c;
+ CallstackEntry csEntry;
+ IMAGEHLP_SYMBOL64 *pSym = NULL;
+ StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;
+ IMAGEHLP_LINE64 Line;
+ int frameNum;
+ bool bLastEntryCalled = true;
+ int curRecursionCount = 0;
+
+ if (m_modulesLoaded == FALSE)
+ this->LoadModules(); // ignore the result...
+
+ if (this->m_sw->m_hDbhHelp == NULL)
+ {
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ return FALSE;
+ }
+
+ s_readMemoryFunction = readMemoryFunction;
+ s_readMemoryFunction_UserData = pUserData;
+
+ if (context == NULL)
+ {
+ // If no context is provided, capture the context
+ // See: https://stackwalker.codeplex.com/discussions/446958
+#if _WIN32_WINNT <= 0x0501
+ // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available!
+ if (hThread == GetCurrentThread())
+#else
+ if (GetThreadId(hThread) == GetCurrentThreadId())
+#endif
+ {
+ GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
+ }
+ else
+ {
+ SuspendThread(hThread);
+ memset(&c, 0, sizeof(CONTEXT));
+ c.ContextFlags = USED_CONTEXT_FLAGS;
+ if (GetThreadContext(hThread, &c) == FALSE)
+ {
+ ResumeThread(hThread);
+ return FALSE;
+ }
+ }
+ }
+ else
+ c = *context;
+
+ // init STACKFRAME for first call
+ STACKFRAME64 s; // in/out stackframe
+ memset(&s, 0, sizeof(s));
+ DWORD imageType;
+#ifdef _M_IX86
+ // normally, call ImageNtHeader() and use machine info from PE header
+ imageType = IMAGE_FILE_MACHINE_I386;
+ s.AddrPC.Offset = c.Eip;
+ s.AddrPC.Mode = AddrModeFlat;
+ s.AddrFrame.Offset = c.Ebp;
+ s.AddrFrame.Mode = AddrModeFlat;
+ s.AddrStack.Offset = c.Esp;
+ s.AddrStack.Mode = AddrModeFlat;
+#elif _M_X64
+ imageType = IMAGE_FILE_MACHINE_AMD64;
+ s.AddrPC.Offset = c.Rip;
+ s.AddrPC.Mode = AddrModeFlat;
+ s.AddrFrame.Offset = c.Rsp;
+ s.AddrFrame.Mode = AddrModeFlat;
+ s.AddrStack.Offset = c.Rsp;
+ s.AddrStack.Mode = AddrModeFlat;
+#elif _M_IA64
+ imageType = IMAGE_FILE_MACHINE_IA64;
+ s.AddrPC.Offset = c.StIIP;
+ s.AddrPC.Mode = AddrModeFlat;
+ s.AddrFrame.Offset = c.IntSp;
+ s.AddrFrame.Mode = AddrModeFlat;
+ s.AddrBStore.Offset = c.RsBSP;
+ s.AddrBStore.Mode = AddrModeFlat;
+ s.AddrStack.Offset = c.IntSp;
+ s.AddrStack.Mode = AddrModeFlat;
+#else
+#error "Platform not supported!"
+#endif
+
+ pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
+ if (!pSym) goto cleanup; // not enough memory...
+ memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
+ pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+ pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
+
+ memset(&Line, 0, sizeof(Line));
+ Line.SizeOfStruct = sizeof(Line);
+
+ memset(&Module, 0, sizeof(Module));
+ Module.SizeOfStruct = sizeof(Module);
+
+ for (frameNum = 0; ; ++frameNum )
+ {
+ // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
+ // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
+ // assume that either you are done, or that the stack is so hosed that the next
+ // deeper frame could not be found.
+ // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
+ if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) )
+ {
+ // INFO: "StackWalk64" does not set "GetLastError"...
+ this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
+ break;
+ }
+
+ csEntry.offset = s.AddrPC.Offset;
+ csEntry.name[0] = 0;
+ csEntry.undName[0] = 0;
+ csEntry.undFullName[0] = 0;
+ csEntry.offsetFromSmybol = 0;
+ csEntry.offsetFromLine = 0;
+ csEntry.lineFileName[0] = 0;
+ csEntry.lineNumber = 0;
+ csEntry.loadedImageName[0] = 0;
+ csEntry.moduleName[0] = 0;
+ if (s.AddrPC.Offset == s.AddrReturn.Offset)
+ {
+ if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) )
+ {
+ this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
+ break;
+ }
+ curRecursionCount++;
+ }
+ else
+ curRecursionCount = 0;
+ if (s.AddrPC.Offset != 0)
+ {
+ // we seem to have a valid PC
+ // show procedure info (SymGetSymFromAddr64())
+ if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)
+ {
+ MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);
+ // UnDecorateSymbolName()
+ this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );
+ this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );
+ }
+ else
+ {
+ this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
+ }
+
+ // show line number info, NT5.0-method (SymGetLineFromAddr64())
+ if (this->m_sw->pSGLFA != NULL )
+ { // yes, we have SymGetLineFromAddr64()
+ if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)
+ {
+ csEntry.lineNumber = Line.LineNumber;
+ MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName);
+ }
+ else
+ {
+ this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
+ }
+ } // yes, we have SymGetLineFromAddr64()
+
+ if (m_verbose) // getting module info is very slow, skip unless we're being verbose.
+ {
+ // show module info (SymGetModuleInfo64())
+ if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)
+ { // got module info OK
+ switch ( Module.SymType )
+ {
+ case SymNone:
+ csEntry.symTypeString = "-nosymbols-";
+ break;
+ case SymCoff:
+ csEntry.symTypeString = "COFF";
+ break;
+ case SymCv:
+ csEntry.symTypeString = "CV";
+ break;
+ case SymPdb:
+ csEntry.symTypeString = "PDB";
+ break;
+ case SymExport:
+ csEntry.symTypeString = "-exported-";
+ break;
+ case SymDeferred:
+ csEntry.symTypeString = "-deferred-";
+ break;
+ case SymSym:
+ csEntry.symTypeString = "SYM";
+ break;
+#if API_VERSION_NUMBER >= 9
+ case SymDia:
+ csEntry.symTypeString = "DIA";
+ break;
+#endif
+ case 8: //SymVirtual:
+ csEntry.symTypeString = "Virtual";
+ break;
+ default:
+ //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );
+ csEntry.symTypeString = NULL;
+ break;
+ }
+
+ MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName);
+ csEntry.baseOfImage = Module.BaseOfImage;
+ MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName);
+ } // got module info OK
+ else
+ {
+ this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
+ }
+ }
+ else
+ {
+ MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, "MODULE?");
+ }
+ } // we seem to have a valid PC
+
+ CallstackEntryType et = nextEntry;
+ if (frameNum == 0)
+ et = firstEntry;
+ bLastEntryCalled = false;
+ this->OnCallstackEntry(et, csEntry);
+
+ if (s.AddrReturn.Offset == 0)
+ {
+ bLastEntryCalled = true;
+ this->OnCallstackEntry(lastEntry, csEntry);
+ SetLastError(ERROR_SUCCESS);
+ break;
+ }
+ } // for ( frameNum )
+
+ cleanup:
+ if (pSym) free( pSym );
+
+ if (bLastEntryCalled == false)
+ this->OnCallstackEntry(lastEntry, csEntry);
+
+ if (context == NULL)
+ ResumeThread(hThread);
+
+ return TRUE;
+}
+
+BOOL __stdcall StackWalker::myReadProcMem(
+ HANDLE hProcess,
+ DWORD64 qwBaseAddress,
+ PVOID lpBuffer,
+ DWORD nSize,
+ LPDWORD lpNumberOfBytesRead
+ )
+{
+ if (s_readMemoryFunction == NULL)
+ {
+ SIZE_T st;
+ BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
+ *lpNumberOfBytesRead = (DWORD) st;
+ //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
+ return bRet;
+ }
+ else
+ {
+ return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);
+ }
+}
+
+void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
+{
+ CHAR buffer[STACKWALK_MAX_NAMELEN];
+ if (fileVersion == 0)
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);
+ else
+ {
+ DWORD v4 = (DWORD) (fileVersion & 0xFFFF);
+ DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF);
+ DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF);
+ DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF);
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
+ }
+ if (m_verbose)
+ {
+ OnOutput(buffer);
+ }
+}
+
+void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
+{
+ CHAR buffer[STACKWALK_MAX_NAMELEN];
+ if ( (eType != lastEntry) && (entry.offset != 0) )
+ {
+ if (entry.name[0] == 0)
+ MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");
+ if (entry.undName[0] != 0)
+ MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
+ if (entry.undFullName[0] != 0)
+ MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
+ if (entry.lineFileName[0] == 0)
+ {
+ MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
+ if (entry.moduleName[0] == 0)
+ MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
+ }
+ else
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
+ buffer[STACKWALK_MAX_NAMELEN-1] = 0;
+ OnOutput(buffer);
+ }
+}
+
+void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
+{
+ CHAR buffer[STACKWALK_MAX_NAMELEN];
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
+ if (m_verbose)
+ {
+ OnOutput(buffer);
+ }
+}
+
+#pragma warning (disable : 4996)
+
+void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
+{
+ CHAR buffer[STACKWALK_MAX_NAMELEN];
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
+ if (m_verbose)
+ {
+ OnOutput(buffer);
+ }
+ // Also display the OS-version
+#if _MSC_VER <= 1200
+ OSVERSIONINFOA ver;
+ ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
+ ver.dwOSVersionInfoSize = sizeof(ver);
+ if (GetVersionExA(&ver) != FALSE)
+ {
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
+ ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
+ ver.szCSDVersion);
+ if (m_verbose)
+ {
+ OnOutput(buffer);
+ }
+ }
+#else
+ OSVERSIONINFOEXA ver;
+ ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
+ ver.dwOSVersionInfoSize = sizeof(ver);
+ if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
+ {
+ _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
+ ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
+ ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
+ if (m_verbose)
+ {
+ OnOutput(buffer);
+ }
+ }
+#endif
+}
+
+void StackWalker::OnOutput(LPCSTR buffer)
+{
+ OutputDebugStringA(buffer);
+}
+
+#endif // LL_WINDOWS
diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h
new file mode 100644
index 0000000000..5a5ed96e6f
--- /dev/null
+++ b/indra/llcommon/StackWalker.h
@@ -0,0 +1,226 @@
+/**********************************************************************
+ *
+ * StackWalker.h
+ *
+ *
+ *
+ * $LicenseInfo:firstyear=2016&license=bsd$
+ *
+ * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/
+ *
+ * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Copyright (c) 2005-2009, Jochen Kalmbach
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of Jochen Kalmbach nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * **********************************************************************/
+
+#if LL_WINDOWS
+
+// #pragma once is supported starting with _MCS_VER 1000,
+// so we need not to check the version (because we only support _MSC_VER >= 1100)!
+#pragma once
+
+#include <windows.h>
+
+// special defines for VC5/6 (if no actual PSDK is installed):
+#if _MSC_VER < 1300
+typedef unsigned __int64 DWORD64, *PDWORD64;
+#if defined(_WIN64)
+typedef unsigned __int64 SIZE_T, *PSIZE_T;
+#else
+typedef unsigned long SIZE_T, *PSIZE_T;
+#endif
+#endif // _MSC_VER < 1300
+
+class StackWalkerInternal; // forward
+class StackWalker
+{
+public:
+ typedef enum StackWalkOptions
+ {
+ // No addition info will be retrived
+ // (only the address is available)
+ RetrieveNone = 0,
+
+ // Try to get the symbol-name
+ RetrieveSymbol = 1,
+
+ // Try to get the line for this symbol
+ RetrieveLine = 2,
+
+ // Try to retrieve the module-infos
+ RetrieveModuleInfo = 4,
+
+ // Also retrieve the version for the DLL/EXE
+ RetrieveFileVersion = 8,
+
+ // Contains all the abouve
+ RetrieveVerbose = 0xF,
+
+ // Generate a "good" symbol-search-path
+ SymBuildPath = 0x10,
+
+ // Also use the public Microsoft-Symbol-Server
+ SymUseSymSrv = 0x20,
+
+ // Contains all the abouve "Sym"-options
+ SymAll = 0x30,
+
+ // Contains all options (default)
+ OptionsAll = 0x3F
+ } StackWalkOptions;
+
+ StackWalker(
+ bool verbose = true,
+ int options = OptionsAll, // 'int' is by design, to combine the enum-flags
+ LPCSTR szSymPath = NULL,
+ DWORD dwProcessId = GetCurrentProcessId(),
+ HANDLE hProcess = GetCurrentProcess()
+ );
+ StackWalker(DWORD dwProcessId, HANDLE hProcess);
+ virtual ~StackWalker();
+
+ typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
+ HANDLE hProcess,
+ DWORD64 qwBaseAddress,
+ PVOID lpBuffer,
+ DWORD nSize,
+ LPDWORD lpNumberOfBytesRead,
+ LPVOID pUserData // optional data, which was passed in "ShowCallstack"
+ );
+
+ BOOL LoadModules();
+
+ BOOL ShowCallstack(
+ bool verbose,
+ HANDLE hThread = GetCurrentThread(),
+ const CONTEXT *context = NULL,
+ PReadProcessMemoryRoutine readMemoryFunction = NULL,
+ LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
+ );
+
+#if _MSC_VER >= 1300
+// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
+// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
+protected:
+#endif
+ enum { STACKWALK_MAX_NAMELEN = 2048 }; // max name length for found symbols
+
+protected:
+ // Entry for each Callstack-Entry
+ typedef struct CallstackEntry
+ {
+ DWORD64 offset; // if 0, we have no valid entry
+ CHAR name[STACKWALK_MAX_NAMELEN];
+ CHAR undName[STACKWALK_MAX_NAMELEN];
+ CHAR undFullName[STACKWALK_MAX_NAMELEN];
+ DWORD64 offsetFromSmybol;
+ DWORD offsetFromLine;
+ DWORD lineNumber;
+ CHAR lineFileName[STACKWALK_MAX_NAMELEN];
+ DWORD symType;
+ LPCSTR symTypeString;
+ CHAR moduleName[STACKWALK_MAX_NAMELEN];
+ DWORD64 baseOfImage;
+ CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
+ } CallstackEntry;
+
+ typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
+
+ virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
+ virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
+ virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
+ virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
+ virtual void OnOutput(LPCSTR szText);
+
+ StackWalkerInternal *m_sw;
+ HANDLE m_hProcess;
+ DWORD m_dwProcessId;
+ BOOL m_modulesLoaded;
+ LPSTR m_szSymPath;
+
+ bool m_verbose;
+ int m_options;
+ int m_MaxRecursionCount;
+
+ static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
+
+ friend StackWalkerInternal;
+}; // class StackWalker
+
+
+// The "ugly" assembler-implementation is needed for systems before XP
+// If you have a new PSDK and you only compile for XP and later, then you can use
+// the "RtlCaptureContext"
+// Currently there is no define which determines the PSDK-Version...
+// So we just use the compiler-version (and assumes that the PSDK is
+// the one which was installed by the VS-IDE)
+
+// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
+// But I currently use it in x64/IA64 environments...
+//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
+
+#if defined(_M_IX86)
+#ifdef CURRENT_THREAD_VIA_EXCEPTION
+// TODO: The following is not a "good" implementation,
+// because the callstack is only valid in the "__except" block...
+#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
+ do { \
+ memset(&c, 0, sizeof(CONTEXT)); \
+ EXCEPTION_POINTERS *pExp = NULL; \
+ __try { \
+ throw 0; \
+ } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
+ if (pExp != NULL) \
+ memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
+ c.ContextFlags = contextFlags; \
+ } while(0);
+#else
+// The following should be enough for walking the callstack...
+#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
+ do { \
+ memset(&c, 0, sizeof(CONTEXT)); \
+ c.ContextFlags = contextFlags; \
+ __asm call x \
+ __asm x: pop eax \
+ __asm mov c.Eip, eax \
+ __asm mov c.Ebp, ebp \
+ __asm mov c.Esp, esp \
+ } while(0);
+#endif
+
+#else
+
+// The following is defined for x86 (XP and higher), x64 and IA64:
+#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
+ do { \
+ memset(&c, 0, sizeof(CONTEXT)); \
+ c.ContextFlags = contextFlags; \
+ RtlCaptureContext(&c); \
+} while(0);
+#endif
+
+#endif // LL_WINDOWS
diff --git a/indra/llcommon/llcallstack.cpp b/indra/llcommon/llcallstack.cpp
new file mode 100644
index 0000000000..9978645ff4
--- /dev/null
+++ b/indra/llcommon/llcallstack.cpp
@@ -0,0 +1,186 @@
+/**
+ * @file llcallstack.cpp
+ * @brief run-time extraction of the current callstack
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2016, 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 "llcommon.h"
+#include "llcallstack.h"
+#include "StackWalker.h"
+#include "llthreadlocalstorage.h"
+
+#if LL_WINDOWS
+class LLCallStackImpl: public StackWalker
+{
+public:
+ LLCallStackImpl():
+ StackWalker(false,0) // non-verbose, options = 0
+ {
+ }
+ ~LLCallStackImpl()
+ {
+ }
+ void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false)
+ {
+ m_stack.clear();
+ ShowCallstack(verbose);
+ // Skip the first few lines because they're just bookkeeping for LLCallStack,
+ // plus any additional lines requested to skip.
+ S32 first_line = skip_count + 3;
+ for (S32 i=first_line; i<m_stack.size(); ++i)
+ {
+ stack.push_back(m_stack[i]);
+ }
+ }
+protected:
+ virtual void OnOutput(LPCSTR szText)
+ {
+ m_stack.push_back(szText);
+ }
+ std::vector<std::string> m_stack;
+};
+#else
+// Stub - not implemented currently on other platforms.
+class LLCallStackImpl
+{
+public:
+ LLCallStackImpl() {}
+ ~LLCallStackImpl() {}
+ void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false)
+ {
+ stack.clear();
+ }
+};
+#endif
+
+LLCallStackImpl *LLCallStack::s_impl = NULL;
+
+LLCallStack::LLCallStack(S32 skip_count, bool verbose):
+ m_skipCount(skip_count),
+ m_verbose(verbose)
+{
+ if (!s_impl)
+ {
+ s_impl = new LLCallStackImpl;
+ }
+ LLTimer t;
+ s_impl->getStack(m_strings, m_skipCount, m_verbose);
+}
+
+bool LLCallStack::contains(const std::string& str)
+{
+ for (std::vector<std::string>::const_iterator it = m_strings.begin();
+ it != m_strings.end(); ++it)
+ {
+ if (it->find(str) != std::string::npos)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack)
+{
+ std::vector<std::string>::const_iterator it;
+ for (it=call_stack.m_strings.begin(); it!=call_stack.m_strings.end(); ++it)
+ {
+ s << *it;
+ }
+ return s;
+}
+
+LLContextStrings::LLContextStrings()
+{
+}
+
+// static
+LLContextStrings* LLContextStrings::getThreadLocalInstance()
+{
+ LLContextStrings *cons = LLThreadLocalSingletonPointer<LLContextStrings>::getInstance();
+ if (!cons)
+ {
+ LLThreadLocalSingletonPointer<LLContextStrings>::setInstance(new LLContextStrings);
+ }
+ return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance();
+}
+
+// static
+void LLContextStrings::addContextString(const std::string& str)
+{
+ LLContextStrings *cons = getThreadLocalInstance();
+ //LL_INFOS() << "CTX " << (S32)cons << " ADD " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL;
+ cons->m_contextStrings[str]++;
+}
+
+// static
+void LLContextStrings::removeContextString(const std::string& str)
+{
+ LLContextStrings *cons = getThreadLocalInstance();
+ cons->m_contextStrings[str]--;
+ //LL_INFOS() << "CTX " << (S32)cons << " REMOVE " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL;
+ if (cons->m_contextStrings[str] == 0)
+ {
+ cons->m_contextStrings.erase(str);
+ }
+}
+
+// static
+bool LLContextStrings::contains(const std::string& str)
+{
+ const std::map<std::string,S32>& strings =
+ LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings;
+ for (std::map<std::string,S32>::const_iterator it = strings.begin(); it!=strings.end(); ++it)
+ {
+ if (it->first.find(str) != std::string::npos)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// static
+void LLContextStrings::output(std::ostream& os)
+{
+ const std::map<std::string,S32>& strings =
+ LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings;
+ for (std::map<std::string,S32>::const_iterator it = strings.begin(); it!=strings.end(); ++it)
+ {
+ os << it->first << "[" << it->second << "]" << "\n";
+ }
+}
+
+// static
+std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status)
+{
+ LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->output(s);
+ return s;
+}
+
+bool LLContextStatus::contains(const std::string& str)
+{
+ return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->contains(str);
+}
diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h
new file mode 100644
index 0000000000..1f7a7689d7
--- /dev/null
+++ b/indra/llcommon/llcallstack.h
@@ -0,0 +1,80 @@
+/**
+ * @file llcallstack.h
+ * @brief run-time extraction of the current callstack
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2016, 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 <map>
+
+class LLCallStackImpl;
+
+class LLCallStack
+{
+public:
+ LLCallStack(S32 skip_count=0, bool verbose=false);
+ std::vector<std::string> m_strings;
+ bool m_verbose;
+ bool contains(const std::string& str);
+private:
+ static LLCallStackImpl *s_impl;
+ S32 m_skipCount;
+};
+
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack);
+
+class LLContextStrings
+{
+public:
+ LLContextStrings();
+ static void addContextString(const std::string& str);
+ static void removeContextString(const std::string& str);
+ static void output(std::ostream& os);
+ static LLContextStrings* getThreadLocalInstance();
+ static bool contains(const std::string& str);
+private:
+ std::map<std::string,S32> m_contextStrings;
+};
+
+class LLScopedContextString
+{
+public:
+ LLScopedContextString(const std::string& str):
+ m_str(str)
+ {
+ LLContextStrings::addContextString(m_str);
+ }
+ ~LLScopedContextString()
+ {
+ LLContextStrings::removeContextString(m_str);
+ }
+private:
+ std::string m_str;
+};
+
+// Mostly exists as a class to hook an ostream override to.
+struct LLContextStatus
+{
+ bool contains(const std::string& str);
+};
+
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 0435cb8a08..b024b47225 100755
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -242,7 +242,6 @@ inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key)
template <typename K, typename T>
inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
{
- typedef typename std::map<K,T>::const_iterator map_iter;
if(inmap.find(key) == inmap.end())
{
return false;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 8608e45a91..206330fd53 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -4568,6 +4568,7 @@ LLVolumeFace::LLVolumeFace() :
mTexCoords(NULL),
mIndices(NULL),
mWeights(NULL),
+ mWeightsRemapped(FALSE),
mOctree(NULL),
mOptimized(FALSE)
{
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 1da2d0c6b1..33e1403a14 100755
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -953,6 +953,10 @@ public:
// mWeights.size() should be empty or match mVertices.size()
LLVector4a* mWeights;
+ // Whether or not the weights have been cleaned up and remapped
+ // based on currently supported joints.
+ mutable BOOL mWeightsRemapped;
+
LLOctreeNode<LLVolumeTriangle>* mOctree;
//whether or not face has been cache optimized
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 720986a411..50875669fa 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -807,17 +807,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
// LLDAELoader
//-----------------------------------------------------------------------------
LLDAELoader::LLDAELoader(
- std::string filename,
- S32 lod,
+ std::string filename,
+ S32 lod,
load_callback_t load_cb,
joint_lookup_func_t joint_lookup_func,
texture_load_func_t texture_load_func,
- state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointMap,
- JointSet& jointsFromNodes,
+ state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ std::map<std::string, std::string>& jointAliasMap,
+ U32 maxJointsPerMesh,
U32 modelLimit,
- bool preprocess)
+ bool preprocess)
: LLModelLoader(
filename,
lod,
@@ -826,10 +828,12 @@ LLDAELoader::LLDAELoader(
texture_load_func,
state_cb,
opaque_userdata,
- jointMap,
- jointsFromNodes),
-mGeneratedModelLimit(modelLimit),
-mPreprocessDAE(preprocess)
+ jointTransformMap,
+ jointsFromNodes,
+ jointAliasMap,
+ maxJointsPerMesh),
+ mGeneratedModelLimit(modelLimit),
+ mPreprocessDAE(preprocess)
{
}
@@ -1235,6 +1239,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
extractTranslation( pTranslateA, workingTransform );
}
else
+ {
if ( pTranslateB )
{
extractTranslation( pTranslateB, workingTransform );
@@ -1259,9 +1264,10 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}
+ }
- //Store the joint transform w/respect to it's name.
- mJointList[(*jointIt).second.c_str()] = workingTransform;
+ //Store the joint transform w/respect to its name.
+ mJointList[(*jointIt).second.c_str()] = workingTransform;
}
}
@@ -1307,7 +1313,6 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
name = mJointMap[name];
}
model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
}
}
else
@@ -1325,7 +1330,6 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
name = mJointMap[name];
}
model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
}
}
}
@@ -1353,8 +1357,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
mat.mMatrix[i][j] = transform[k*16 + i + j*4];
}
}
-
- model->mSkinInfo.mInvBindMatrix.push_back(mat);
+ model->mSkinInfo.mInvBindMatrix.push_back(mat);
}
}
}
@@ -1370,35 +1373,40 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
if ( !missingSkeletonOrScene )
{
- //Set the joint translations on the avatar - if it's a full mapping
- //The joints are reset in the dtor
- if ( getRigWithSceneParity() )
- {
- JointMap :: const_iterator masterJointIt = mJointMap.begin();
- JointMap :: const_iterator masterJointItEnd = mJointMap.end();
- for (;masterJointIt!=masterJointItEnd;++masterJointIt )
- {
- std::string lookingForJoint = (*masterJointIt).first.c_str();
-
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
- {
- //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
- LLJoint* pJoint = mJointLookupFunc(lookingForJoint,mOpaqueData);
- if ( pJoint )
- {
- LLUUID fake_mesh_id;
- fake_mesh_id.generate();
- pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, "");
- }
- else
- {
- //Most likely an error in the asset.
- LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
- }
- }
- }
- }
+ //Set the joint translations on the avatar
+ JointMap :: const_iterator masterJointIt = mJointMap.begin();
+ JointMap :: const_iterator masterJointItEnd = mJointMap.end();
+ for (;masterJointIt!=masterJointItEnd;++masterJointIt )
+ {
+ std::string lookingForJoint = (*masterJointIt).first.c_str();
+
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLJoint* pJoint = mJointLookupFunc(lookingForJoint,mOpaqueData);
+ if ( pJoint )
+ {
+ // FIXME: mesh_id is used to determine which
+ // mesh gets to set the joint offset, in the
+ // event of a conflict. Since we don't know
+ // the mesh id yet, we can't guarantee that
+ // joint offsets will be applied with the same
+ // priority as in the uploaded model. If the
+ // file contains multiple meshes with
+ // conflicting joint offsets, preview may be
+ // incorrect.
+ LLUUID fake_mesh_id;
+ fake_mesh_id.generate();
+ pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, "");
+ }
+ else
+ {
+ //Most likely an error in the asset.
+ LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
+ }
+ }
+ }
} //missingSkeletonOrScene
//We need to construct the alternate bind matrix (which contains the new joint positions)
@@ -1412,16 +1420,15 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
std::string lookingForJoint = (*jointIt).c_str();
//Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
//and store it in the alternate bind matrix
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ if ( mJointMap.find( lookingForJoint ) != mJointMap.end() )
{
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
- }
+ }
else
{
- LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL;
+ LL_DEBUGS("Mesh")<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<"] "<<LL_ENDL;
}
}
@@ -1868,7 +1875,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string
{
return pChildOfElement;
}
- LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
+ LL_DEBUGS("Mesh")<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
return NULL;
}
diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h
index 27db5326d5..4e990dbe5e 100644
--- a/indra/llprimitive/lldaeloader.h
+++ b/indra/llprimitive/lldaeloader.h
@@ -47,17 +47,19 @@ public:
dae_model_map mModelsMap;
LLDAELoader(
- std::string filename,
- S32 lod,
+ std::string filename,
+ S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointMap,
- JointSet& jointsFromNodes,
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ std::map<std::string, std::string>& jointAliasMap,
+ U32 maxJointsPerMesh,
U32 modelLimit,
- bool preprocess);
+ bool preprocess);
virtual ~LLDAELoader() ;
virtual bool OpenFile(const std::string& filename);
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index e494c55250..adf392fa21 100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -867,6 +867,7 @@ LLSD LLModel::writeModel(
S32 count = 0;
for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter)
{
+ // Note joint index cannot exceed 255.
if (iter->mJointIdx < 255 && iter->mJointIdx >= 0)
{
U8 idx = (U8) iter->mJointIdx;
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index ae602c09df..5f98942340 100755
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -46,7 +46,7 @@ public:
std::vector<std::string> mJointNames;
std::vector<LLMatrix4> mInvBindMatrix;
std::vector<LLMatrix4> mAlternateBindMatrix;
- std::map<std::string, U32> mJointMap;
+ std::vector<U32> mJointRemap;
LLMeshSkinInfo() { }
LLMeshSkinInfo(LLSD& data);
diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
index f86eceb98d..816ebc558a 100644
--- a/indra/llprimitive/llmodelloader.cpp
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -102,16 +102,18 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3&
// LLModelLoader
//-----------------------------------------------------------------------------
LLModelLoader::LLModelLoader(
- std::string filename,
- S32 lod,
+ std::string filename,
+ S32 lod,
load_callback_t load_cb,
joint_lookup_func_t joint_lookup_func,
texture_load_func_t texture_load_func,
- state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointMap,
- JointSet& jointsFromNodes )
-: mJointList( jointMap )
+ state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ JointMap& legalJointNamesMap,
+ U32 maxJointsPerMesh)
+: mJointList( jointTransformMap )
, mJointsFromNode( jointsFromNodes )
, LLThread("Model Loader")
, mFilename(filename)
@@ -124,124 +126,14 @@ LLModelLoader::LLModelLoader(
, mTextureLoadFunc(texture_load_func)
, mStateCallback(state_cb)
, mOpaqueData(opaque_userdata)
-, mRigParityWithScene(false)
-, mRigValidJointUpload(false)
-, mLegacyRigValid(false)
+, mRigValidJointUpload(true)
+, mLegacyRigValid(true)
, mNoNormalize(false)
, mNoOptimize(false)
, mCacheOnlyHitIfRigged(false)
-{
- mJointMap["mPelvis"] = "mPelvis";
- mJointMap["mTorso"] = "mTorso";
- mJointMap["mChest"] = "mChest";
- mJointMap["mNeck"] = "mNeck";
- mJointMap["mHead"] = "mHead";
- mJointMap["mSkull"] = "mSkull";
- mJointMap["mEyeRight"] = "mEyeRight";
- mJointMap["mEyeLeft"] = "mEyeLeft";
- mJointMap["mCollarLeft"] = "mCollarLeft";
- mJointMap["mShoulderLeft"] = "mShoulderLeft";
- mJointMap["mElbowLeft"] = "mElbowLeft";
- mJointMap["mWristLeft"] = "mWristLeft";
- mJointMap["mCollarRight"] = "mCollarRight";
- mJointMap["mShoulderRight"] = "mShoulderRight";
- mJointMap["mElbowRight"] = "mElbowRight";
- mJointMap["mWristRight"] = "mWristRight";
- mJointMap["mHipRight"] = "mHipRight";
- mJointMap["mKneeRight"] = "mKneeRight";
- mJointMap["mAnkleRight"] = "mAnkleRight";
- mJointMap["mFootRight"] = "mFootRight";
- mJointMap["mToeRight"] = "mToeRight";
- mJointMap["mHipLeft"] = "mHipLeft";
- mJointMap["mKneeLeft"] = "mKneeLeft";
- mJointMap["mAnkleLeft"] = "mAnkleLeft";
- mJointMap["mFootLeft"] = "mFootLeft";
- mJointMap["mToeLeft"] = "mToeLeft";
-
- mJointMap["avatar_mPelvis"] = "mPelvis";
- mJointMap["avatar_mTorso"] = "mTorso";
- mJointMap["avatar_mChest"] = "mChest";
- mJointMap["avatar_mNeck"] = "mNeck";
- mJointMap["avatar_mHead"] = "mHead";
- mJointMap["avatar_mSkull"] = "mSkull";
- mJointMap["avatar_mEyeRight"] = "mEyeRight";
- mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
- mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
- mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
- mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
- mJointMap["avatar_mWristLeft"] = "mWristLeft";
- mJointMap["avatar_mCollarRight"] = "mCollarRight";
- mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
- mJointMap["avatar_mElbowRight"] = "mElbowRight";
- mJointMap["avatar_mWristRight"] = "mWristRight";
- mJointMap["avatar_mHipRight"] = "mHipRight";
- mJointMap["avatar_mKneeRight"] = "mKneeRight";
- mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
- mJointMap["avatar_mFootRight"] = "mFootRight";
- mJointMap["avatar_mToeRight"] = "mToeRight";
- mJointMap["avatar_mHipLeft"] = "mHipLeft";
- mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
- mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
- mJointMap["avatar_mFootLeft"] = "mFootLeft";
- mJointMap["avatar_mToeLeft"] = "mToeLeft";
-
-
- mJointMap["hip"] = "mPelvis";
- mJointMap["abdomen"] = "mTorso";
- mJointMap["chest"] = "mChest";
- mJointMap["neck"] = "mNeck";
- mJointMap["head"] = "mHead";
- mJointMap["figureHair"] = "mSkull";
- mJointMap["lCollar"] = "mCollarLeft";
- mJointMap["lShldr"] = "mShoulderLeft";
- mJointMap["lForeArm"] = "mElbowLeft";
- mJointMap["lHand"] = "mWristLeft";
- mJointMap["rCollar"] = "mCollarRight";
- mJointMap["rShldr"] = "mShoulderRight";
- mJointMap["rForeArm"] = "mElbowRight";
- mJointMap["rHand"] = "mWristRight";
- mJointMap["rThigh"] = "mHipRight";
- mJointMap["rShin"] = "mKneeRight";
- mJointMap["rFoot"] = "mFootRight";
- mJointMap["lThigh"] = "mHipLeft";
- mJointMap["lShin"] = "mKneeLeft";
- mJointMap["lFoot"] = "mFootLeft";
-
- //move into joint mapper class
- //1. joints for joint offset verification
- mMasterJointList.push_front("mPelvis");
- mMasterJointList.push_front("mTorso");
- mMasterJointList.push_front("mChest");
- mMasterJointList.push_front("mNeck");
- mMasterJointList.push_front("mHead");
- mMasterJointList.push_front("mCollarLeft");
- mMasterJointList.push_front("mShoulderLeft");
- mMasterJointList.push_front("mElbowLeft");
- mMasterJointList.push_front("mWristLeft");
- mMasterJointList.push_front("mCollarRight");
- mMasterJointList.push_front("mShoulderRight");
- mMasterJointList.push_front("mElbowRight");
- mMasterJointList.push_front("mWristRight");
- mMasterJointList.push_front("mHipRight");
- mMasterJointList.push_front("mKneeRight");
- mMasterJointList.push_front("mFootRight");
- mMasterJointList.push_front("mHipLeft");
- mMasterJointList.push_front("mKneeLeft");
- mMasterJointList.push_front("mFootLeft");
-
- //2. legacy joint list - used to verify rigs that will not be using joint offsets
- mMasterLegacyJointList.push_front("mPelvis");
- mMasterLegacyJointList.push_front("mTorso");
- mMasterLegacyJointList.push_front("mChest");
- mMasterLegacyJointList.push_front("mNeck");
- mMasterLegacyJointList.push_front("mHead");
- mMasterLegacyJointList.push_front("mHipRight");
- mMasterLegacyJointList.push_front("mKneeRight");
- mMasterLegacyJointList.push_front("mFootRight");
- mMasterLegacyJointList.push_front("mHipLeft");
- mMasterLegacyJointList.push_front("mKneeLeft");
- mMasterLegacyJointList.push_front("mFootLeft");
-
+, mMaxJointsPerMesh(maxJointsPerMesh)
+, mJointMap(legalJointNamesMap)
+{
assert_main_thread();
sActiveLoaderList.push_back(this) ;
}
@@ -476,8 +368,6 @@ void LLModelLoader::loadModelCallback()
//-----------------------------------------------------------------------------
void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
{
- critiqueJointToNodeMappingFromScene();
-
//Determines the following use cases for a rig:
//1. It is suitable for upload with skin weights & joint positions, or
//2. It is suitable for upload as standard av with just skin weights
@@ -485,59 +375,27 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
- //It's OK that both could end up being true, both default to false
- if ( isJointPositionUploadOK )
+ // It's OK that both could end up being true.
+
+ // Both start out as true and are forced to false if any mesh in
+ // the model file is not vald by that criterion. Note that a file
+ // can contain multiple meshes.
+ if ( !isJointPositionUploadOK )
{
- setRigValidForJointPositionUpload( true );
+ // This starts out true, becomes false if false for any loaded
+ // mesh.
+ setRigValidForJointPositionUpload( false );
}
- if ( isRigLegacyOK)
+ if ( !isRigLegacyOK)
{
- setLegacyRigValid( true );
+ // This starts out true, becomes false if false for any loaded
+ // mesh.
+ setLegacyRigValid( false );
}
}
-//-----------------------------------------------------------------------------
-// critiqueJointToNodeMappingFromScene()
-//-----------------------------------------------------------------------------
-void LLModelLoader::critiqueJointToNodeMappingFromScene( void )
-{
- //Do the actual nodes back the joint listing from the dae?
- //if yes then this is a fully rigged asset, otherwise it's just a partial rig
-
- JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin();
- JointSet::iterator jointsFromNodeEndIt = mJointsFromNode.end();
- bool result = true;
-
- if ( !mJointsFromNode.empty() )
- {
- for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
- {
- std::string name = *jointsFromNodeIt;
- if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
- {
- continue;
- }
- else
- {
- LL_INFOS() <<"critiqueJointToNodeMappingFromScene is missing a: " << name << LL_ENDL;
- result = false;
- }
- }
- }
- else
- {
- result = false;
- }
- //Determines the following use cases for a rig:
- //1. Full av rig w/1-1 mapping from the scene and joint array
- //2. Partial rig but w/o parity between the scene and joint array
- if ( result )
- {
- setRigWithSceneParity( true );
- }
-}
//-----------------------------------------------------------------------------
// isRigLegacy()
//-----------------------------------------------------------------------------
@@ -549,68 +407,39 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
return false;
}
- bool result = false;
-
- JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
- JointSet :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
+ // Too many joints in asset
+ if (jointListFromAsset.size()>mMaxJointsPerMesh)
+ {
+ LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
+ LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
+ return false;
+ }
+
+ // Unknown joints in asset
+ S32 unknown_joint_count = 0;
+ for (std::vector<std::string>::const_iterator it = jointListFromAsset.begin();
+ it != jointListFromAsset.end(); ++it)
+ {
+ if (mJointMap.find(*it)==mJointMap.end())
+ {
+ LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
+ unknown_joint_count++;
+ }
+ }
+ if (unknown_joint_count>0)
+ {
+ LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
+ return false;
+ }
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
+ return true;
}
//-----------------------------------------------------------------------------
// isRigSuitableForJointPositionUpload()
//-----------------------------------------------------------------------------
bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
{
- bool result = false;
-
- JointSet :: const_iterator masterJointIt = mMasterJointList.begin();
- JointSet :: const_iterator masterJointEndIt = mMasterJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
-
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
+ return true;
}
diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h
index bb4d06dca3..a902ca3404 100644
--- a/indra/llprimitive/llmodelloader.h
+++ b/indra/llprimitive/llmodelloader.h
@@ -34,10 +34,10 @@
class LLJoint;
-typedef std::map<std::string, LLMatrix4> JointTransformMap;
-typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
-typedef std::map<std::string, std::string> JointMap;
-typedef std::deque<std::string> JointSet;
+typedef std::map<std::string, LLMatrix4> JointTransformMap;
+typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
+typedef std::map<std::string, std::string> JointMap;
+typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
@@ -116,18 +116,21 @@ public:
//map of avatar joints as named in COLLADA assets to internal joint names
JointMap mJointMap;
JointTransformMap& mJointList;
- JointSet& mJointsFromNode;
+ JointNameSet& mJointsFromNode;
+ U32 mMaxJointsPerMesh;
LLModelLoader(
- std::string filename,
- S32 lod,
+ std::string filename,
+ S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointMap,
- JointSet& jointsFromNodes);
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ JointMap& legalJointNamesMap,
+ U32 maxJointsPerMesh);
virtual ~LLModelLoader() ;
virtual void setNoNormalize() { mNoNormalize = true; }
@@ -158,7 +161,6 @@ public:
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
- void critiqueJointToNodeMappingFromScene( void );
//Determines if a rig is a legacy from the joint list
bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
@@ -166,9 +168,6 @@ public:
//Determines if a rig is suitable for upload
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
- void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
- const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
-
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
@@ -180,7 +179,7 @@ public:
//-----------------------------------------------------------------------------
bool isNodeAJoint(const char* name)
{
- return mJointMap.find(name) != mJointMap.end();
+ return name != NULL && mJointMap.find(name) != mJointMap.end();
}
protected:
@@ -189,17 +188,14 @@ protected:
LLModelLoader::joint_lookup_func_t mJointLookupFunc;
LLModelLoader::texture_load_func_t mTextureLoadFunc;
LLModelLoader::state_callback_t mStateCallback;
- void* mOpaqueData;
+ void* mOpaqueData;
- bool mRigParityWithScene;
bool mRigValidJointUpload;
bool mLegacyRigValid;
bool mNoNormalize;
bool mNoOptimize;
- JointSet mMasterJointList;
- JointSet mMasterLegacyJointList;
JointTransformMap mJointTransformMap;
static std::list<LLModelLoader*> sActiveLoaderList;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 05483c4608..3c417a6517 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -540,6 +540,7 @@ set(viewer_SOURCE_FILES
llsidepaneliteminfo.cpp
llsidepaneltaskinfo.cpp
llsidetraypanelcontainer.cpp
+ llskinningutil.cpp
llsky.cpp
llslurl.cpp
llsnapshotlivepreview.cpp
@@ -1149,6 +1150,7 @@ set(viewer_HEADER_FILES
llsidepaneliteminfo.h
llsidepaneltaskinfo.h
llsidetraypanelcontainer.h
+ llskinningutil.h
llsky.h
llslurl.h
llsnapshotlivepreview.h
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index c4e41f9459..0062ac9718 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-4.0.3
+5.0.0
diff --git a/indra/newview/app_settings/anim.ini b/indra/newview/app_settings/anim.ini
index 63c84e544d..c24d2749ef 100755
--- a/indra/newview/app_settings/anim.ini
+++ b/indra/newview/app_settings/anim.ini
@@ -1,87 +1,2 @@
Translations 1.0
-[hip]
- relativepos = firstkey
- relativerot = firstkey
- outname = mPelvis
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[abdomen]
- outname = mTorso
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[chest]
- outname = mChest
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[neckDummy]
- ignore = true
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[neck]
- outname = mNeck
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[head]
- outname = mHead
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[figureHair]
- ignore = true
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lCollar]
- outname = mCollarLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lShldr]
- outname = mShoulderLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lForeArm]
- outname = mElbowLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lHand]
- outname = mWristLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rCollar]
- outname = mCollarRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rShldr]
- outname = mShoulderRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rForeArm]
- outname = mElbowRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rHand]
- outname = mWristRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lThigh]
- outname = mHipLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lShin]
- outname = mKneeLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[lFoot]
- outname = mAnkleLeft
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rThigh]
- outname = mHipRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rShin]
- outname = mKneeRight
- frame = 0 1 0, 0 0 1, 1 0 0
-
-[rFoot]
- outname = mAnkleRight
- frame = 0 1 0, 0 0 1, 1 0 0 \ No newline at end of file
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4a69133fde..5ea847599b 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2194,6 +2194,17 @@
<key>Value</key>
<string />
</map>
+ <key>DebugAvatarJoints</key>
+ <map>
+ <key>Comment</key>
+ <string>List of joints to emit additional debugging info about.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
<key>DebugAvatarRezTime</key>
<map>
<key>Comment</key>
@@ -3503,6 +3514,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>IncludeEnhancedSkeleton</key>
+ <map>
+ <key>Comment</key>
+ <string>Include extended skeleton joints when rendering skinned meshes.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>MinObjectsForUnlinkConfirm</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
index 3060307b21..8f754fe82b 100755
--- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
@@ -24,8 +24,11 @@
ATTRIBUTE vec4 weight4;
-uniform mat3 matrixPalette[52];
-uniform vec3 translationPalette[52];
+/* BENTO JOINT COUNT LIMITS
+ * Note that the value in these two lines also needs to be updated to value-1 several places below.
+ */
+uniform mat3 matrixPalette[MAX_JOINTS_PER_MESH_OBJECT];
+uniform vec3 translationPalette[MAX_JOINTS_PER_MESH_OBJECT];
mat4 getObjectSkinnedTransform()
{
@@ -34,7 +37,7 @@ mat4 getObjectSkinnedTransform()
vec4 w = fract(weight4);
vec4 index = floor(weight4);
- index = min(index, vec4(51.0));
+ index = min(index, vec4(MAX_JOINTS_PER_MESH_OBJECT-1));
index = max(index, vec4( 0.0));
w *= 1.0/(w.x+w.y+w.z+w.w);
@@ -67,8 +70,8 @@ mat4 getObjectSkinnedTransform()
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts.
mat3 dummy1 = matrixPalette[0];
vec3 dummy2 = translationPalette[0];
- mat3 dummy3 = matrixPalette[51];
- vec3 dummy4 = translationPalette[51];
+ mat3 dummy3 = matrixPalette[MAX_JOINTS_PER_MESH_OBJECT-1];
+ vec3 dummy4 = translationPalette[MAX_JOINTS_PER_MESH_OBJECT-1];
#endif
}
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index 9ec6428ee6..2aa90969c9 100755
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
-<linden_avatar
- version="1.0" wearable_definition_version="22">
+<linden_avatar
+ version="2.0" wearable_definition_version="22">
<!-- The wearable_definition_version is checked during asset upload. -->
<!-- If you increment it, check indra/lib/python/indra/assetutil.py. -->
<skeleton
@@ -73,7 +73,7 @@
joint="mFootLeft"
position="0 0.0 0.0"
rotation="0 0 0"
- visible_in_first_person="true"/>
+ visible_in_first_person="true"/>
<attachment_point
id="8"
@@ -83,7 +83,7 @@
joint="mFootRight"
position="0 0.0 0.0"
rotation="0 0 0"
- visible_in_first_person="true"/>
+ visible_in_first_person="true"/>
<attachment_point
id="9"
@@ -93,7 +93,7 @@
joint="mChest"
position="-0.15 0 -0.1"
rotation="0 -90 90"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="10"
@@ -103,7 +103,7 @@
joint="mPelvis"
position="0 0 -0.15"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="11"
@@ -113,8 +113,8 @@
joint="mHead"
position="0.12 0 0.001"
rotation="0 0 0"
- visible_in_first_person="false"/>
-
+ visible_in_first_person="false"/>
+
<attachment_point
id="12"
group="2"
@@ -123,7 +123,7 @@
joint="mHead"
position="0.12 0 -0.04"
rotation="0 0 0"
- visible_in_first_person="false" />
+ visible_in_first_person="false" />
<attachment_point
id="13"
@@ -133,7 +133,7 @@
joint="mHead"
position="0.015 0.08 0.017"
rotation="0 0 0"
- visible_in_first_person="false" />
+ visible_in_first_person="false" />
<attachment_point
id="14"
@@ -143,7 +143,7 @@
joint="mHead"
position="0.015 -0.08 0.017"
rotation="0 0 0"
- visible_in_first_person="false" />
+ visible_in_first_person="false" />
<attachment_point
id="15"
@@ -153,7 +153,7 @@
joint="mEyeLeft"
position="0 0 0"
rotation="0 0 0"
- visible_in_first_person="false"/>
+ visible_in_first_person="false"/>
<attachment_point
id="16"
@@ -163,7 +163,7 @@
joint="mEyeRight"
position="0 0 0"
rotation="0 0 0"
- visible_in_first_person="false" />
+ visible_in_first_person="false" />
<attachment_point
id="17"
@@ -173,7 +173,7 @@
joint="mHead"
position="0.1 0 0.05"
rotation="0 0 0"
- visible_in_first_person="false"/>
+ visible_in_first_person="false"/>
<attachment_point
id="18"
@@ -183,7 +183,7 @@
joint="mShoulderRight"
position="0.01 -0.13 0.01"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="19"
@@ -193,7 +193,7 @@
joint="mElbowRight"
position="0 -0.12 0"
rotation="0 0 0"
- visible_in_first_person="true"/>
+ visible_in_first_person="true"/>
<attachment_point
id="20"
@@ -203,7 +203,7 @@
joint="mShoulderLeft"
position="0.01 0.15 -0.01"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="21"
@@ -213,7 +213,7 @@
joint="mElbowLeft"
position="0 0.113 0"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="22"
@@ -223,7 +223,7 @@
joint="mHipRight"
position="0 0 0"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="23"
@@ -233,7 +233,7 @@
joint="mHipRight"
position="-0.017 0.041 -0.310"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="24"
@@ -243,7 +243,7 @@
joint="mKneeRight"
position="-0.044 -0.007 -0.262"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="25"
@@ -253,8 +253,8 @@
joint="mHipLeft"
position="0 0 0"
rotation="0 0 0"
- visible_in_first_person="true" />
-
+ visible_in_first_person="true" />
+
<attachment_point
id="26"
group="5"
@@ -263,7 +263,7 @@
joint="mHipLeft"
position="-0.019 -0.034 -0.310"
rotation="0 0 0"
- visible_in_first_person="true"/>
+ visible_in_first_person="true"/>
<attachment_point
id="27"
@@ -273,7 +273,7 @@
joint="mKneeLeft"
position="-0.044 -0.007 -0.261"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="28"
@@ -283,7 +283,7 @@
joint="mPelvis"
position="0.092 0.0 0.088"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="29"
@@ -293,7 +293,7 @@
joint="mTorso"
position="0.104 0.082 0.247"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="30"
@@ -303,11 +303,11 @@
joint="mTorso"
position="0.104 -0.082 0.247"
rotation="0 0 0"
- visible_in_first_person="true" />
+ visible_in_first_person="true" />
<attachment_point
id="31"
- group="8"
+ group="9"
name="Center 2"
joint="mScreen"
position="0 0 0"
@@ -318,7 +318,7 @@
<attachment_point
id="32"
- group="8"
+ group="9"
name="Top Right"
joint="mScreen"
position="0 -0.5 0.5"
@@ -329,7 +329,7 @@
<attachment_point
id="33"
- group="8"
+ group="9"
name="Top"
joint="mScreen"
position="0 0 0.5"
@@ -340,7 +340,7 @@
<attachment_point
id="34"
- group="8"
+ group="9"
name="Top Left"
joint="mScreen"
position="0 0.5 0.5"
@@ -351,7 +351,7 @@
<attachment_point
id="35"
- group="8"
+ group="9"
name="Center"
joint="mScreen"
position="0 0 0"
@@ -362,7 +362,7 @@
<attachment_point
id="36"
- group="8"
+ group="9"
name="Bottom Left"
joint="mScreen"
position="0 0.5 -0.5"
@@ -373,7 +373,7 @@
<attachment_point
id="37"
- group="8"
+ group="9"
name="Bottom"
joint="mScreen"
position="0 0 -0.5"
@@ -384,7 +384,7 @@
<attachment_point
id="38"
- group="8"
+ group="9"
name="Bottom Right"
joint="mScreen"
position="0 -0.5 -0.5"
@@ -413,6 +413,140 @@
rotation="0 0 0"
visible_in_first_person="true" />
+ <!-- BENTO ADDITIONS -->
+
+ <attachment_point
+ id="41"
+ group="8"
+ pie_slice="0"
+ name="Left Ring Finger"
+ joint="mHandRing1Left"
+ position="-0.006 0.019 -0.002"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="42"
+ group="8"
+ pie_slice="1"
+ name="Right Ring Finger"
+ joint="mHandRing1Right"
+ position="-0.006 -0.019 -0.002"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="43"
+ group="8"
+ pie_slice="2"
+ name="Tail Base"
+ joint="mTail1"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="44"
+ group="8"
+ pie_slice="3"
+ name="Tail Tip"
+ joint="mTail6"
+ position="-0.025 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="45"
+ group="8"
+ pie_slice="4"
+ name="Left Wing"
+ joint="mWing4Left"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="46"
+ group="8"
+ pie_slice="5"
+ name="Right Wing"
+ joint="mWing4Right"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="47"
+ group="8"
+ pie_slice="6"
+ name="Jaw"
+ joint="mFaceJaw"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="48"
+ group="8"
+ pie_slice="7"
+ name="Alt Left Ear"
+ joint="mFaceEar1Left"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="49"
+ group="8"
+ pie_slice="8"
+ name="Alt Right Ear"
+ joint="mFaceEar1Right"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="50"
+ group="8"
+ pie_slice="9"
+ name="Alt Left Eye"
+ joint="mFaceEyeAltLeft"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="51"
+ group="8"
+ pie_slice="10"
+ name="Alt Right Eye"
+ joint="mFaceEyeAltRight"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="52"
+ group="8"
+ pie_slice="11"
+ name="Tongue"
+ joint="mFaceTongueTip"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <attachment_point
+ id="53"
+ group="8"
+ pie_slice="12"
+ name="Groin"
+ joint="mGroin"
+ position="0.000 0.000 0.000"
+ rotation="0 0 0"
+ visible_in_first_person="true"/>
+
+ <!-- END BENTO -->
+
<param
id="32"
group="1"
@@ -478,6 +612,11 @@
<bone
name="mKneeRight"
scale=".05 .05 .1" />
+
+ <bone name="mWingsRoot" scale="1 0 0" offset="0 0 0" />
+ <bone name="mWing1Right" scale="0 0 0" offset="0.02 0 0" />
+ <bone name="mWing1Left" scale="0 0 0" offset="0.02 0 0" />
+
</param_skeleton>
</param>
@@ -624,6 +763,17 @@
<bone
name="mKneeRight"
scale="0.12 0.12 0" />
+
+ <bone name="mTail1" scale="0.05 0.1 0.1" />
+ <bone name="mTail2" scale="0.05 0.1 0.1" />
+ <bone name="mTail3" scale="0.05 0.1 0.1" />
+ <bone name="mTail4" scale="0.05 0.1 0.1" />
+ <bone name="mTail5" scale="0.05 0.1 0.1" />
+ <bone name="mTail6" scale="0.05 0 0" />
+
+ <bone name="mWing1Right" offset="-0.01 -0.01 0" />
+ <bone name="mWing1Left" offset="-0.01 0.01 0" />
+
</param_skeleton>
</param>
@@ -662,6 +812,10 @@
<bone
name="mChest"
scale="0.02 0.08 0" />
+
+ <bone name="mWing1Right" offset="0 -0.02 0" />
+ <bone name="mWing1Left" offset="0 0.02 0" />
+
</param_skeleton>
</param>
@@ -693,6 +847,11 @@
name="mHipRight"
scale="0 0 0"
offset="0 -.004 0" />
+
+ <bone name="mTail1" scale="0.0 0.05 0" />
+ <bone name="mTail2" scale="0.0 0.02 0" />
+ <bone name="mTail3" scale="0.0 0.01 0" />
+
</param_skeleton>
</param>
@@ -774,6 +933,68 @@
name="mEyeRight"
scale="0 0 0"
offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="0 0 0 "
+ offset="0 .009 0" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="0 0 0 "
+ offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyeLidLowerLeft"
+ scale="0 0 0 "
+ offset="0 .009 0" />
+
+ <bone
+ name="mFaceEyeLidLowerRight"
+ scale="0 0 0 "
+ offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyeLidUpperLeft"
+ scale="0 0 0 "
+ offset="0 .009 0" />
+
+ <bone
+ name="mFaceEyeLidUpperRight"
+ scale="0 0 0 "
+ offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyebrowInnerLeft"
+ scale="0 0 0 "
+ offset="0 .009 0" />
+
+ <bone
+ name="mFaceEyebrowInnerRight"
+ scale="0 0 0 "
+ offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyebrowCenterLeft"
+ scale="0 0 0 "
+ offset="0 .009 0" />
+
+ <bone
+ name="mFaceEyebrowCenterRight"
+ scale="0 0 0 "
+ offset="0 -.009 0" />
+
+ <bone
+ name="mFaceEyebrowOuterLeft"
+ scale="0 0 0 "
+ offset="0 .005 0" />
+
+ <bone
+ name="mFaceEyebrowOuterRight"
+ scale="0 0 0 "
+ offset="0 -.005 0" />
+
+
</param_skeleton>
</param>
@@ -797,6 +1018,146 @@
name="mEyeRight"
scale="0 0 0"
offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceNoseRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceNoseLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEar1Left"
+ scale="0 0 0"
+ offset="0 0 .004" />
+ <bone
+ name="mFaceEar1Right"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceLipUpperLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceLipUpperRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceLipLowerLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceLipLowerRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceLipCornerRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceLipCornerLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceCheekUpperInnerLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceCheekUpperInnerRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceCheekUpperOuterLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceCheekUpperOuterRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyeLidUpperLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyeLidUpperRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyeLidLowerLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyeLidLowerRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyebrowInnerLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyebrowInnerRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyebrowCenterLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyebrowCenterRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceEyebrowOuterLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceEyebrowOuterRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
+ <bone
+ name="mFaceForeheadLeft"
+ scale="0 0 0"
+ offset="0 0 .004" />
+
+ <bone
+ name="mFaceForeheadRight"
+ scale="0 0 0"
+ offset="0 0 -.004" />
+
</param_skeleton>
</param>
@@ -820,6 +1181,94 @@
name="mEyeRight"
scale="0 0 0"
offset=".016 0 0" />
+
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="0 0 0"
+ offset=".016 0 0" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="0 0 0"
+ offset=".016 0 0" />
+
+ <bone
+ name="mFaceRoot"
+ scale="0 0 0"
+ offset=".016 0 0" />
+
+ <bone
+ name="mFaceNoseCenter"
+ scale="0 0 0"
+ offset=".0195 0 0" />
+
+ <bone
+ name="mFaceNoseRight"
+ scale="0 0 0"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceNoseLeft"
+ scale="0 0 0"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEar1Left"
+ scale="0 0 0"
+ offset="-0.016 0 0" />
+ <bone
+ name="mFaceEar1Right"
+ scale="0 0 0"
+ offset="-0.016 0 0" />
+
+ <bone
+ name="mFaceLipUpperCenter"
+ scale="0 0 0"
+ offset="0.005 0 0" />
+
+ <bone
+ name="mFaceLipLowerCenter"
+ scale="0 0 0"
+ offset="-0.0015 0 0" />
+
+ <bone
+ name="mFaceLipUpperLeft"
+ scale="0 0 0"
+ offset="0.005 0 0" />
+
+ <bone
+ name="mFaceLipUpperRight"
+ scale="0 0 0"
+ offset="0.005 0 0" />
+
+ <bone
+ name="mFaceLipLowerLeft"
+ scale="0 0 0"
+ offset="-0.0015 0 0" />
+
+ <bone
+ name="mFaceLipLowerRight"
+ scale="0 0 0"
+ offset="-0.0015 0 0" />
+
+ <bone
+ name="mFaceLipCornerRight"
+ scale="0 0 0"
+ offset="-0.0015 0 0" />
+
+ <bone
+ name="mFaceLipCornerLeft"
+ scale="0 0 0"
+ offset="-0.0015 0 0" />
+ <bone
+ name="mFaceCheekUpperInnerLeft"
+ scale="0 0 0"
+ offset="-0.005 0 0" />
+ <bone
+ name="mFaceCheekUpperInnerRight"
+ scale="0 0 0"
+ offset="-0.005 0 0" />
+
</param_skeleton>
</param>
@@ -843,6 +1292,67 @@
name="mEyeRight"
scale="0 0 0"
offset=".005 0 0" />
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="0 0 0"
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="0 0 0"
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyeLidLowerLeft"
+ scale="0 0 0 "
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyeLidLowerRight"
+ scale="0 0 0 "
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyeLidUpperLeft"
+ scale="0 0 0 "
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyeLidUpperRight"
+ scale="0 0 0 "
+ offset=".005 0 0" />
+
+ <bone
+ name="mFaceEyebrowInnerRight"
+ scale="0 0 0 "
+ offset=".002 0 0" />
+
+ <bone
+ name="mFaceEyebrowInnerLeft"
+ scale="0 0 0 "
+ offset=".002 0 0" />
+
+ <bone
+ name="mFaceEyebrowCenterRight"
+ scale="0 0 0 "
+ offset=".001 0 0" />
+
+ <bone
+ name="mFaceEyebrowCenterLeft"
+ scale="0 0 0 "
+ offset=".001 0 0" />
+
+ <bone
+ name="mFaceEyebrowOuterRight"
+ scale="0 0 0 "
+ offset=".002 0 0" />
+
+ <bone
+ name="mFaceEyebrowOuterLeft"
+ scale="0 0 0 "
+ offset=".002 0 0" />
+
+
</param_skeleton>
</param>
@@ -850,7 +1360,7 @@
id="655"
group="1"
name="Head Size"
- label="Head Size"
+ label="Head Size"
wearable="shape"
edit_group="shape_head"
label_min="Small Head"
@@ -870,6 +1380,11 @@
offset="0 0 0" />
<bone
+ name="mFaceRoot"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
name="mEyeLeft"
scale="1 1 1"
offset="0 0 0" />
@@ -878,6 +1393,162 @@
name="mEyeRight"
scale="1 1 1"
offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceForeheadLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceForeheadCenter"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceForeheadRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowOuterLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowCenterLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowInnerLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowOuterRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowCenterRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyebrowInnerRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeLidUpperLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeLidLowerLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeLidUpperRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceEyeLidLowerRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceNoseLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceNoseCenter"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceNoseRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceCheekUpperInnerLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceCheekUpperOuterLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceCheekUpperInnerRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceCheekUpperOuterRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceJaw"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipUpperLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipUpperCenter"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipUpperRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipCornerLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipCornerRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipLowerLeft"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipLowerCenter"
+ scale="1 1 1"
+ offset="0 0 0" />
+
+ <bone
+ name="mFaceLipLowerRight"
+ scale="1 1 1"
+ offset="0 0 0" />
+
</param_skeleton>
</param>
@@ -951,6 +1622,47 @@
name="mWristLeft"
scale="1 1 1"
offset="0 0 0" />
+
+ <bone name = "mHandThumb1Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandThumb2Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandThumb3Right" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandIndex1Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandIndex2Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandIndex3Right" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandMiddle1Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandMiddle2Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandMiddle3Right" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandRing1Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandRing2Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandRing3Right" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandPinky1Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandPinky2Right" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandPinky3Right" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandThumb1Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandThumb2Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandThumb3Left" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandIndex1Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandIndex2Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandIndex3Left" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandMiddle1Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandMiddle2Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandMiddle3Left" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandRing1Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandRing2Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandRing3Left" scale = "1 1 1" offset = "0 0 0" />
+
+ <bone name = "mHandPinky1Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandPinky2Left" scale = "1 1 1" offset = "0 0 0" />
+ <bone name = "mHandPinky3Left" scale = "1 1 1" offset = "0 0 0" />
+
</param_skeleton>
</param>
@@ -997,6 +1709,37 @@
name="mEyeRight"
scale="0 0 0"
offset="-.005 0 0" />
+
+ <bone
+ name="mFaceEyeAltLeft"
+ scale="0 0 0"
+ offset="-.005 0 0" />
+
+ <bone
+ name="mFaceEyeAltRight"
+ scale="0 0 0"
+ offset="-.005 0 0" />
+
+ <bone
+ name="mFaceEyeLidLowerRight"
+ scale="0 0 0"
+ offset="-.003 0 -0.003" />
+
+ <bone
+ name="mFaceEyeLidLowerLeft"
+ scale="0 0 0"
+ offset="-.003 0 -0.003" />
+
+ <bone
+ name="mFaceEyeLidUpperRight"
+ scale="0 0 0"
+ offset="-.003 0 0.003" />
+
+ <bone
+ name="mFaceEyeLidUpperLeft"
+ scale="0 0 0"
+ offset="-.003 0 0.003" />
+
</param_skeleton>
</param>
diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml
index 6b07bbc1d3..b1f54e94bb 100755
--- a/indra/newview/character/avatar_skeleton.xml
+++ b/indra/newview/character/avatar_skeleton.xml
@@ -1,81 +1,220 @@
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
-<linden_skeleton version="1.0" num_bones="53" num_collision_volumes="26">
-<bone name="mPelvis" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 1.067015">
- <collision_volume name="PELVIS" pos = "-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17"/>
- <collision_volume name="BUTT" pos = "-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1"/>
- <bone name="mTorso" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 0.084073">
- <collision_volume name="BELLY" pos = "0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15"/>
- <collision_volume name="LOWER_BACK" pos = "0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15"/>
- <collision_volume name="LEFT_HANDLE" pos = "0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05"/>
- <collision_volume name="RIGHT_HANDLE" pos = "0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05"/>
- <bone name="mChest" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.015368 0.000000 0.204877">
- <collision_volume name="CHEST" pos = "0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2"/>
- <collision_volume name="UPPER_BACK" pos = "0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15"/>
- <collision_volume name="LEFT_PEC" pos = "0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05"/>
- <collision_volume name="RIGHT_PEC" pos = "0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05"/>
- <bone name="mNeck" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.009507 0.000000 0.251108">
- <collision_volume name="NECK" pos = "0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08"/>
- <bone name="mHead" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.000000 0.075630">
- <collision_volume name="HEAD" pos = "0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12"/>
- <bone name="mSkull" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 0.079000">
- </bone>
- <bone name="mEyeRight" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" pivot="0.098466 -0.036000 0.079000">
- </bone>
- <bone name="mEyeLeft" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.098461 0.036000 0.079000">
- </bone>
- </bone>
- </bone>
- <bone name="mCollarLeft" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.020927 0.084665 0.165396">
- <collision_volume name="L_CLAVICLE" pos = "0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05"/>
- <bone name="mShoulderLeft" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.079000 -0.000000">
- <collision_volume name="L_UPPER_ARM" pos = "0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05"/>
- <bone name="mElbowLeft" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.248000 0.000000">
- <collision_volume name="L_LOWER_ARM" pos = "0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04"/>
- <bone name="mWristLeft" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000000 0.204846 0.000000">
- <collision_volume name="L_HAND" pos = "0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03"/>
- </bone>
- </bone>
- </bone>
- </bone>
- <bone name="mCollarRight" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.020927 -0.085000 0.165396">
- <collision_volume name="R_CLAVICLE" pos = "0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05"/>
- <bone name="mShoulderRight" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.079418 -0.000000">
- <collision_volume name="R_UPPER_ARM" pos = "0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05"/>
- <bone name="mElbowRight" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.248000 -0.000000">
- <collision_volume name="R_LOWER_ARM" pos = "0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04"/>
- <bone name="mWristRight" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000000 -0.205000 -0.000000">
- <collision_volume name="R_HAND" pos = "0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03"/>
- </bone>
- </bone>
- </bone>
- </bone>
- </bone>
- </bone>
- <bone name="mHipRight" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.033620 -0.128806 -0.041086">
- <collision_volume name="R_UPPER_LEG" pos = "-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32"/>
- <bone name="mKneeRight" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000780 0.048635 -0.490922">
- <collision_volume name="R_LOWER_LEG" pos = "-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25"/>
- <bone name="mAnkleRight" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.028869 0.000000 -0.468494">
- <collision_volume name="R_FOOT" pos = "0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05"/>
- <bone name="mFootRight" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.111956 -0.000000 -0.060637">
- <bone name="mToeRight" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.105399 -0.010408 -0.000104">
- </bone>
- </bone>
- </bone>
- </bone>
- </bone>
- <bone name="mHipLeft" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.033757 0.126765 -0.040998">
- <collision_volume name="L_UPPER_LEG" pos = "-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32"/>
- <bone name="mKneeLeft" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000887 -0.045568 -0.491053">
- <collision_volume name="L_LOWER_LEG" pos = "-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25"/>
- <bone name="mAnkleLeft" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.028887 0.001378 -0.468449">
- <collision_volume name="L_FOOT" pos = "0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05"/>
- <bone name="mFootLeft" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.111956 -0.000000 -0.060620">
- <bone name="mToeLeft" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.105387 0.008270 0.000871">
- </bone>
- </bone>
- </bone>
- </bone>
- </bone>
-</bone>
-</linden_skeleton> \ No newline at end of file
+<linden_skeleton num_bones="123" num_collision_volumes="26" version="1.0">
+ <bone aliases="hip avatar_mPelvis" end="0.000 0.000 0.084" group="SL Base" name="mPelvis" pivot="0.000000 0.000000 1.067015" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false">
+ <collision_volume end="0.030 0.000 0.095" group="Collision" name="PELVIS" pos="-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17" support="base"/>
+ <collision_volume end="-0.100 0.000 0.000" group="Collision" name="BUTT" pos="-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1" support="base"/>
+ <bone connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+ <bone aliases="abdomen avatar_mTorso" connected="true" end="-0.015 0.000 0.205" group="SL Base" name="mTorso" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.028 0.000 0.094" group="Collision" name="BELLY" pos="0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15" support="base"/>
+ <collision_volume end="0.000 0.100 0.000" group="Collision" name="LEFT_HANDLE" pos="0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/>
+ <collision_volume end="0.000 -0.100 0.000" group="Collision" name="RIGHT_HANDLE" pos="0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/>
+ <collision_volume end="-0.100 0.000 0.000" group="Collision" name="LOWER_BACK" pos="0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base"/>
+ <bone connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
+ <bone aliases="chest avatar_mChest" connected="true" end="-0.010 0.000 0.250" group="SL Base" name="mChest" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="-0.096 0.000 0.152" group="Collision" name="CHEST" pos="0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2" support="base"/>
+ <collision_volume end="0.080 0.000 -0.006" group="Collision" name="LEFT_PEC" pos="0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base"/>
+ <collision_volume end="0.080 0.000 -0.006" group="Collision" name="RIGHT_PEC" pos="0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base"/>
+ <collision_volume end="-0.100 0.000 0.000" group="Collision" name="UPPER_BACK" pos="0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base"/>
+ <bone aliases="neck avatar_mNeck" connected="true" end="0.000 0.000 0.077" group="SL Base" name="mNeck" pivot="-0.009507 0.000000 0.251108" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 0.000 0.080" group="Collision" name="NECK" pos="0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08" support="base"/>
+ <bone aliases="head avatar_mHead" connected="true" end="0.000 0.000 0.079" group="SL Base" name="mHead" pivot="0.000000 -0.000000 0.075630" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 0.000 0.100" group="Collision" name="HEAD" pos="0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12" support="base"/>
+ <bone aliases="figureHair avatar_mSkull" end="0.000 0.000 0.033" group="SL Base" name="mSkull" pivot="0.000000 0.000000 0.079000" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false"/>
+ <bone aliases="avatar_mEyeRight" end="0.100 0.000 0.000" group="SL Base" name="mEyeRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" support="base" connected="false"/>
+ <bone aliases="avatar_mEyeLeft" end="0.100 0.000 0.000" group="SL Base" name="mEyeLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false"/>
+ <bone end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025 0.000 0.045" pos="0.025 0.000 0.045" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.038 0.000 0.000" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.062 0.036 0.039" pos="0.062 0.036 0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone connected="false" end="0.100 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073479 0.036009 0.034009" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
+ <bone end="0.036 0.000 0.000" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.061 0.036 0.027" pos="0.061 0.036 0.027" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.038 0.000 0.000" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.062 -0.036 0.039" pos="0.062 -0.036 0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone connected="false" end="0.100 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073484 -0.036009 0.034009" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
+ <bone end="0.036 0.000 0.000" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.061 -0.036 0.027" pos="0.061 -0.036 0.027" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ <bone end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ <bone end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.026 0.017 -0.010" group="Face" name="mFaceCheekUpperInnerLeft" pivot="0.062 0.037 -0.012" pos="0.062 0.037 -0.012" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.015 0.028 0.005" group="Face" name="mFaceCheekUpperOuterLeft" pivot="0.047 0.044 0.008" pos="0.047 0.044 0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.022 -0.017 -0.010" group="Face" name="mFaceCheekUpperInnerRight" pivot="0.062 -0.037 -0.012" pos="0.062 -0.037 -0.012" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.015 -0.028 0.005" group="Face" name="mFaceCheekUpperOuterRight" pivot="0.047 -0.044 0.008" pos="0.047 -0.044 0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.048 0.003 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.058 0.012 -0.033" pos="0.058 0.012 -0.033" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.048 -0.003 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.058 -0.012 -0.033" pos="0.058 -0.012 -0.033" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.045 0.008 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.048 0.024 -0.040" pos="0.048 0.024 -0.040" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.045 -0.008 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.048 -0.024 -0.040" pos="0.048 -0.024 -0.040" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.044 0.000 -0.021" group="Mouth" name="mFaceJaw" pivot="0.020 0.000 -0.037" pos="0.020 0.000 -0.037" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.020 0.000 0.008" group="Mouth" name="mFaceTongueBase" pivot="0.044 0.000 -0.021" pos="0.044 0.000 -0.021" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.007 0.000 0.003" group="Mouth" name="mFaceTongueTip" pivot="0.020 0.000 0.008" pos="0.020 0.000 0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ <bone end="0.047 0.003 0.000" group="Lips" name="mFaceLipLowerLeft" pivot="0.032 0.014 -0.012" pos="0.032 0.014 -0.012" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.047 -0.003 0.000" group="Lips" name="mFaceLipLowerRight" pivot="0.032 -0.014 -0.012" pos="0.032 -0.014 -0.012" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.048 0.000 0.000" group="Lips" name="mFaceLipLowerCenter" pivot="0.037 0.000 -0.017" pos="0.037 0.000 -0.017" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ </bone>
+ <bone end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="0.048 0.000 0.000" group="Lips" name="mFaceLipUpperCenter" pivot="0.060 0.000 -0.030" pos="0.060 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ </bone>
+ </bone>
+ </bone>
+ <bone aliases="lCollar avatar_mCollarLeft" end="0.000 0.079 0.000" group="SL Base" name="mCollarLeft" pivot="-0.020927 0.084665 0.165396" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false">
+ <collision_volume end="0.000 0.100 0.000" group="Collision" name="L_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base"/>
+ <bone aliases="lShldr avatar_mShoulderLeft" connected="true" end="0.000 0.247 0.000" group="SL Base" name="mShoulderLeft" pivot="0.000000 0.079000 -0.000000" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 0.130 -0.003" group="Collision" name="L_UPPER_ARM" pos="0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base"/>
+ <bone aliases="lForeArm avatar_mElbowLeft" connected="true" end="0.000 0.205 0.000" group="SL Base" name="mElbowLeft" pivot="0.000000 0.248000 0.000000" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 0.100 -0.001" group="Collision" name="L_LOWER_ARM" pos="0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/>
+ <bone aliases="lHand avatar_mWristLeft" connected="true" end="0.000 0.060 0.000" group="SL Base" name="mWristLeft" pivot="-0.000000 0.204846 0.000000" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.005 0.049 -0.001" group="Collision" name="L_HAND" pos="0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03" support="base"/>
+ <bone end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="0.028 0.032 -0.001" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.023 0.031 -0.001" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.015 0.025 0.001" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone aliases="rCollar avatar_mCollarRight" end="0.000 -0.079 0.000" group="SL Base" name="mCollarRight" pivot="-0.020927 -0.085000 0.165396" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false">
+ <collision_volume end="0.000 -0.100 0.000" group="Collision" name="R_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base"/>
+ <bone aliases="rShldr avatar_mShoulderRight" connected="true" end="0.000 -0.247 0.000" group="SL Base" name="mShoulderRight" pivot="0.000000 -0.079418 -0.000000" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 -0.130 -0.003" group="Collision" name="R_UPPER_ARM" pos="0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base"/>
+ <bone aliases="rForeArm avatar_mElbowRight" connected="true" end="0.000 -0.205 0.000" group="SL Base" name="mElbowRight" pivot="0.000000 -0.248000 -0.000000" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.000 -0.100 -0.001" group="Collision" name="R_LOWER_ARM" pos="0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/>
+ <bone aliases="rHand avatar_mWristRight" connected="true" end="0.000 -0.060 0.000" group="SL Base" name="mWristRight" pivot="-0.000000 -0.205000 -0.000000" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.005 -0.049 -0.001" group="Collision" name="R_HAND" pos="0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03" support="base"/>
+ <bone end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="0.028 -0.032 -0.001" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="0.023 -0.031 -0.001" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.015 -0.025 0.001" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ <bone connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ <bone end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ <bone connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone aliases="rThigh avatar_mHipRight" end="-0.001 0.049 -0.491" group="SL Base" name="mHipRight" pivot="0.033620 -0.128806 -0.041086" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false">
+ <collision_volume end="0.000 0.000 -0.200" group="Collision" name="R_UPPER_LEG" pos="-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base"/>
+ <bone aliases="rShin avatar_mKneeRight" connected="true" end="-0.029 0.000 -0.469" group="SL Base" name="mKneeRight" pivot="-0.000780 0.048635 -0.490922" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="-0.010 0.000 -0.150" group="Collision" name="R_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base"/>
+ <bone aliases="rFoot avatar_mAnkleRight" connected="true" end="0.112 0.000 -0.061" group="SL Base" name="mAnkleRight" pivot="-0.028869 0.000000 -0.468494" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.089 0.000 -0.026" group="Collision" name="R_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base"/>
+ <bone aliases="avatar_mFootRight" connected="true" end="0.105 -0.010 -0.000" group="SL Base" name="mFootRight" pivot="0.111956 -0.000000 -0.060637" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <bone aliases="avatar_mToeRight" connected="true" end="0.020 0.000 0.000" group="SL Base" name="mToeRight" pivot="0.105399 -0.010408 -0.000104" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone aliases="lThigh avatar_mHipLeft" end="-0.001 -0.046 -0.491" group="SL Base" name="mHipLeft" pivot="0.033757 0.126765 -0.040998" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" connected="false">
+ <collision_volume end="0.000 0.000 -0.200" group="Collision" name="L_UPPER_LEG" pos="-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base"/>
+ <bone aliases="lShin avatar_mKneeLeft" connected="true" end="-0.029 0.001 -0.469" group="SL Base" name="mKneeLeft" pivot="-0.000887 -0.045568 -0.491053" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="-0.010 0.000 -0.150" group="Collision" name="L_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base"/>
+ <bone aliases="lFoot avatar_mAnkleLeft" connected="true" end="0.112 0.000 -0.061" group="SL Base" name="mAnkleLeft" pivot="-0.028887 0.001378 -0.468449" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <collision_volume end="0.089 0.000 -0.026" group="Collision" name="L_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base"/>
+ <bone aliases="avatar_mFootLeft" connected="true" end="0.105 0.008 0.001" group="SL Base" name="mFootLeft" pivot="0.111956 -0.000000 -0.060620" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
+ <bone aliases="avatar_mToeLeft" connected="true" end="0.020 0.000 0.000" group="SL Base" name="mToeLeft" pivot="0.105387 0.008270 0.000871" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+ <bone end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false"/>
+ <bone end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.138 0.000 -0.067" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ <bone end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" connected="false">
+ <bone connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
+ <bone connected="true" end="0.138 0.000 -0.067" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
+ </bone>
+ </bone>
+ </bone>
+ </bone>
+</linden_skeleton>
+
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 675b1973d8..eb9b35191c 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4165,6 +4165,8 @@ void LLAgent::setTeleportState(ETeleportState state)
void LLAgent::stopCurrentAnimations()
{
+ LL_DEBUGS("Avatar") << "Stopping current animations" << LL_ENDL;
+
// This function stops all current overriding animations on this
// avatar, propagating this change back to the server.
if (isAgentAvatarValid())
@@ -4182,6 +4184,7 @@ void LLAgent::stopCurrentAnimations()
// don't cancel a ground-sit anim, as viewers
// use this animation's status in
// determining whether we're sitting. ick.
+ LL_DEBUGS("Avatar") << "sit or do-not-disturb animation will not be stopped" << LL_ENDL;
}
else
{
@@ -4211,8 +4214,7 @@ void LLAgent::stopCurrentAnimations()
// re-assert at least the default standing animation, because
// viewers get confused by avs with no associated anims.
- sendAnimationRequest(ANIM_AGENT_STAND,
- ANIM_REQUEST_START);
+ sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START);
}
}
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index fa16f02c16..e335eabd1a 100755
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -1448,6 +1448,7 @@ void LLAgentCamera::updateCamera()
diff.mV[VZ] = 0.f;
}
+ // SL-315
gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff);
gAgentAvatarp->mRoot->updateWorldMatrixChildren();
@@ -2144,6 +2145,7 @@ void LLAgentCamera::changeCameraToFollow(BOOL animate)
if (isAgentAvatarValid())
{
+ // SL-315
gAgentAvatarp->mPelvisp->setPosition(LLVector3::zero);
gAgentAvatarp->startMotion( ANIM_AGENT_BODY_NOISE );
gAgentAvatarp->startMotion( ANIM_AGENT_BREATHE_ROT );
@@ -2184,6 +2186,7 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate)
{
if (!gAgentAvatarp->isSitting())
{
+ // SL-315
gAgentAvatarp->mPelvisp->setPosition(LLVector3::zero);
}
gAgentAvatarp->startMotion(ANIM_AGENT_BODY_NOISE);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 2898d8ca31..c661141940 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -101,6 +101,7 @@
#include "llscenemonitor.h"
#include "llavatarrenderinfoaccountant.h"
#include "lllocalbitmaps.h"
+#include "llskinningutil.h"
// Linden library includes
#include "llavatarnamecache.h"
@@ -799,6 +800,9 @@ bool LLAppViewer::init()
LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
+ // initialize skinning util
+ LLSkinningUtil::initClass();
+
//set the max heap size.
initMaxHeapSize() ;
LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize"));
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 8bbc529244..33c6d0b00a 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "lldrawpoolavatar.h"
+#include "llskinningutil.h"
#include "llrender.h"
#include "llvoavatar.h"
@@ -55,8 +56,6 @@ static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
static U32 sShaderLevel = 0;
-#define JOINT_COUNT 52
-
LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL;
BOOL LLDrawPoolAvatar::sSkipOpaque = FALSE;
BOOL LLDrawPoolAvatar::sSkipTransparent = FALSE;
@@ -1462,7 +1461,13 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
}
}
-void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
+void LLDrawPoolAvatar::getRiggedGeometry(
+ LLFace* face,
+ LLPointer<LLVertexBuffer>& buffer,
+ U32 data_mask,
+ const LLMeshSkinInfo* skin,
+ LLVolume* volume,
+ const LLVolumeFace& vol_face)
{
face->setGeomIndex(0);
face->setIndicesIndex(0);
@@ -1471,7 +1476,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>
face->setTextureIndex(255);
if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
- { //make a new buffer
+ {
+ // make a new buffer
if (sShaderLevel > 0)
{
buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
@@ -1483,7 +1489,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>
buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true);
}
else
- { //resize existing buffer
+ {
+ //resize existing buffer
buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices);
}
@@ -1497,9 +1504,9 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>
m = m.inverse().transpose();
F32 mat3[] =
- { m.m[0], m.m[1], m.m[2],
- m.m[4], m.m[5], m.m[6],
- m.m[8], m.m[9], m.m[10] };
+ { m.m[0], m.m[1], m.m[2],
+ m.m[4], m.m[5], m.m[6],
+ m.m[8], m.m[9], m.m[10] };
LLMatrix3 mat_normal(mat3);
@@ -1526,26 +1533,37 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>
{
face->clearState(LLFace::TEXTURE_ANIM);
}
-
-
face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
buffer->flush();
}
-void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
+void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
+ LLVOAvatar* avatar,
+ LLFace* face,
+ const LLMeshSkinInfo* skin,
+ LLVolume* volume,
+ const LLVolumeFace& vol_face)
{
LLVector4a* weight = vol_face.mWeights;
if (!weight)
{
return;
}
+ // FIXME ugly const cast
+ LLSkinningUtil::remapSkinInfoJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
LLDrawable* drawable = face->getDrawable();
U32 data_mask = face->getRiggedVertexBufferDataMask();
+ if (!vol_face.mWeightsRemapped)
+ {
+ LLSkinningUtil::remapSkinWeights(weight, vol_face.mNumVertices, skin);
+ vol_face.mWeightsRemapped = TRUE;
+ }
+
if (buffer.isNull() ||
buffer->getTypeMask() != data_mask ||
buffer->getNumVerts() != vol_face.mNumVertices ||
@@ -1596,60 +1614,19 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
//build matrix palette
- LLMatrix4a mp[JOINT_COUNT];
- LLMatrix4* mat = (LLMatrix4*) mp;
-
- U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT);
- for (U32 j = 0; j < count; ++j)
- {
- LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
- if (!joint)
- {
- joint = avatar->getJoint("mPelvis");
- }
- if (joint)
- {
- mat[j] = skin->mInvBindMatrix[j];
- mat[j] *= joint->getWorldMatrix();
- }
- }
+ LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+ U32 count = LLSkinningUtil::getMeshJointCount(skin);
+ LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar);
+ LLSkinningUtil::checkSkinWeights(weight, buffer->getNumVerts(), skin);
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+ const U32 max_joints = LLSkinningUtil::getMaxJointCount();
for (U32 j = 0; j < buffer->getNumVerts(); ++j)
{
LLMatrix4a final_mat;
- final_mat.clear();
-
- S32 idx[4];
-
- LLVector4 wght;
-
- F32 scale = 0.f;
- for (U32 k = 0; k < 4; k++)
- {
- F32 w = weight[j][k];
-
- idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)JOINT_COUNT-1);
-
- wght[k] = w - floorf(w);
- scale += wght[k];
- }
- // This is enforced in unpackVolumeFaces()
- llassert(scale>0.f);
- wght *= 1.f/scale;
-
- for (U32 k = 0; k < 4; k++)
- {
- F32 w = wght[k];
-
- LLMatrix4a src;
- src.setMul(mp[idx[k]], w);
-
- final_mat.add(src);
- }
-
+ LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints);
LLVector4a& v = vol_face.mPositions[j];
LLVector4a t;
@@ -1729,34 +1706,21 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
if (buff)
{
if (sShaderLevel > 0)
- { //upload matrix palette to shader
- LLMatrix4 mat[JOINT_COUNT];
-
- U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT);
+ {
+ // upload matrix palette to shader
+ LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+ U32 count = LLSkinningUtil::getMeshJointCount(skin);
+ LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar);
- for (U32 i = 0; i < count; ++i)
- {
- LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
- if (!joint)
- {
- joint = avatar->getJoint("mPelvis");
- }
- if (joint)
- {
- mat[i] = skin->mInvBindMatrix[i];
- mat[i] *= joint->getWorldMatrix();
- }
- }
-
stop_glerror();
- F32 mp[JOINT_COUNT*9];
+ F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*9];
- F32 transp[JOINT_COUNT*3];
+ F32 transp[LL_MAX_JOINTS_PER_MESH_OBJECT*3];
for (U32 i = 0; i < count; ++i)
{
- F32* m = (F32*) mat[i].mMatrix;
+ F32* m = (F32*) mat[i].mMatrix[0].getF32ptr();
U32 idx = i*9;
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 669ffa7c59..543b6ff813 100755
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -178,6 +178,12 @@ void LLFloaterBvhPreview::setAnimCallbacks()
getChild<LLUICtrl>("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseOut, this, _1));
}
+std::map <std::string, std::string> LLFloaterBvhPreview::getJointAliases()
+{
+ LLPointer<LLVOAvatar> av = (LLVOAvatar*)mAnimPreview->getDummyAvatar();
+ return av->getJointAliases();
+}
+
//-----------------------------------------------------------------------------
// postBuild()
//-----------------------------------------------------------------------------
@@ -215,6 +221,8 @@ BOOL LLFloaterBvhPreview::postBuild()
getChildView("bad_animation_text")->setVisible(FALSE);
+ mAnimPreview = new LLPreviewAnimation(256, 256);
+
std::string exten = gDirUtilp->getExtension(mFilename);
if (exten == "bvh")
{
@@ -241,8 +249,11 @@ BOOL LLFloaterBvhPreview::postBuild()
file_buffer[file_size] = '\0';
LL_INFOS() << "Loading BVH file " << mFilename << LL_ENDL;
ELoadStatus load_status = E_ST_OK;
- S32 line_number = 0;
- loaderp = new LLBVHLoader(file_buffer, load_status, line_number);
+ S32 line_number = 0;
+
+ std::map<std::string, std::string> joint_alias_map = getJointAliases();
+
+ loaderp = new LLBVHLoader(file_buffer, load_status, line_number, joint_alias_map);
std::string status = getString(STATUS[load_status]);
if(load_status == E_ST_NO_XLT_FILE)
@@ -266,8 +277,6 @@ BOOL LLFloaterBvhPreview::postBuild()
mTransactionID.generate();
mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
- mAnimPreview = new LLPreviewAnimation(256, 256);
-
// motion will be returned, but it will be in a load-pending state, as this is a new motion
// this motion will not request an asset transfer until next update, so we have a chance to
// load the keyframe data locally
@@ -280,9 +289,12 @@ BOOL LLFloaterBvhPreview::postBuild()
LLDataPackerBinaryBuffer dp(buffer, buffer_size);
// pass animation data through memory buffer
+ LL_INFOS("BVH") << "Serializing loaderp" << LL_ENDL;
loaderp->serialize(dp);
dp.reset();
+ LL_INFOS("BVH") << "Deserializing motionp" << LL_ENDL;
BOOL success = motionp && motionp->deserialize(dp);
+ LL_INFOS("BVH") << "Done" << LL_ENDL;
delete []buffer;
diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h
index b81cc6e3a5..20d15d9603 100755
--- a/indra/newview/llfloaterbvhpreview.h
+++ b/indra/newview/llfloaterbvhpreview.h
@@ -109,7 +109,9 @@ public:
S32 status, LLExtStat ext_status);
private:
void setAnimCallbacks() ;
-
+ std::map <std::string, std::string> getJointAliases();
+
+
protected:
void draw();
void resetMotion();
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 57d69589d3..4170d42a3e 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -42,7 +42,6 @@
#include "llcombobox.h"
#include "lldatapacker.h"
#include "lldrawable.h"
-#include "lldrawpoolavatar.h"
#include "llrender.h"
#include "llface.h"
#include "lleconomy.h"
@@ -54,6 +53,7 @@
#include "llmeshrepository.h"
#include "llnotificationsutil.h"
#include "llsdutil_math.h"
+#include "llskinningutil.h"
#include "lltextbox.h"
#include "lltoolmgr.h"
#include "llui.h"
@@ -1190,7 +1190,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
, mModelNoErrors( true )
-, mRigParityWithScene( false )
, mLastJointUpdate( false )
{
mNeedsUpdate = TRUE;
@@ -1723,6 +1722,20 @@ void LLModelPreview::clearModel(S32 lod)
mScene[lod].clear();
}
+void LLModelPreview::getJointAliases( JointMap& joint_map)
+{
+ // Get all standard skeleton joints from the preview avatar.
+ LLVOAvatar *av = getPreviewAvatar();
+
+ //Joint names and aliases come from avatar_skeleton.xml
+
+ joint_map = av->getJointAliases();
+ for (S32 i = 0; i < av->mNumCollisionVolumes; i++)
+ {
+ joint_map[av->mCollisionVolumes[i].getName()] = av->mCollisionVolumes[i].getName();
+ }
+}
+
void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm)
{
assert_main_thread();
@@ -1765,6 +1778,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
clearGLODGroup();
}
+ std::map<std::string, std::string> joint_alias_map;
+ getJointAliases(joint_alias_map);
+
mModelLoader = new LLDAELoader(
filename,
lod,
@@ -1775,6 +1791,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
this,
mJointTransformMap,
mJointsFromNode,
+ joint_alias_map,
+ LLSkinningUtil::getMaxJointCount(),
gSavedSettings.getU32("ImporterModelLimit"),
gSavedSettings.getBOOL("ImporterPreprocessDAE"));
@@ -3360,19 +3378,6 @@ void LLModelPreview::update()
}
//-----------------------------------------------------------------------------
-// getTranslationForJointOffset()
-//-----------------------------------------------------------------------------
-LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint )
-{
- LLMatrix4 jointTransform;
- if ( mJointTransformMap.find( joint ) != mJointTransformMap.end() )
- {
- jointTransform = mJointTransformMap[joint];
- return jointTransform.getTranslation();
- }
- return LLVector3(0.0f,0.0f,0.0f);
-}
-//-----------------------------------------------------------------------------
// createPreviewAvatar
//-----------------------------------------------------------------------------
void LLModelPreview::createPreviewAvatar( void )
@@ -3501,6 +3506,7 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget )
pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() );
}
+
//-----------------------------------------------------------------------------
// render()
//-----------------------------------------------------------------------------
@@ -3998,20 +4004,6 @@ BOOL LLModelPreview::render()
LLVector3::z_axis, // up
target_pos); // point of interest
- if (joint_positions)
- {
- LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
- if (shader)
- {
- gDebugProgram.bind();
- }
- getPreviewAvatar()->renderCollisionVolumes();
- if (shader)
- {
- shader->bind();
- }
- }
-
for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
{
for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
@@ -4036,58 +4028,32 @@ BOOL LLModelPreview::render()
//quick 'n dirty software vertex skinning
//build matrix palette
-
- LLMatrix4 mat[64];
- for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)
- {
- LLJoint* joint = getPreviewAvatar()->getJoint(model->mSkinInfo.mJointNames[j]);
- if (joint)
- {
- mat[j] = model->mSkinInfo.mInvBindMatrix[j];
- mat[j] *= joint->getWorldMatrix();
- }
- }
+ LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+ const LLMeshSkinInfo *skin = &model->mSkinInfo;
+ U32 count = LLSkinningUtil::getMeshJointCount(skin);
+ LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count,
+ skin, getPreviewAvatar());
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+ U32 max_joints = LLSkinningUtil::getMaxJointCount();
for (U32 j = 0; j < buffer->getNumVerts(); ++j)
{
- LLMatrix4 final_mat;
- final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f;
-
- LLVector4 wght;
- S32 idx[4];
-
- F32 scale = 0.f;
- for (U32 k = 0; k < 4; k++)
- {
- F32 w = weight[j].mV[k];
-
- idx[k] = (S32) floorf(w);
- wght.mV[k] = w - floorf(w);
- scale += wght.mV[k];
- }
-
- wght *= 1.f/scale;
-
- for (U32 k = 0; k < 4; k++)
- {
- F32* src = (F32*) mat[idx[k]].mMatrix;
- F32* dst = (F32*) final_mat.mMatrix;
-
- F32 w = wght.mV[k];
-
- for (U32 l = 0; l < 16; l++)
- {
- dst[l] += src[l]*w;
- }
- }
+ LLMatrix4a final_mat;
+ F32 *wptr = weight[j].mV;
+ LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints);
//VECTORIZE THIS
- LLVector3 v(face.mPositions[j].getF32ptr());
+ LLVector4a& v = face.mPositions[j];
- v = v * model->mSkinInfo.mBindShapeMatrix;
- v = v * final_mat;
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
- position[j] = v;
+ position[j][0] = dst[0];
+ position[j][1] = dst[1];
+ position[j][2] = dst[2];
}
llassert(model->mMaterialList.size() > i);
@@ -4121,6 +4087,22 @@ BOOL LLModelPreview::render()
}
}
}
+
+ if (joint_positions)
+ {
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ gDebugProgram.bind();
+ }
+ getPreviewAvatar()->renderCollisionVolumes();
+ getPreviewAvatar()->renderBones();
+ if (shader)
+ {
+ shader->bind();
+ }
+ }
+
}
}
@@ -4257,7 +4239,14 @@ void LLFloaterModelPreview::refresh()
}
//static
-void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata )
+void LLModelPreview::textureLoadedCallback(
+ BOOL success,
+ LLViewerFetchedTexture *src_vi,
+ LLImageRaw* src,
+ LLImageRaw* src_aux,
+ S32 discard_level,
+ BOOL final,
+ void* userdata )
{
LLModelPreview* preview = (LLModelPreview*) userdata;
preview->refresh();
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index b2bb15ef05..0930b7bed2 100755
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -259,6 +259,7 @@ public:
virtual BOOL needsRender() { return mNeedsUpdate; }
void setPreviewLOD(S32 lod);
void clearModel(S32 lod);
+ void getJointAliases(JointMap& joint_map);
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
void loadModelCallback(S32 lod);
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
@@ -299,11 +300,7 @@ public:
void setLoadState( U32 state ) { mLoadState = state; }
U32 getLoadState() { return mLoadState; }
- void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
- const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
- LLVector3 getTranslationForJointOffset( std::string joint );
-
static bool sIgnoreLoadedCallback;
std::vector<S32> mLodsQuery;
@@ -351,7 +348,6 @@ private:
bool mLoading;
U32 mLoadState;
bool mResetJoints;
- bool mRigParityWithScene;
bool mModelNoErrors;
std::map<std::string, bool> mViewOption;
@@ -409,7 +405,7 @@ private:
bool mLastJointUpdate;
- JointSet mJointsFromNode;
+ JointNameSet mJointsFromNode;
JointTransformMap mJointTransformMap;
LLPointer<LLVOAvatar> mPreviewAvatar;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 5571a9f39c..b3dd395e8a 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -348,6 +348,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.HardwareSettings", boost::bind(&LLFloaterPreference::onOpenHardwareSettings, this));
mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this));
mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreference::onVertexShaderEnable, this));
+ mCommitCallbackRegistrar.add("Pref.EnhancedSkeletonEnable", boost::bind(&LLFloaterPreference::onEnhancedSkeletonEnable, this, _1));
mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this));
mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this));
mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));
@@ -760,6 +761,16 @@ void LLFloaterPreference::onVertexShaderEnable()
refreshEnabledGraphics();
}
+void LLFloaterPreference::onEnhancedSkeletonEnable(LLUICtrl *ctrl)
+{
+ bool enabled = ctrl->getValue().asBoolean();
+ bool curr_enabled = gSavedSettings.getBOOL("IncludeEnhancedSkeleton");
+ if (enabled != curr_enabled)
+ {
+ gSavedSettings.setBOOL("IncludeEnhancedSkeleton",enabled);
+ }
+}
+
//static
void LLFloaterPreference::initDoNotDisturbResponse()
{
@@ -1128,7 +1139,11 @@ void LLFloaterPreference::refreshEnabledState()
bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE);
radio_reflection_detail->setEnabled(reflections);
-
+
+ LLCheckBoxCtrl* ctrl_enhanced_skel = getChild<LLCheckBoxCtrl>("AvatarEnhancedSkeleton");
+ bool enhanced_skel_enabled = gSavedSettings.getBOOL("IncludeEnhancedSkeleton");
+ ctrl_enhanced_skel->setValue(enhanced_skel_enabled);
+
// Avatar Mode
// Enable Avatar Shaders
LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
@@ -1707,7 +1722,7 @@ void LLFloaterPreference::onClickAutoReplace()
void LLFloaterPreference::onClickSpellChecker()
{
- LLFloaterReg::showInstance("prefs_spellchecker");
+ LLFloaterReg::showInstance("prefs_spellchecker");
}
void LLFloaterPreference::onClickActionChange()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 04e5e37731..c6d6723d78 100755
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -116,6 +116,8 @@ protected:
void setHardwareDefaults();
// callback for when client turns on shaders
void onVertexShaderEnable();
+ // callback for when enhanced skeleton support checkbox toggled.
+ void onEnhancedSkeletonEnable(LLUICtrl *ctrl);
// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
void onClickActionChange();
diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp
index 35ac0537a3..fb40af1302 100755
--- a/indra/newview/llpreviewanim.cpp
+++ b/indra/newview/llpreviewanim.cpp
@@ -37,6 +37,7 @@
#include "lllineeditor.h"
#include "lluictrlfactory.h"
#include "lluictrlfactory.h"
+#include "lldatapacker.h"
extern LLAgent gAgent;
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
new file mode 100644
index 0000000000..8beb485a0f
--- /dev/null
+++ b/indra/newview/llskinningutil.cpp
@@ -0,0 +1,357 @@
+/**
+* @file llskinningutil.cpp
+* @brief Functions for mesh object skinning
+* @author vir@lindenlab.com
+*
+* $LicenseInfo:firstyear=2015&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2015, 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 "llviewerprecompiledheaders.h"
+
+#include "llskinningutil.h"
+#include "llvoavatar.h"
+#include "llviewercontrol.h"
+#include "llmeshrepository.h"
+
+bool LLSkinningUtil::sIncludeEnhancedSkeleton = true;
+
+namespace {
+
+bool get_name_index(const std::string& name, std::vector<std::string>& names, U32& result)
+{
+ std::vector<std::string>::const_iterator find_it =
+ std::find(names.begin(), names.end(), name);
+ if (find_it != names.end())
+ {
+ result = find_it - names.begin();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Find a name table index that is also a valid joint on the
+// avatar. Order of preference is: requested name, mPelvis, first
+// valid match in names table.
+U32 get_valid_joint_index(const std::string& name, LLVOAvatar *avatar, std::vector<std::string>& joint_names)
+{
+ U32 result;
+ if (avatar->getJoint(name) && get_name_index(name,joint_names,result))
+ {
+ return result;
+ }
+ if (get_name_index("mPelvis",joint_names,result))
+ {
+ return result;
+ }
+ for (U32 j=0; j<joint_names.size(); j++)
+ {
+ if (avatar->getJoint(joint_names[j]))
+ {
+ return j;
+ }
+ }
+ // BENTO how to handle?
+ LL_ERRS() << "no valid joints in joint_names" << LL_ENDL;
+ return 0;
+}
+
+// Which joint will stand in for this joint?
+U32 get_proxy_joint_index(U32 joint_index, LLVOAvatar *avatar, std::vector<std::string>& joint_names)
+{
+ bool include_enhanced = LLSkinningUtil::sIncludeEnhancedSkeleton;
+ U32 j_proxy = get_valid_joint_index(joint_names[joint_index], avatar, joint_names);
+ LLJoint *joint = avatar->getJoint(joint_names[j_proxy]);
+ llassert(joint);
+ // Find the first ancestor that's not flagged as extended, or the
+ // last ancestor that's rigged in this mesh, whichever
+ // comes first.
+ while (1)
+ {
+ if (include_enhanced ||
+ joint->getSupport()==LLJoint::SUPPORT_BASE)
+ break;
+ LLJoint *parent = joint->getParent();
+ if (!parent)
+ break;
+ if (!get_name_index(parent->getName(), joint_names, j_proxy))
+ {
+ break;
+ }
+ joint = parent;
+ }
+ return j_proxy;
+}
+
+}
+
+// static
+void LLSkinningUtil::initClass()
+{
+ sIncludeEnhancedSkeleton = gSavedSettings.getBOOL("IncludeEnhancedSkeleton");
+}
+
+// static
+U32 LLSkinningUtil::getMaxJointCount()
+{
+ U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT;
+ if (!sIncludeEnhancedSkeleton)
+ {
+ // BENTO - currently the remap logic does not guarantee joint count <= 52;
+ // if one of the base ancestors is not rigged in a given mesh, an extended
+ // joint can still be included.
+ result = llmin(result,(U32)52);
+ }
+ return result;
+}
+
+// static
+U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
+{
+ return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
+}
+
+// static
+
+// Destructively remap the joints in skin info based on what joints
+// are known in the avatar, and which are currently supported. This
+// will also populate mJointRemap[] in the skin, which can be used to
+// make the corresponding changes to the integer part of vertex
+// weights.
+//
+// This will throw away joint info for any joints that are not known
+// in the avatar, or not currently flagged to support based on the
+// debug setting for IncludeEnhancedSkeleton.
+//
+
+// BENTO maybe this really only makes sense for new leaf joints? New spine
+// joints may need different logic.
+
+// static
+void LLSkinningUtil::remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
+{
+ // skip if already done.
+ if (!skin->mJointRemap.empty())
+ {
+ return;
+ }
+
+ U32 max_joints = getMeshJointCount(skin);
+
+ // Compute the remap
+ std::vector<U32> j_proxy(skin->mJointNames.size());
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ U32 j_rep = get_proxy_joint_index(j, avatar, skin->mJointNames);
+ j_proxy[j] = j_rep;
+ }
+ S32 top = 0;
+ std::vector<U32> j_remap(skin->mJointNames.size());
+ // Fill in j_remap for all joints that will be kept.
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ if (j_proxy[j] == j)
+ {
+ // Joint will be included
+ j_remap[j] = top;
+ if (top < max_joints-1)
+ {
+ top++;
+ }
+
+
+ }
+ }
+ // Then use j_proxy to fill in j_remap for the joints that will be discarded
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ if (j_proxy[j] != j)
+ {
+ j_remap[j] = j_remap[j_proxy[j]];
+ }
+ }
+
+
+ // Apply the remap to mJointNames, mInvBindMatrix, and mAlternateBindMatrix
+ std::vector<std::string> new_joint_names;
+ std::vector<LLMatrix4> new_inv_bind_matrix;
+ std::vector<LLMatrix4> new_alternate_bind_matrix;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ if (j_proxy[j] == j && new_joint_names.size() < max_joints)
+ {
+ new_joint_names.push_back(skin->mJointNames[j]);
+ new_inv_bind_matrix.push_back(skin->mInvBindMatrix[j]);
+ if (!skin->mAlternateBindMatrix.empty())
+ {
+ new_alternate_bind_matrix.push_back(skin->mAlternateBindMatrix[j]);
+ }
+ }
+ }
+ llassert(new_joint_names.size() <= max_joints);
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ if (skin->mJointNames[j] != new_joint_names[j_remap[j]])
+ {
+ LL_DEBUGS("Avatar") << "Starting joint[" << j << "] = " << skin->mJointNames[j] << " j_remap " << j_remap[j] << " ==> " << new_joint_names[j_remap[j]] << LL_ENDL;
+ }
+ }
+
+ skin->mJointNames = new_joint_names;
+ skin->mInvBindMatrix = new_inv_bind_matrix;
+ skin->mAlternateBindMatrix = new_alternate_bind_matrix;
+ skin->mJointRemap = j_remap;
+}
+
+// static
+void LLSkinningUtil::initSkinningMatrixPalette(
+ LLMatrix4* mat,
+ S32 count,
+ const LLMeshSkinInfo* skin,
+ LLVOAvatar *avatar)
+{
+ // BENTO - switching to use Matrix4a and SSE might speed this up.
+ // Note that we are mostly passing Matrix4a's to this routine anyway, just dubiously casted.
+ for (U32 j = 0; j < count; ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ mat[j] = skin->mInvBindMatrix[j];
+ if (joint)
+ {
+ mat[j] *= joint->getWorldMatrix();
+ }
+ else
+ {
+ // This shouldn't happen - in mesh upload, skinned
+ // rendering should be disabled unless all joints are
+ // valid. In other cases of skinned rendering, invalid
+ // joints should already have been removed during remap.
+ LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL;
+ }
+ }
+}
+
+// Transform the weights based on the remap info stored in skin. Note
+// that this is destructive and non-idempotent, so we need to keep
+// track of whether we've done it already. If the desired remapping
+// changes, the viewer must be restarted.
+//
+// static
+void LLSkinningUtil::remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
+{
+ llassert(skin->mJointRemap.size()>0); // Must call remapSkinInfoJoints() first, which this checks for.
+ const U32* remap = &skin->mJointRemap[0];
+ const S32 max_joints = skin->mJointNames.size();
+ for (U32 j=0; j<num_vertices; j++)
+ {
+ F32 *w = weights[j].getF32ptr();
+
+ for (U32 k=0; k<4; ++k)
+ {
+ S32 i = llfloor(w[k]);
+ F32 f = w[k]-i;
+ i = llclamp(i,0,max_joints-1);
+ w[k] = remap[i] + f;
+ }
+ }
+}
+
+// static
+void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
+{
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ const S32 max_joints = skin->mJointNames.size();
+ if (skin->mJointRemap.size()>0)
+ {
+ // Check the weights are consistent with the current remap.
+ for (U32 j=0; j<num_vertices; j++)
+ {
+ F32 *w = weights[j].getF32ptr();
+
+ for (U32 k=0; k<4; ++k)
+ {
+ S32 i = llfloor(w[k]);
+ llassert(i>=0);
+ llassert(i<max_joints);
+ }
+ }
+ }
+#endif
+}
+
+// static
+void LLSkinningUtil::getPerVertexSkinMatrix(
+ F32* weights,
+ LLMatrix4a* mat,
+ bool handle_bad_scale,
+ LLMatrix4a& final_mat,
+ U32 max_joints)
+{
+
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weights[k];
+
+ // BENTO potential optimizations
+ // - Do clamping in unpackVolumeFaces() (once instead of every time)
+ // - int vs floor: if we know w is
+ // >= 0.0, we can use int instead of floorf; the latter
+ // allegedly has a lot of overhead due to ieeefp error
+ // checking which we should not need.
+ idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)max_joints-1);
+
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+ if (handle_bad_scale && scale <= 0.f)
+ {
+ wght = LLVector4(1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ // This is enforced in unpackVolumeFaces()
+ llassert(scale>0.f);
+ wght *= 1.f/scale;
+ }
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mat[idx[k]], w);
+
+ final_mat.add(src);
+ }
+}
+
diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h
new file mode 100644
index 0000000000..9a28100dc3
--- /dev/null
+++ b/indra/newview/llskinningutil.h
@@ -0,0 +1,50 @@
+/**
+* @file llskinningutil.h
+* @brief Functions for mesh object skinning
+* @author vir@lindenlab.com
+*
+* $LicenseInfo:firstyear=2015&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2015, 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 LLSKINNINGUTIL_H
+#define LLSKINNINGUTIL_H
+
+class LLVOAvatar;
+class LLMeshSkinInfo;
+class LLMatrix4a;
+
+class LLSkinningUtil
+{
+public:
+ static void initClass();
+ static U32 getMaxJointCount();
+ static U32 getMeshJointCount(const LLMeshSkinInfo *skin);
+ static void remapSkinInfoJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
+ static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
+ static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
+ static void remapSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
+ static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
+
+ // This is initialized from gSavedSettings at startup and then left alone.
+ static bool sIncludeEnhancedSkeleton;
+};
+
+#endif
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 22944493c9..24ac302325 100755
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -3216,6 +3216,11 @@ void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
avatar->renderCollisionVolumes();
}
+void renderAvatarBones(LLVOAvatar* avatar)
+{
+ avatar->renderBones();
+}
+
void renderAgentTarget(LLVOAvatar* avatar)
{
// render these for self only (why, i don't know)
@@ -3374,6 +3379,11 @@ public:
renderAvatarCollisionVolumes(avatar);
}
+ if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS))
+ {
+ renderAvatarBones(avatar);
+ }
+
if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
{
renderAgentTarget(avatar);
@@ -3664,6 +3674,7 @@ void LLSpatialPartition::renderDebug()
LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
LLPipeline::RENDER_DEBUG_RAYCAST |
LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
+ LLPipeline::RENDER_DEBUG_AVATAR_JOINTS |
LLPipeline::RENDER_DEBUG_AGENT_TARGET |
//LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8a027fdbfa..d62cf3caab 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -28,6 +28,7 @@
#include "llappviewer.h"
#include "llstartup.h"
+#include "llcallstack.h"
#if LL_WINDOWS
# include <process.h> // _spawnl()
@@ -197,6 +198,8 @@
#include "lltoolbarview.h"
#include "llexperiencelog.h"
+#include "llstacktrace.h"
+
#if LL_WINDOWS
#include "lldxhardware.h"
#endif
@@ -1258,7 +1261,7 @@ bool idle_startup()
LLPostProcess::initClass();
display_startup();
- LLAvatarAppearance::initClass();
+ LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml");
display_startup();
LLViewerObject::initVOClasses();
diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp
index fd950864aa..01d799dcd5 100755
--- a/indra/newview/lltoolbarview.cpp
+++ b/indra/newview/lltoolbarview.cpp
@@ -283,7 +283,7 @@ bool LLToolBarView::loadToolbars(bool force_default)
}
BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.left_toolbar.commands)
{
- if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_LEFT]))
+ if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_LEFT]))
{
LL_WARNS() << "Error adding command '" << command_params.name() << "' to left toolbar." << LL_ENDL;
}
@@ -298,7 +298,7 @@ bool LLToolBarView::loadToolbars(bool force_default)
}
BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.right_toolbar.commands)
{
- if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_RIGHT]))
+ if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_RIGHT]))
{
LL_WARNS() << "Error adding command '" << command_params.name() << "' to right toolbar." << LL_ENDL;
}
@@ -313,7 +313,7 @@ bool LLToolBarView::loadToolbars(bool force_default)
}
BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.bottom_toolbar.commands)
{
- if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM]))
+ if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM]))
{
LL_WARNS() << "Error adding command '" << command_params.name() << "' to bottom toolbar." << LL_ENDL;
}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 5020518454..3532a872c9 100755
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -67,6 +67,7 @@
#include "llvowlsky.h"
#include "llrender.h"
#include "llnavigationbar.h"
+#include "llnotificationsutil.h"
#include "llfloatertools.h"
#include "llpaneloutfitsinventory.h"
#include "llpanellogin.h"
@@ -119,6 +120,19 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue)
}
+static bool handleDebugAvatarJointsChanged(const LLSD& newvalue)
+{
+ std::string new_string = newvalue.asString();
+ LLJoint::setDebugJointNames(new_string);
+ return true;
+}
+
+static bool handleDeferredDebugSettingChanged(const LLSD& newvalue)
+{
+ LLNotificationsUtil::add("ChangeDeferredDebugSetting");
+ return true;
+}
+
static bool handleSetShaderChanged(const LLSD& newvalue)
{
// changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache
@@ -761,6 +775,8 @@ void settings_setup_listeners()
gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged));
gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged));
+ gSavedSettings.getControl("IncludeEnhancedSkeleton")->getCommitSignal()->connect(boost::bind(&handleDeferredDebugSettingChanged, _2));
+ gSavedSettings.getControl("DebugAvatarJoints")->getCommitSignal()->connect(boost::bind(&handleDebugAvatarJointsChanged, _2));
}
#if TEST_CACHED_CONTROL
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index e46299f9d2..b7bd131246 100755
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -48,14 +48,13 @@ LLViewerJoint::LLViewerJoint() :
LLAvatarJoint()
{ }
-LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) :
- LLAvatarJoint(name, parent)
-{ }
-
LLViewerJoint::LLViewerJoint(S32 joint_num) :
LLAvatarJoint(joint_num)
{ }
+LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) :
+ LLAvatarJoint(name, parent)
+{ }
//-----------------------------------------------------------------------------
// ~LLViewerJoint()
diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h
index fd262b6e80..abe11bbf5c 100755
--- a/indra/newview/llviewerjoint.h
+++ b/indra/newview/llviewerjoint.h
@@ -44,7 +44,8 @@ class LLViewerJoint :
{
public:
LLViewerJoint();
- LLViewerJoint(S32 joint_num);
+ LLViewerJoint(S32 joint_num);
+
// *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
LLViewerJoint(const std::string &name, LLJoint *parent = NULL);
virtual ~LLViewerJoint();
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 888decd3be..66e392ac42 100755
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -352,6 +352,7 @@ void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible)
void LLViewerJointAttachment::setOriginalPosition(LLVector3& position)
{
mOriginalPos = position;
+ // SL-315
setPosition(position);
}
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index bf7cf08c63..43a81ada49 100755
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -203,7 +203,7 @@ void LLViewerJointMesh::uploadJointMatrices()
// DrawElementsBLEND and utility code
//--------------------------------------------------------------------
-// compate_int is used by the qsort function to sort the index array
+// compare_int is used by the qsort function to sort the index array
int compare_int(const void *a, const void *b)
{
if (*(U32*)a < *(U32*)b)
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index de219edcff..fefbcabb2b 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -187,10 +187,10 @@ LLMenuGL* gDetachSubMenu = NULL;
LLMenuGL* gTakeOffClothes = NULL;
LLContextMenu* gAttachScreenPieMenu = NULL;
LLContextMenu* gAttachPieMenu = NULL;
-LLContextMenu* gAttachBodyPartPieMenus[8];
+LLContextMenu* gAttachBodyPartPieMenus[9];
LLContextMenu* gDetachPieMenu = NULL;
LLContextMenu* gDetachScreenPieMenu = NULL;
-LLContextMenu* gDetachBodyPartPieMenus[8];
+LLContextMenu* gDetachBodyPartPieMenus[9];
//
// Local prototypes
@@ -6031,6 +6031,18 @@ class LLAvatarToggleMyProfile : public view_listener_t
}
};
+class LLAvatarResetSkeleton: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ avatar->resetSkeleton();
+ }
+ return true;
+ }
+};
class LLAvatarAddContact : public view_listener_t
{
@@ -9017,6 +9029,7 @@ void initialize_menus()
enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
+ view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible));
commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL")));
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index b7bdf00157..8ce3c69787 100755
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -188,8 +188,8 @@ extern LLContextMenu* gAttachScreenPieMenu;
extern LLContextMenu* gDetachScreenPieMenu;
extern LLContextMenu* gAttachPieMenu;
extern LLContextMenu* gDetachPieMenu;
-extern LLContextMenu* gAttachBodyPartPieMenus[8];
-extern LLContextMenu* gDetachBodyPartPieMenus[8];
+extern LLContextMenu* gAttachBodyPartPieMenus[9];
+extern LLContextMenu* gDetachBodyPartPieMenus[9];
extern LLMenuItemCallGL* gMutePieMenu;
extern LLMenuItemCallGL* gMuteObjectPieMenu;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index dafe2cafec..3e0cec0f09 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -27,6 +27,8 @@
#include "llviewerprecompiledheaders.h"
+#include <boost/lexical_cast.hpp>
+
#include "llfeaturemanager.h"
#include "llviewershadermgr.h"
@@ -41,6 +43,8 @@
#include "llsky.h"
#include "llvosky.h"
#include "llrender.h"
+#include "lljoint.h"
+#include "llskinningutil.h"
#ifdef LL_RELEASE_FOR_DOWNLOAD
#define UNIFORM_ERRS LL_WARNS_ONCE("Shader")
@@ -871,7 +875,9 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) );
boost::unordered_map<std::string, std::string> attribs;
-
+ attribs["MAX_JOINTS_PER_MESH_OBJECT"] =
+ boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount());
+
// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
for (U32 i = 0; i < shaders.size(); i++)
{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 4efad480f1..61df144227 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -105,6 +105,8 @@
#include "llsdutil.h"
#include "llscenemonitor.h"
#include "llsdserialize.h"
+#include "llcallstack.h"
+#include "llrendersphere.h"
extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
@@ -213,24 +215,6 @@ struct LLTextureMaskData
**
**/
-//------------------------------------------------------------------------
-// LLVOAvatarBoneInfo
-// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
-//------------------------------------------------------------------------
-struct LLVOAvatarCollisionVolumeInfo : public LLInitParam::Block<LLVOAvatarCollisionVolumeInfo>
-{
- LLVOAvatarCollisionVolumeInfo()
- : name("name"),
- pos("pos"),
- rot("rot"),
- scale("scale")
- {}
-
- Mandatory<std::string> name;
- Mandatory<LLVector3> pos,
- rot,
- scale;
-};
struct LLAppearanceMessageContents
{
@@ -252,49 +236,6 @@ struct LLAppearanceMessageContents
bool mHoverOffsetWasSet;
};
-struct LLVOAvatarChildJoint : public LLInitParam::ChoiceBlock<LLVOAvatarChildJoint>
- {
- Alternative<Lazy<struct LLVOAvatarBoneInfo, IS_A_BLOCK> > bone;
- Alternative<LLVOAvatarCollisionVolumeInfo> collision_volume;
-
- LLVOAvatarChildJoint()
- : bone("bone"),
- collision_volume("collision_volume")
- {}
-};
-
-
-
-struct LLVOAvatarBoneInfo : public LLInitParam::Block<LLVOAvatarBoneInfo, LLVOAvatarCollisionVolumeInfo>
-{
- LLVOAvatarBoneInfo()
- : pivot("pivot")
- {}
-
- Mandatory<LLVector3> pivot;
- Multiple<LLVOAvatarChildJoint> children;
-};
-
-//------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo
-// Overall avatar skeleton
-//------------------------------------------------------------------------
-struct LLVOAvatarSkeletonInfo : public LLInitParam::Block<LLVOAvatarSkeletonInfo>
-{
- LLVOAvatarSkeletonInfo()
- : skeleton_root(""),
- num_bones("num_bones"),
- num_collision_volumes("num_collision_volumes"),
- version("version")
- {}
-
- Mandatory<std::string> version;
- Mandatory<S32> num_bones,
- num_collision_volumes;
- Mandatory<LLVOAvatarChildJoint> skeleton_root;
-};
-
-
//-----------------------------------------------------------------------------
// class LLBodyNoiseMotion
@@ -1114,7 +1055,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll)
{
if (LLViewerTexLayerSet::sHasCaches)
{
- LL_DEBUGS() << "Deleting layer set caches" << LL_ENDL;
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
iter != LLCharacter::sInstances.end(); ++iter)
{
@@ -1145,6 +1085,9 @@ void LLVOAvatar::initClass()
gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix");
gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target");
gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust");
+
+ // Where should this be set initially?
+ LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints"));
}
@@ -1398,18 +1341,78 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
newMax.add(buffer);
}
+void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color)
+{
+ // Unoccluded bone portions
+ LLGLDepthTest normal_depth(GL_TRUE);
+
+ // Draw line segment for unoccluded joint
+ gGL.diffuseColor3f(visible_color[0], visible_color[1], visible_color[2]);
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(begin_pos.mV);
+ gGL.vertex3fv(end_pos.mV);
+ gGL.end();
+
+
+ // Draw sphere representing joint pos
+ gGL.pushMatrix();
+ gGL.scalef(sphere_scale, sphere_scale, sphere_scale);
+ gSphere.renderGGL();
+ gGL.popMatrix();
+
+ LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ // Occluded bone portions
+ gGL.diffuseColor3f(occ_color[0], occ_color[1], occ_color[2]);
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(begin_pos.mV);
+ gGL.vertex3fv(end_pos.mV);
+ gGL.end();
+
+ // Draw sphere representing joint pos
+ gGL.pushMatrix();
+ gGL.scalef(sphere_scale, sphere_scale, sphere_scale);
+ gSphere.renderGGL();
+ gGL.popMatrix();
+}
+
//-----------------------------------------------------------------------------
// renderCollisionVolumes()
//-----------------------------------------------------------------------------
void LLVOAvatar::renderCollisionVolumes()
{
std::ostringstream ostr;
+
for (S32 i = 0; i < mNumCollisionVolumes; i++)
{
- mCollisionVolumes[i].renderCollision();
ostr << mCollisionVolumes[i].getName() << ", ";
- }
+ LLAvatarJointCollisionVolume& collision_volume = mCollisionVolumes[i];
+
+ collision_volume.updateWorldMatrix();
+
+ gGL.pushMatrix();
+ gGL.multMatrix( &collision_volume.getXform()->getWorldMatrix().mMatrix[0][0] );
+
+ LLVector3 begin_pos(0,0,0);
+ LLVector3 end_pos(collision_volume.getEnd());
+ static F32 sphere_scale = 1.0f;
+ static F32 center_dot_scale = 0.05f;
+
+ static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f);
+ static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f);
+ static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f);
+ static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f);
+
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE);
+ render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE);
+
+ gGL.popMatrix();
+ }
+
+
if (mNameText.notNull())
{
LLVector4a unused;
@@ -1421,6 +1424,67 @@ void LLVOAvatar::renderCollisionVolumes()
addDebugText(ostr.str());
}
+void LLVOAvatar::renderBones()
+{
+
+ LLGLEnable blend(GL_BLEND);
+
+ std::ostringstream ostr;
+ std::ostringstream nullstr;
+
+ avatar_joint_list_t::iterator iter = mSkeleton.begin();
+ avatar_joint_list_t::iterator end = mSkeleton.end();
+
+ static LLVector3 BASE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f);
+ static LLVector3 BASE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
+ static LLVector3 EXTENDED_COLOR_OCCLUDED(0.0f, 1.0f, 0.0f);
+ static LLVector3 EXTENDED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
+
+ static F32 SPHERE_SCALEF = 0.003f;
+
+ for (; iter != end; ++iter)
+ {
+ LLJoint* jointp = *iter;
+ if (!jointp)
+ {
+ continue;
+ }
+
+ ostr << jointp->getName() << ", ";
+
+ jointp->updateWorldMatrix();
+ LLJoint::SupportCategory sc = jointp->getSupport();
+ LLVector3 occ_color, visible_color;
+
+ if (sc == LLJoint::SUPPORT_BASE)
+ {
+ occ_color = BASE_COLOR_OCCLUDED;
+ visible_color = BASE_COLOR_VISIBLE;
+ }
+ else
+ {
+ occ_color = EXTENDED_COLOR_OCCLUDED;
+ visible_color = EXTENDED_COLOR_VISIBLE;
+ }
+ LLVector3 begin_pos(0,0,0);
+ LLVector3 end_pos(jointp->getEnd());
+
+ F32 sphere_scale = SPHERE_SCALEF;
+
+ gGL.pushMatrix();
+ gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] );
+
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, occ_color, visible_color);
+
+ gGL.popMatrix();
+ }
+
+ mDebugText.clear();
+ addDebugText(ostr.str());
+ addDebugText(nullstr.str());
+}
+
+
void LLVOAvatar::renderJoints()
{
std::ostringstream ostr;
@@ -1528,7 +1592,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
for (S32 i = 0; i < mNumCollisionVolumes; ++i)
{
mCollisionVolumes[i].updateWorldMatrix();
-
+
glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix);
glh::matrix4f inverse = mat.inverse();
glh::matrix4f norm_mat = inverse.transpose();
@@ -1737,6 +1801,34 @@ void LLVOAvatar::buildCharacter()
mMeshValid = TRUE;
}
+//-----------------------------------------------------------------------------
+// resetSkeleton()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetSkeleton()
+{
+ LL_DEBUGS("Avatar") << avString() << LL_ENDL;
+
+ // Reset params
+ for (LLVisualParam *param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ if (param->isAnimating())
+ {
+ continue;
+ }
+ param->setLastWeight(param->getDefaultWeight());
+ }
+
+ // Reset all bones and collision volumes to their initial skeleton state.
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ LL_ERRS() << "Error resetting skeleton" << LL_ENDL;
+ }
+
+ // Apply params
+ updateVisualParams();
+}
//-----------------------------------------------------------------------------
// releaseMeshData()
@@ -1748,8 +1840,6 @@ void LLVOAvatar::releaseMeshData()
return;
}
- LL_DEBUGS() << "Releasing mesh data" << LL_ENDL;
-
// cleanup mesh data
for (avatar_joint_list_t::iterator iter = mMeshLOD.begin();
iter != mMeshLOD.end();
@@ -1959,17 +2049,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
// Do base class updates...
U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
- //LLTEContents tec;
- //S32 te_retval = parseTEMessage(mesgsys, _PREHASH_ObjectData, block_num, tec);
-
- LL_DEBUGS("Avatar") << avString() << update_type << LL_ENDL;
-
// Print out arrival information once we have name of avatar.
- if (has_name && getNVPair("FirstName"))
- {
- mDebugExistenceTimer.reset();
- debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived");
- }
+ if (has_name && getNVPair("FirstName"))
+ {
+ mDebugExistenceTimer.reset();
+ debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived");
+ }
if(retval & LLViewerObject::INVALID_UPDATE)
{
@@ -2077,6 +2162,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
return;
}
+ LLScopedContextString str("avatar_idle_update " + getFullname());
+
checkTextureLoading() ;
// force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
@@ -3078,6 +3165,7 @@ void LLVOAvatar::idleUpdateBelowWater()
void LLVOAvatar::slamPosition()
{
gAgent.setPositionAgent(getPositionAgent());
+ // SL-315
mRoot->setWorldPosition(getPositionAgent()); // teleport
setChanged(TRANSLATED);
if (mDrawable.notNull())
@@ -3430,6 +3518,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
mTimeLast = animation_time;
// put the pelvis at slaved position/mRotation
+ // SL-315
mRoot->setWorldPosition( getPositionAgent() ); // first frame
mRoot->setWorldRotation( getRotation() );
}
@@ -3484,6 +3573,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
if (newPosition != mRoot->getXform()->getWorldPosition())
{
mRoot->touch();
+ // SL-315
mRoot->setWorldPosition( newPosition ); // regular update
}
@@ -3647,6 +3737,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{
LLVector3 pos = mDrawable->getPosition();
pos += getHoverOffset() * mDrawable->getRotation();
+ // SL-315
mRoot->setPosition(pos);
mRoot->setRotation(mDrawable->getRotation());
}
@@ -3677,6 +3768,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
LLVector3 pos = mRoot->getWorldPosition();
pos.mV[VZ] += off_z;
mRoot->touch();
+ // SL-315
mRoot->setWorldPosition(pos);
}
}
@@ -5151,6 +5243,8 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
void LLVOAvatar::clearAttachmentPosOverrides()
{
+ LLScopedContextString str("clearAttachmentPosOverrides " + getFullname());
+
//Subsequent joints are relative to pelvis
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
@@ -5158,7 +5252,10 @@ void LLVOAvatar::clearAttachmentPosOverrides()
for (; iter != end; ++iter)
{
LLJoint* pJoint = (*iter);
- pJoint->clearAttachmentPosOverrides();
+ if (pJoint)
+ {
+ pJoint->clearAttachmentPosOverrides();
+ }
}
}
@@ -5172,7 +5269,9 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
}
-
+
+ LLScopedContextString str("addAttachmentPosOverridesForObject " + av->getFullname());
+
// Process all children
LLViewerObject::const_child_list_t& children = vo->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
@@ -5293,6 +5392,7 @@ void LLVOAvatar::resetJointPositionsOnDetach(const LLUUID& mesh_id)
if ( pJoint && pJoint == pJointPelvis)
{
removePelvisFixup( mesh_id );
+ // SL-315
pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
}
}
@@ -5438,16 +5538,18 @@ BOOL LLVOAvatar::loadSkeletonNode ()
}
LLViewerJointAttachment* attachment = new LLViewerJointAttachment();
-
attachment->setName(info->mName);
- LLJoint *parentJoint = getJoint(info->mJointName);
- if (!parentJoint)
- {
+ LLJoint *parent_joint = getJoint(info->mJointName);
+ if (!parent_joint)
+ {
+ // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt.
LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL;
- delete attachment;
- continue;
- }
-
+ LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL;
+ // If we wanted to continue from this case, we could do:
+ //delete attachment;
+ //continue;
+ // but there's no point.
+ }
if (info->mHasPosition)
{
attachment->setOriginalPosition(info->mPosition);
@@ -5465,7 +5567,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()
int group = info->mGroup;
if (group >= 0)
{
- if (group < 0 || group >= 9)
+ if (group < 0 || group > 9)
{
LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL;
}
@@ -5492,11 +5594,12 @@ BOOL LLVOAvatar::loadSkeletonNode ()
attachment->setPieSlice(info->mPieMenuSlice);
attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
attachment->setIsHUDAttachment(info->mIsHUDAttachment);
-
+ // attachment can potentially be animated, needs a number.
+ attachment->setJointNum(mSkeleton.size() + attachmentID -1);
mAttachmentPoints[attachmentID] = attachment;
// now add attachment joint
- parentJoint->addChild(attachment);
+ parent_joint->addChild(attachment);
}
}
@@ -6069,6 +6172,7 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
// objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
sitDown(TRUE);
mRoot->getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
+ // SL-315
mRoot->setPosition(getPosition());
mRoot->updateWorldMatrixChildren();
@@ -6127,6 +6231,7 @@ void LLVOAvatar::getOffObject()
sitDown(FALSE);
mRoot->getXform()->setParent(NULL); // LLVOAvatar::getOffObject
+ // SL-315
mRoot->setPosition(cur_position_world);
mRoot->setRotation(cur_rotation_world);
mRoot->getXform()->update();
@@ -7233,7 +7338,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
U8 av_u8;
mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, av_u8, 0);
contents.mAppearanceVersion = av_u8;
- LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL;
mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, contents.mCOFVersion, 0);
// For future use:
//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
@@ -7245,7 +7350,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
{
LLVector3 hover;
mesgsys->getVector3Fast(_PREHASH_AppearanceHover, _PREHASH_HoverHeight, hover);
- LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL;
contents.mHoverOffset = hover;
contents.mHoverOffsetWasSet = true;
}
@@ -7255,7 +7360,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
if( num_blocks > 1 && !drop_visual_params_debug)
{
- LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
LLVisualParam* param = getFirstVisualParam();
llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
@@ -7316,7 +7421,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
{
S32 index = it - contents.mParams.begin();
contents.mParamAppearanceVersion = ll_round(contents.mParamWeights[index]);
- LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL;
}
}
}
@@ -7345,9 +7450,9 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
{
appearance_version = 1;
}
- LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
- << " param: " << contents.mParamAppearanceVersion
- << " final: " << appearance_version << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
+ // << " param: " << contents.mParamAppearanceVersion
+ // << " final: " << appearance_version << LL_ENDL;
return true;
}
@@ -7356,8 +7461,6 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
//-----------------------------------------------------------------------------
void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
{
- LL_DEBUGS("Avatar") << "starts" << LL_ENDL;
-
bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
@@ -7401,7 +7504,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
else
{
- LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL;
}
// Check for stale update.
@@ -7465,8 +7568,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
mFirstAppearanceMessageReceived = TRUE;
- LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID
- << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID
+ // << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
if (is_first_appearance_message )
{
@@ -7479,7 +7582,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// Apply visual params
if( num_params > 1)
{
- LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
BOOL params_changed = FALSE;
BOOL interp_params = FALSE;
S32 params_changed_count = 0;
@@ -7710,7 +7813,7 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu
if (selfp)
{
- LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL;
+ //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL;
}
if (!success && selfp)
@@ -7728,14 +7831,14 @@ void LLVOAvatar::onBakedTextureLoaded(BOOL success,
LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src,
S32 discard_level, BOOL final, void* userdata)
{
- LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL;
LLUUID id = src_vi->getID();
LLUUID *avatar_idp = (LLUUID *)userdata;
LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
if (selfp)
{
- LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL;
}
if (selfp && !success)
@@ -7923,6 +8026,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
}
}
+ // Bones
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
for (; iter != end; ++iter)
@@ -7930,10 +8034,33 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
LLJoint* pJoint = (*iter);
const LLVector3& pos = pJoint->getPosition();
const LLVector3& scale = pJoint->getScale();
- apr_file_printf( file, "\t\t<joint name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ apr_file_printf( file, "\t\t<bone name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
}
+ // Collision volumes
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ LLAvatarJointCollisionVolume* pJoint = &mCollisionVolumes[i];
+ const LLVector3& pos = pJoint->getPosition();
+ const LLVector3& scale = pJoint->getScale();
+ apr_file_printf( file, "\t\t<collision_volume name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
+ }
+
+ // Attachment joints
+ for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end(); ++iter)
+ {
+ LLViewerJointAttachment* pJoint = iter->second;
+ if (!pJoint) continue;
+ const LLVector3& pos = pJoint->getPosition();
+ const LLVector3& scale = pJoint->getScale();
+ apr_file_printf( file, "\t\t<attachment_point name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
+ }
+
+ // Joint pos overrides
for (iter = mSkeleton.begin(); iter != end; ++iter)
{
LLJoint* pJoint = (*iter);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 09d8662034..76b40fb90a 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -68,13 +68,11 @@ class LLVoiceVisualizer;
class LLHUDNameTag;
class LLHUDEffectSpiral;
class LLTexGlobalColor;
-struct LLVOAvatarBoneInfo;
-struct LLVOAvatarChildJoint;
-//class LLViewerJoint;
+
struct LLAppearanceMessageContents;
-struct LLVOAvatarSkeletonInfo;
class LLViewerJointMesh;
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLVOAvatar
//
@@ -366,6 +364,7 @@ public:
/*virtual*/ BOOL loadSkeletonNode();
/*virtual*/ void buildCharacter();
+ void resetSkeleton();
LLVector3 mCurRootToHeadOffset;
LLVector3 mTargetRootToHeadOffset;
@@ -403,6 +402,7 @@ public:
F32 getLastSkinTime() { return mLastSkinTime; }
U32 renderTransparent(BOOL first_pass);
void renderCollisionVolumes();
+ void renderBones();
void renderJoints();
static void deleteCachedImages(bool clearAll=true);
static void destroyGL();
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index c1ca0aed69..daf347caa3 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -65,6 +65,7 @@
#include "llsdutil.h"
#include "llstartup.h"
#include "llsdserialize.h"
+#include "llcallstack.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -205,6 +206,7 @@ bool update_avatar_rez_metrics()
return true;
gAgentAvatarp->updateAvatarRezMetrics(false);
+
return false;
}
@@ -232,7 +234,6 @@ void LLVOAvatarSelf::initInstance()
{
mDebugBakedTextureTimes[i][0] = -1.0f;
mDebugBakedTextureTimes[i][1] = -1.0f;
- mInitialBakeIDs[i] = LLUUID::null;
}
status &= buildMenus();
@@ -353,6 +354,7 @@ BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLAvatarSkeletonInfo *info)
F32 aspect = LLViewerCamera::getInstance()->getAspect();
LLVector3 scale(1.f, aspect, 1.f);
mScreenp->setScale(scale);
+ // SL-315
mScreenp->setWorldPosition(LLVector3::zero);
// need to update screen agressively when sidebar opens/closes, for example
mScreenp->mUpdateXform = TRUE;
@@ -394,6 +396,10 @@ BOOL LLVOAvatarSelf::buildMenus()
params.name(params.label);
gAttachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params);
+ params.label(LLTrans::getString("BodyPartsEnhancedSkeleton"));
+ params.name(params.label);
+ gAttachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params);
+
gDetachBodyPartPieMenus[0] = NULL;
params.label(LLTrans::getString("BodyPartsRightArm"));
@@ -422,7 +428,11 @@ BOOL LLVOAvatarSelf::buildMenus()
params.name(params.label);
gDetachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params);
- for (S32 i = 0; i < 8; i++)
+ params.label(LLTrans::getString("BodyPartsEnhancedSkeleton"));
+ params.name(params.label);
+ gDetachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params);
+
+ for (S32 i = 0; i < 9; i++)
{
if (gAttachBodyPartPieMenus[i])
{
@@ -507,7 +517,7 @@ BOOL LLVOAvatarSelf::buildMenus()
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getGroup() == 8)
+ if (attachment->getGroup() == 9)
{
LLMenuItemCallGL::Params item_params;
std::string sub_piemenu_name = attachment->getName();
@@ -593,7 +603,7 @@ BOOL LLVOAvatarSelf::buildMenus()
}
}
- for (S32 group = 0; group < 8; group++)
+ for (S32 group = 0; group < 9; group++)
{
// skip over groups that don't have sub menus
if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group])
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 257a760eeb..c9c899afd6 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -101,17 +101,6 @@ private:
// helper function. Passed in param is assumed to be in avatar's parameter list.
BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight);
-
-
-/** Initialization
- ** **
- *******************************************************************************/
-
-private:
- LLUUID mInitialBakeIDs[6];
- //bool mInitialBakesLoaded;
-
-
/********************************************************************************
** **
** STATE
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 476c0eef15..4e427289e7 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -54,6 +54,7 @@
#include "llspatialpartition.h"
#include "llhudmanager.h"
#include "llflexibleobject.h"
+#include "llskinningutil.h"
#include "llsky.h"
#include "lltexturefetch.h"
#include "llvector4a.h"
@@ -80,7 +81,7 @@
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
-U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20;
+U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1;
BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
@@ -4175,27 +4176,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
//build matrix palette
- static const size_t kMaxJoints = 52;
+ static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT;
- LLMatrix4a mp[kMaxJoints];
- LLMatrix4* mat = (LLMatrix4*) mp;
-
- U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints);
- for (U32 j = 0; j < maxJoints; ++j)
- {
- LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
- if (!joint)
- {
- // Fall back to a point inside the avatar if mesh is
- // rigged to an unknown joint.
- joint = avatar->getJoint("mPelvis");
- }
- if (joint)
- {
- mat[j] = skin->mInvBindMatrix[j];
- mat[j] *= joint->getWorldMatrix();
- }
- }
+ LLMatrix4a mat[kMaxJoints];
+ U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
+ LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar);
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
@@ -4207,6 +4192,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
if ( weight )
{
+ LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin);
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
@@ -4216,40 +4202,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
{
LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
+ U32 max_joints = LLSkinningUtil::getMaxJointCount();
for (U32 j = 0; j < dst_face.mNumVertices; ++j)
{
LLMatrix4a final_mat;
- final_mat.clear();
-
- S32 idx[4];
-
- LLVector4 wght;
-
- F32 scale = 0.f;
- for (U32 k = 0; k < 4; k++)
- {
- F32 w = weight[j][k];
-
- idx[k] = (S32) floorf(w);
- wght[k] = w - floorf(w);
- scale += wght[k];
- }
- // This is enforced in unpackVolumeFaces()
- llassert(scale>0.f);
- wght *= 1.f / scale;
-
- for (U32 k = 0; k < 4; k++)
- {
- F32 w = wght[k];
-
- LLMatrix4a src;
- // Insure ref'd bone is in our clamped array of mats
- // clamp idx to maxJoints to avoid reading garbage off stack in release
- S32 index = llclamp((S32)idx[k],(S32)0,(S32)kMaxJoints-1);
- src.setMul(mp[index], w);
- final_mat.add(src);
- }
-
+ LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints);
LLVector4a& v = vol_face.mPositions[j];
LLVector4a t;
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index bd6faf4ed8..502c6e0f1f 100755
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -3,7 +3,7 @@
legacy_header_height="18"
positioning="centered"
default_tab_group="1"
- height="460"
+ height="512"
layout="topleft"
name="Preferences"
help_topic="preferences"
@@ -19,7 +19,7 @@
layout="topleft"
right="-105"
name="OK"
- top="433"
+ top="473"
width="90">
<button.commit_callback
function="Pref.OK" />
@@ -40,7 +40,7 @@
<tab_container
follows="all"
halign="left"
- height="410"
+ height="440"
layout="topleft"
left="0"
name="pref core"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
index ba91b0b5d9..c3c6701d01 100755
--- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
@@ -40,6 +40,15 @@
function="Avatar.InviteToGroup" />
</menu_item_call>
<menu_item_separator />
+
+ <menu_item_call label="Reset Skeleton"
+ layout="topleft"
+ name="Reset Skeleton">
+ <menu_item_call.on_click
+ function="Avatar.ResetSkeleton" />
+ </menu_item_call>
+
+ <menu_item_separator />
<menu_item_call
enabled="false"
label="Block"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
index c6ae844d67..ced0dd37b1 100755
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -99,6 +99,13 @@ name="Edit Outfit">
<menu_item_call.on_enable
function="Edit.EnableHoverHeight" />
</menu_item_call>
+ <menu_item_call label="Reset Skeleton"
+ layout="topleft"
+ name="Reset Skeleton">
+ <menu_item_call.on_click
+ function="Avatar.ResetSkeleton" />
+ </menu_item_call>
+
<menu_item_call
label="My Friends"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
index cfbbe41f95..f04a70d0a5 100755
--- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
@@ -41,6 +41,15 @@
</menu_item_call>
<menu_item_separator />
+
+ <menu_item_call label="Reset Skeleton"
+ layout="topleft"
+ name="Reset Skeleton">
+ <menu_item_call.on_click
+ function="Avatar.ResetSkeleton" />
+ </menu_item_call>
+
+ <menu_item_separator />
<menu_item_call
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
index d3b0b07f70..924e8b8454 100755
--- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
@@ -237,6 +237,12 @@
<menu_item_call.on_enable
function="Edit.EnableHoverHeight" />
</menu_item_call>
+ <menu_item_call label="Reset Skeleton"
+ layout="topleft"
+ name="Reset Skeleton">
+ <menu_item_call.on_click
+ function="Avatar.ResetSkeleton" />
+ </menu_item_call>
<menu_item_call
label="My Friends"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 8de9a1a99a..34aafda861 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -3555,6 +3555,16 @@
parameter="collision skeleton" />
</menu_item_check>
<menu_item_check
+ label="Show Bones"
+ name="Show Bones">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="joints" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="joints" />
+ </menu_item_check>
+ <menu_item_check
label="Display Agent Target"
name="Display Agent Target">
<menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7a70fb1a2a..5e13259699 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1432,6 +1432,13 @@ Port settings take effect after you restart [APP_NAME].
<notification
icon="alertmodal.tga"
+ name="ChangeDeferredDebugSetting"
+ type="alertmodal">
+This debug setting change will take effect after you restart [APP_NAME].
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="ChangeSkin"
type="alertmodal">
The new skin will appear after you restart [APP_NAME].
@@ -10338,6 +10345,14 @@ Not enough script resources available to attach object!
</notification>
<notification
+ icon="alertmodal.tga"
+ name="IllegalAttachment"
+ type="notify">
+ <tag>fail</tag>
+ The attachment has requested a nonexistent point on the avatar. It has been attached to the chest instead.
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="CantDropItemTrialUser"
type="notify">
diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml
index 94c468e1bb..756b8f8102 100755
--- a/indra/newview/skins/default/xui/en/panel_notification.xml
+++ b/indra/newview/skins/default/xui/en/panel_notification.xml
@@ -10,7 +10,6 @@
left="0"
name="notification_panel"
chrome="true"
- show_title="false"
top="0"
height="140"
translate="false"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index 6c485c0595..923e1f1b06 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -2,7 +2,7 @@
<panel
border="true"
follows="left|top|right|bottom"
- height="418"
+ height="438"
label="Graphics"
layout="topleft"
left="102"
@@ -813,6 +813,19 @@
function="Pref.VertexShaderEnable" />
</check_box>
<check_box
+ control_name="RenderAvatarEnhancedSkeleton"
+ height="16"
+ initial_value="true"
+ label="Enhanced skeleton"
+ layout="topleft"
+ left_delta="0"
+ name="AvatarEnhancedSkeleton"
+ top_pad="1"
+ width="256">
+ <check_box.commit_callback
+ function="Pref.EnhancedSkeletonEnable" />
+ </check_box>
+ <check_box
control_name="RenderAvatarCloth"
height="16"
initial_value="true"
@@ -869,7 +882,7 @@
layout="topleft"
left="10"
name="Apply"
- top="390"
+ top="400"
width="115">
<button.commit_callback
function="Pref.Apply" />
@@ -881,7 +894,7 @@
layout="topleft"
left_pad="3"
name="Defaults"
- top="390"
+ top="400"
width="115">
<button.commit_callback
function="Pref.HardwareDefaults" />
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index 323da2be38..284688d4d1 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -16,7 +16,7 @@
</panel.string>
<button
- follows="left|bottom"
+ follows="left|top"
height="23"
label="Clear History"
tool_tip="Clear login image, last location, teleport history, web, and texture cache"
@@ -75,7 +75,7 @@
top_pad="10"
width="350" />
<button
- follows="left|bottom"
+ follows="left|top"
height="23"
label="Block list"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 615abbaa89..53b74fa645 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -2,7 +2,7 @@
<panel
border="true"
follows="all"
- height="408"
+ height="438"
label="Sounds"
layout="topleft"
left="102"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f2eddbb38e..b221c81f7b 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2254,6 +2254,7 @@ For AI Character: Get the closest navigable point to the point provided.
<string name="BodyPartsLeftLeg">Left Leg</string>
<string name="BodyPartsTorso">Torso</string>
<string name="BodyPartsRightLeg">Right Leg</string>
+ <string name="BodyPartsEnhancedSkeleton">Enhanced Skeleton</string>
<!-- slider -->
<string name="GraphicsQualityLow">Low</string>
@@ -2475,8 +2476,21 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f
<string name="Stomach">Stomach</string>
<string name="Left Pec">Left Pec</string>
<string name="Right Pec">Right Pec</string>
- <string name="Neck">Neck</string>
- <string name="Avatar Center">Avatar Center</string>
+ <string name="Neck">Neck</string>
+ <string name="Avatar Center">Avatar Center</string>
+ <string name="Left Ring Finger">Left Ring Finger</string>
+ <string name="Right Ring Finger">Right Ring Finger</string>
+ <string name="Tail Base">Tail Base</string>
+ <string name="Tail Tip">Tail Tip</string>
+ <string name="Left Wing">Left Wing</string>
+ <string name="Right Wing">Right Wing</string>
+ <string name="Jaw">Jaw</string>
+ <string name="Alt Left Ear">Alt Left Ear</string>
+ <string name="Alt Right Ear">Alt Right Ear</string>
+ <string name="Alt Left Eye">Alt Left Eye</string>
+ <string name="Alt Right Eye">Alt Right Eye</string>
+ <string name="Tongue">Tongue</string>
+ <string name="Groin">Groin</string>
<string name="Invalid Attachment">Invalid Attachment Point</string>
<string name="ATTACHMENT_MISSING_ITEM">Error: missing item</string>
<string name="ATTACHMENT_MISSING_BASE_ITEM">Error: missing base item</string>