diff options
author | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2016-05-21 08:15:28 -0400 |
---|---|---|
committer | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2016-05-21 08:15:28 -0400 |
commit | f47ceb47bbcfd3466813d1653992e1ea418964b5 (patch) | |
tree | f3b1c26e835c8ddf40587783095a8b8954717d7b | |
parent | c2ef3b4c7186dbbd95b16520f281b7d58364fb52 (diff) | |
parent | a46fdc10c76ebbf76b4976f0cbb36b649fe4fdd2 (diff) |
merged jelly-doll viewer-release into bento
93 files changed, 10059 insertions, 2130 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index 9b31e5032a..52ccdea456 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -12,6 +12,7 @@ Able Whitman Adam Marker VWR-2755 Adeon Writer + MAINT-1211 Aeonix Aeon Agathos Frascati CT-246 @@ -304,6 +305,7 @@ Catherine Pfeffer VWR-1282 VWR-8624 VWR-10854 +Cathy Foil Cayu Cluny Celierra Darling VWR-1274 @@ -856,6 +858,7 @@ MartinRJ Fayray STORM-1845 STORM-1911 STORM-1934 +Matrice Laville Matthew Anthony Matthew Dowd VWR-1344 diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index d1eb389013..2ce43436db 100644 --- 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); @@ -574,15 +601,19 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent } // add to parent - if (parent) + if (parent && (joint->getParent()!=parent)) { parent->addChild( joint ); } + // SL-315 joint->setPosition(info->mPos); + joint->setDefaultPosition(info->mPos); joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], info->mRot.mV[VZ], LLQuaternion::XYZ)); joint->setScale(info->mScale); + joint->setSupport(info->mSupport); + joint->setEnd(info->mEnd); if (info->mIsJoint) { @@ -613,12 +644,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 +659,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 +686,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 +851,7 @@ void LLAvatarAppearance::buildCharacter() //------------------------------------------------------------------------- // initialize the pelvis //------------------------------------------------------------------------- + // SL-315 mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); mIsBuilt = TRUE; @@ -1240,6 +1272,11 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num ) { return NULL; } + if (!mSkeleton[num]) + { + mSkeleton[num] = createAvatarJoint(); + mSkeleton[num]->setJointNum(num); + } return mSkeleton[num]; } @@ -1476,16 +1513,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 +1543,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 +1583,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 +1652,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 100644 --- 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 ¤t_volume_num, S32 ¤t_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 == ¤t_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(¤t_joint->getParent()->getWorldMatrix(), NULL)); - LL_DEBUGS() << "joint " << joint_count++ << current_joint->getParent()->getName() << LL_ENDL; - mMesh->mJointRenderData.push_back(new LLJointRenderData(¤t_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(¤t_joint->getWorldMatrix(), &js)); + LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL; } } diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index e630c1118b..e5e502b158 100644 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -110,6 +110,14 @@ void LLDriverParamInfo::toStream(std::ostream &out) out << std::endl; + // FIXME - this mDriverParam backlink makes no sense, because the + // LLDriverParamInfos are static objects - there's only one copy + // for each param type, so the backlink will just reference the + // corresponding param in the most recently created + // avatar. Apparently these toStream() methods are not currently + // used anywhere, so it's not an urgent problem. + LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL; + if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() && mDriverParam->getAvatarAppearance()->isValid()) { diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index f71c930e5e..f278dcc2e2 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -128,6 +128,10 @@ public: S32 getDrivenParamsCount() const; const LLViewerVisualParam* getDrivenParam(S32 index) const; + typedef std::vector<LLDrivenEntry> entry_list_t; + entry_list_t& getDrivenList() { return mDriven; } + void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; } + protected: LLDriverParam(const LLDriverParam& pOther); F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); @@ -135,7 +139,6 @@ protected: LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder - typedef std::vector<LLDrivenEntry> entry_list_t; entry_list_t mDriven; LLViewerVisualParam* mCurrentDistortionParam; // Backlink only; don't make this an LLPointer. diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index e3992a080e..2cb4c65d7c 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -369,7 +369,8 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) { if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) { - mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], + mVolumeMorphs.push_back( + LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], volume_info->mScale, volume_info->mPos)); break; @@ -647,6 +648,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); } } @@ -730,6 +732,20 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 apply(mLastSex); } +void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight) +{ + // now apply volume changes + for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) + { + LLPolyVolumeMorph* volume_morph = &(*iter); + LLVector3 scale_delta = volume_morph->mScale * delta_weight; + LLVector3 pos_delta = volume_morph->mPos * delta_weight; + + volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); + // SL-315 + volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); + } +} //----------------------------------------------------------------------------- // LLPolyVertexMask() diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index 3c2c68079c..c6133cd831 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -182,6 +182,8 @@ public: void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); void addPendingMorphMask() { mNumMorphMasksPending++; } + void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() + void* operator new(size_t size) { return ll_aligned_malloc_16(size); diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index fbc312c426..fdce8d97ce 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -34,6 +34,7 @@ #include "llpolymorph.h" #include "llwearable.h" #include "llfasttimer.h" +#include "llcallstack.h" #include "llpolyskeletaldistortion.h" @@ -134,55 +135,58 @@ LLPolySkeletalDistortion::~LLPolySkeletalDistortion() BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mInfo = info; - mID = info->mID; - setWeight(getDefaultWeight()); - - LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; - for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + if (info->mID < 0) + { + return FALSE; + } + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight()); + + LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; + for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + { + LLPolySkeletalBoneInfo *bone_info = &(*iter); + LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); + if (!joint) { - LLPolySkeletalBoneInfo *bone_info = &(*iter); - LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); - if (!joint) - { - LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; - continue; - } + LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; + continue; + } - if (mJointScales.find(joint) != mJointScales.end()) - { - LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; - } + // BENTO remove? + //if (mJointScales.find(joint) != mJointScales.end()) + //{ + // LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; + //} - // store it - mJointScales[joint] = bone_info->mScaleDeformation; + // store it + mJointScales[joint] = bone_info->mScaleDeformation; - // apply to children that need to inherit it - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); - iter != joint->mChildren.end(); ++iter) - { - LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); - if (child_joint->inheritScale()) - { - LLVector3 childDeformation = LLVector3(child_joint->getScale()); - childDeformation.scaleVec(bone_info->mScaleDeformation); - mJointScales[child_joint] = childDeformation; - } - } + // apply to children that need to inherit it + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) + { + LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); + if (child_joint->inheritScale()) + { + LLVector3 childDeformation = LLVector3(child_joint->getScale()); + childDeformation.scaleVec(bone_info->mScaleDeformation); + mJointScales[child_joint] = childDeformation; + } + } - if (bone_info->mHasPositionDeformation) - { - if (mJointOffsets.find(joint) != mJointOffsets.end()) - { - LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; - } - mJointOffsets[joint] = bone_info->mPositionDeformation; - } + if (bone_info->mHasPositionDeformation) + { + // BENTO remove? + //if (mJointOffsets.find(joint) != mJointOffsets.end()) + //{ + // LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; + //} + mJointOffsets[joint] = bone_info->mPositionDeformation; } - return TRUE; + } + return TRUE; } /*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const @@ -211,9 +215,16 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex ) joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; - newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); + LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta; + newScale = newScale + offset; //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached // needed? // joint->storeScaleForReset( newScale ); + + // BENTO debugging stuff can be pulled. + std::stringstream ostr; + ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset; + LLScopedContextString str(ostr.str()); + joint->setScale(newScale); } @@ -225,7 +236,9 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex ) LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); - joint->setPosition(newPosition); + // SL-315 + // BENTO - allow attachment positions to override requests from the params. + joint->setPosition(newPosition, true); } if (mLastWeight != mCurWeight && !mIsAnimating) diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 5ca9f55ac8..63069adcc8 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -173,7 +173,7 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) { if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true)) { - LL_WARNS() << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; + LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; continue; } } diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 2573417b26..a17a5b0aa6 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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..c4eda0b432 100644 --- 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() << "LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be increased" << LL_ENDL; + LL_ERRS() << "joint_num " << joint_num << " + 2 is too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL; + } +} +//----------------------------------------------------------------------------- // getRoot() //----------------------------------------------------------------------------- LLJoint *LLJoint::getRoot() @@ -290,25 +326,54 @@ 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; } //-------------------------------------------------------------------- // setPosition() //-------------------------------------------------------------------- -void LLJoint::setPosition( const LLVector3& pos ) -{ - if (pos != getPosition()) +void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides ) +{ + LLVector3 pos(requested_pos); + + LLVector3 active_override; + LLUUID mesh_id; + if (apply_attachment_overrides && m_attachmentOverrides.findActiveOverride(mesh_id,active_override)) + { + if (pos != active_override && do_debug_joint(getName())) + { + LLScopedContextString str("setPosition"); + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos + << " overriden by attachment " << active_override << LL_ENDL; + } + pos = active_override; + } + 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); } +void LLJoint::setDefaultPosition( const LLVector3& pos ) +{ + mDefaultPosition = pos; +} + +const LLVector3& LLJoint::getDefaultPosition() const +{ + return mDefaultPosition; +} void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) { std::ostringstream os; @@ -317,6 +382,13 @@ void showJointPosOverrides( const LLJoint& joint, const std::string& note, const LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; } +bool above_joint_pos_threshold(const LLVector3& diff) +{ + //return !diff.isNull(); + const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; +} + //-------------------------------------------------------------------- // addAttachmentPosOverride() //-------------------------------------------------------------------- @@ -326,6 +398,15 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh { return; } + if (!above_joint_pos_threshold(pos-getDefaultPosition())) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "Attachment pos override ignored for " << getName() + << ", pos " << pos << " is same as default pos" << LL_ENDL; + } + return; + } if (!m_attachmentOverrides.count()) { if (do_debug_joint(getName())) @@ -385,6 +466,49 @@ void LLJoint::clearAttachmentPosOverrides() } //-------------------------------------------------------------------- +// showAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentOverrides.count(); + if (count==1) + { + LLPosOverrideMap::map_type::const_iterator it = m_attachmentOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment pos override " << highlight << "" << it->second << " default " << mDefaultPosition << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment pos overrides" << LL_ENDL; + std::set<LLVector3> distinct_offsets; + LLPosOverrideMap::map_type::const_iterator it = m_attachmentOverrides.getMap().begin(); + for (; it != m_attachmentOverrides.getMap().end(); ++it) + { + distinct_offsets.insert(it->second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + std::set<LLVector3>::iterator dit = distinct_offsets.begin(); + for ( ; dit != distinct_offsets.end(); ++dit) + { + std::string highlight = (has_active_override && *dit == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << (*dit) << " default " << mDefaultPosition << LL_ENDL; + } + } +} + +//-------------------------------------------------------------------- // updatePos() //-------------------------------------------------------------------- void LLJoint::updatePos(const std::string& av_info) @@ -393,17 +517,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 +678,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..d2c573864b 100644 --- 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 = 192; // 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; @@ -56,8 +62,10 @@ public: void add(const LLUUID& mesh_id, const LLVector3& pos); bool remove(const LLUUID& mesh_id); void clear(); -private: + typedef std::map<LLUUID,LLVector3> map_type; + const map_type& getMap() const { return m_map; } +private: map_type m_map; }; @@ -86,9 +94,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; @@ -97,6 +113,8 @@ protected: LLUUID mId; + LLVector3 mDefaultPosition; + public: U32 mDirtyFlags; BOOL mUpdateXform; @@ -104,6 +122,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 +135,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 +147,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 +180,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; } @@ -155,10 +209,12 @@ public: // get/set local position const LLVector3& getPosition(); - void setPosition( const LLVector3& pos ); - + void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false ); + + // Tracks the default position defined by the skeleton void setDefaultPosition( const LLVector3& pos ); - + const LLVector3& getDefaultPosition() const; + // get/set world position LLVector3 getWorldPosition(); LLVector3 getLastWorldPosition(); @@ -198,12 +254,11 @@ 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; void clearAttachmentPosOverrides(); + void showAttachmentPosOverrides(const std::string& av_info) const; //Accessor for the joint id LLUUID getId( void ) { return mId; } diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index cd201a65b4..052ca3be58 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 907dbab8f8..c3242389c2 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -40,6 +40,7 @@ set(llcommon_SOURCE_FILES llbase64.cpp llbitpack.cpp llcallbacklist.cpp + llcallstack.cpp llcommon.cpp llcommonutils.cpp llcoros.cpp @@ -114,6 +115,7 @@ set(llcommon_SOURCE_FILES llworkerthread.cpp timing.cpp u64.cpp + StackWalker.cpp ) set(llcommon_HEADER_FILES @@ -134,6 +136,7 @@ set(llcommon_HEADER_FILES llbitpack.h llboost.h llcallbacklist.h + llcallstack.h llcommon.h llcommonutils.h llcoros.h @@ -235,6 +238,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..834f89c471 --- /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 = 4096 }; // 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..8db291eed1 --- /dev/null +++ b/indra/llcommon/llcallstack.cpp @@ -0,0 +1,190 @@ +/** + * @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) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + std::vector<std::string>::const_iterator it; + for (it=call_stack.m_strings.begin(); it!=call_stack.m_strings.end(); ++it) + { + s << *it; + } +#else + s << "UNAVAILABLE IN RELEASE"; +#endif + 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 100644 --- 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 d932eb53a0..2918e2e272 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2544,7 +2544,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) U16 influence = weights[idx++]; influence |= ((U16) weights[idx++] << 8); - F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); + F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f); wght.mV[cur_influence] = w; joints[cur_influence] = joint; cur_influence++; @@ -2561,11 +2561,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; if (wsum <= 0.f) { - wght = LLVector4(0.99999f,0.f,0.f,0.f); + wght = LLVector4(0.999f,0.f,0.f,0.f); } - for (U32 k=0; k<4; k++) + for (U32 k=0; k<cur_influence; k++) { - joints_with_weights[k] = (F32) joints[k] + wght[k]; + F32 f_combined = (F32) joints[k] + wght[k]; + llassert(f_combined-(S32)f_combined>0); // If this fails, we have a floating point precision error. + joints_with_weights[k] = f_combined; } face.mWeights[cur_vertex].loadua(joints_with_weights.mV); @@ -4568,6 +4570,7 @@ LLVolumeFace::LLVolumeFace() : mTexCoords(NULL), mIndices(NULL), mWeights(NULL), + mWeightsRemapped(FALSE), mOctree(NULL), mOptimized(FALSE) { @@ -4593,6 +4596,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mTexCoords(NULL), mIndices(NULL), mWeights(NULL), + mWeightsRemapped(FALSE), mOctree(NULL) { mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); @@ -4664,6 +4668,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) ll_aligned_free_16(mWeights); mWeights = NULL; } + mWeightsRemapped = src.mWeightsRemapped; } if (mNumIndices) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 1da2d0c6b1..33e1403a14 100644 --- 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..38b061dd79 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) { } @@ -1148,28 +1152,29 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae->getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); + U32 skeleton_count = dae->getDatabase()->getElementCount( NULL, "skeleton" ); + std::vector<domInstance_controller::domSkeleton*> skeletons; + for (S32 i=0; i<skeleton_count; i++) + { + daeElement* pElement = 0; + dae->getDatabase()->getElement( &pElement, i, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); + daeElement* pSkeletonRootNode = NULL; + if (pSkeleton) + { + pSkeletonRootNode = pSkeleton->getValue().getElement(); + } + if (pSkeleton && pSkeletonRootNode) + { + skeletons.push_back(pSkeleton); + } + } bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) - { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - - } - if ( !pSkeleton || !rootNode ) + if ( skeletons.size() == 0 ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) @@ -1184,7 +1189,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do S32 childCount = children.getCount(); //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + //Not all children are joints, some could be ambient lights, cameras, geometry etc.. for (S32 i = 0; i < childCount; ++i) { domNode* pNode = daeSafeCast<domNode>(children[i]); @@ -1196,83 +1201,90 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } } else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - JointMap :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i<jointCnt; ++i, ++jointIt ) - { - //Build a joint for the resolver to work with - char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str() ); - //LL_WARNS()<<"Joint "<< str <<LL_ENDL; - - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); - - //Look for the joint - domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pJoint, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pJoint, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslateA ) - { - extractTranslation( pTranslateA, workingTransform ); - } - else - if ( pTranslateB ) - { - extractTranslation( pTranslateB, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - missingSkeletonOrScene = true; - } - else - if ( pTranslateElement ) - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - else - { - extractTranslationViaSID( pJoint, workingTransform ); - } - - } - - //Store the joint transform w/respect to it's name. - mJointList[(*jointIt).second.c_str()] = workingTransform; - } - } - - //If anything failed in regards to extracting the skeleton, joints or translation id, - //mention it - if ( missingSkeletonOrScene ) - { - LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; - } - }//got skeleton? - } + //Has one or more skeletons + for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin(); + skel_it != skeletons.end(); ++skel_it) + { + domInstance_controller::domSkeleton* pSkeleton = *skel_it; + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + JointMap :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i<jointCnt; ++i, ++jointIt ) + { + //Build a joint for the resolver to work with + char str[64]={0}; + sprintf(str,"./%s",(*jointIt).first.c_str() ); + //LL_WARNS()<<"Joint "<< str <<LL_ENDL; + + //Setup the resolver + daeSIDResolver resolver( pSkeletonRootNode, str ); + + //Look for the joint + domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); + if ( pJoint ) + { + // FIXME this has a lot of overlap with processJointNode(), would be nice to refactor. + + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolverA( pJoint, "./translate" ); + domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); + daeSIDResolver jointResolverB( pJoint, "./location" ); + domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslateA ) + { + extractTranslation( pTranslateA, workingTransform ); + } + else + { + if ( pTranslateB ) + { + extractTranslation( pTranslateB, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; + missingSkeletonOrScene = true; + } + else + if ( pTranslateElement ) + { + extractTranslationViaElement( pTranslateElement, workingTransform ); + } + else + { + extractTranslationViaSID( pJoint, workingTransform ); + } + + } + } + + //Store the joint transform w/respect to its name. + mJointList[(*jointIt).second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingSkeletonOrScene ) + { + LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; + } + }//got skeleton? + } domSkin::domJoints* joints = skin->getJoints(); @@ -1307,7 +1319,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 +1336,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 +1363,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 +1379,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 +1426,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 +1881,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..398f0997f3 100644 --- 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; @@ -1000,7 +1001,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { - //1. If a vertex has been weighted then we'll find it via pos and return it's weight list + //1. If a vertex has been weighted then we'll find it via pos and return its weight list weight_map::iterator iterPos = mSkinWeights.begin(); weight_map::iterator iterEnd = mSkinWeights.end(); @@ -1223,7 +1224,6 @@ bool LLModel::loadModel(std::istream& is) } return false; - } bool LLModel::isMaterialListSubset( LLModel* ref ) diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index ae602c09df..5f98942340 100644 --- 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 8d863631cf..769b86c218 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -533,6 +533,7 @@ set(viewer_SOURCE_FILES llsidepaneliteminfo.cpp llsidepaneltaskinfo.cpp llsidetraypanelcontainer.cpp + llskinningutil.cpp llsky.cpp llslurl.cpp llsnapshotlivepreview.cpp @@ -1137,6 +1138,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 d13e837c8e..0062ac9718 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -4.0.6 +5.0.0 diff --git a/indra/newview/app_settings/anim.ini b/indra/newview/app_settings/anim.ini index 63c84e544d..c24d2749ef 100644 --- 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 a8d42be2a1..a7a15c9c7b 100644 --- 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> @@ -3514,6 +3525,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> @@ -14442,6 +14464,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>LogWearableAssetSave</key> + <map> + <key>Comment</key> + <string>Save copy of saved wearables to log dir</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>LogTextureDownloadsToViewerLog</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 100644 --- 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 7f7eaed38a..38bcd88078 100644 --- 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"> + 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 @@ -307,7 +307,7 @@ <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" @@ -412,7 +412,161 @@ position="0 0 0" 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"/> + + <attachment_point + id="54" + group="8" + pie_slice="13" + name="Left Hind Foot" + joint="mHindLimb4Left" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="55" + group="8" + pie_slice="14" + name="Right Hind Foot" + joint="mHindLimb4Right" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <!-- END BENTO --> + <param id="32" group="1" @@ -460,8 +614,12 @@ scale="0 0 .05" /> <bone - name="mPelvis" - scale="0 0 0" /> + name="mSpine3" + scale="0 0 .05" /> + + <bone + name="mSpine4" + scale="0 0 .05" /> <bone name="mHipLeft" @@ -478,6 +636,27 @@ <bone name="mKneeRight" scale=".05 .05 .1" /> + + <bone + name="mHindLimb1Left" + scale=".05 .05 0" /> + + <bone + name="mHindLimb1Right" + scale=".05 .05 0" /> + + <bone + name="mHindLimb2Left" + scale=".05 .05 .1" /> + + <bone + name="mHindLimb2Right" + 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> @@ -533,8 +712,12 @@ scale="0 0 0.05" /> <bone - name="mPelvis" - scale="0 0 0" /> + name="mSpine3" + scale="0 0 0.05" /> + + <bone + name="mSpine4" + scale="0 0 0.05" /> <bone name="mHipLeft" @@ -551,6 +734,22 @@ <bone name="mKneeRight" scale="0 0 0.1" /> + + <bone + name="mHindLimb1Left" + scale="0 0 0.1" /> + + <bone + name="mHindLimb1Right" + scale="0 0 0.1" /> + + <bone + name="mHindLimb2Left" + scale="0 0 0.1" /> + + <bone + name="mHindLimb2Right" + scale="0 0 0.1" /> </param_skeleton> </param> @@ -606,10 +805,26 @@ scale="0.1 0.1 0" /> <bone + name="mSpine3" + scale="0.1 0.1 0" /> + + <bone + name="mSpine4" + scale="0.1 0.1 0" /> + + <bone name="mPelvis" scale="0.1 0.1 0" /> <bone + name="mSpine1" + scale="0.1 0.1 0" /> + + <bone + name="mSpine2" + scale="0.1 0.1 0" /> + + <bone name="mHipLeft" scale="0.13 0.13 0" /> @@ -624,6 +839,33 @@ <bone name="mKneeRight" scale="0.12 0.12 0" /> + + <bone + name="mHindLimb1Left" + scale="0.13 0.13 0" /> + + <bone + name="mHindLimb1Right" + scale="0.13 0.13 0" /> + + <bone + name="mHindLimb2Left" + scale="0.12 0.12 0" /> + + <bone + name="mHindLimb2Right" + 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" scale="0.0 0.0 0.0" offset="-0.01 -0.01 0" /> + <bone name="mWing1Left" scale="0.0 0.0 0.0" offset="-0.01 0.01 0" /> + </param_skeleton> </param> @@ -662,6 +904,17 @@ <bone name="mChest" scale="0.02 0.08 0" /> + + <bone + name="mWing1Right" + scale="0.0 0.0 0.0" + offset="0 -0.02 0" /> + + <bone + name="mWing1Left" + scale="0.0 0.0 0.0" + offset="0 0.02 0" /> + </param_skeleton> </param> @@ -669,7 +922,7 @@ id="37" group="0" name="Hip Width" - label="Hip Width" + label="Hip Width" wearable="shape" edit_group="shape_legs" edit_group_order="3" @@ -685,6 +938,14 @@ scale="0 0.1 0" /> <bone + name="mSpine1" + scale="0 0.1 0" /> + + <bone + name="mSpine2" + scale="0 0.1 0" /> + + <bone name="mHipLeft" scale="0 0 0" offset="0 .004 0" /> @@ -693,6 +954,21 @@ name="mHipRight" scale="0 0 0" offset="0 -.004 0" /> + + <bone + name="mHindLimb1Left" + scale="0 0 0" + offset="0 .004 0" /> + + <bone + name="mHindLimb1Right" + 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> @@ -712,7 +988,15 @@ <bone name="mPelvis" scale="0 0 0.3" /> - </param_skeleton> + + <bone + name="mSpine1" + scale="0 0 0.3" /> + + <bone + name="mSpine2" + scale="0 0 0.3" /> + </param_skeleton> </param> <param @@ -733,10 +1017,26 @@ scale="0 0 .3" /> <bone + name="mSpine3" + scale="0 0 .3" /> + + <bone + name="mSpine4" + scale="0 0 .3" /> + + <bone name="mPelvis" scale="0 0 .1" /> <bone + name="mSpine1" + scale="0 0 .1" /> + + <bone + name="mSpine2" + scale="0 0 .1" /> + + <bone name="mHipLeft" scale="0 0 -.1" /> @@ -751,6 +1051,22 @@ <bone name="mKneeLeft" scale="0 0 -.05" /> + + <bone + name="mHindLimb1Left" + scale="0 0 -.1" /> + + <bone + name="mHindLimb1Right" + scale="0 0 -.1" /> + + <bone + name="mHindLimb2Right" + scale="0 0 -.05" /> + + <bone + name="mHindLimb2Left" + scale="0 0 -.05" /> </param_skeleton> </param> @@ -774,6 +1090,77 @@ 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" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0 " + offset="0 .008 0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0 " + offset="0 -.008 0" /> + </param_skeleton> </param> @@ -797,6 +1184,156 @@ 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="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceCheekUpperRight" + 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="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 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 +1357,102 @@ 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.25 0 0" + offset="0 0 0" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset=".01 0 0" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceLipUpperCenter" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipLowerCenter" + scale="0 0 0" + offset="0.01 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.01 0 0" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0.01 0 0" /> + + <bone + name="mFaceLipCornerRight" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipCornerLeft" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0.007 0 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="-0.007 0 0" /> + + <bone + name="mFaceTeethUpper" + scale="0 0 0" + offset="0.015 0 0" /> + + <bone + name="mFaceTeethLower" + scale="0 0 0" + offset="0.007 0 0" /> + </param_skeleton> </param> @@ -843,6 +1476,79 @@ 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="mFaceEyecornerInnerLeft" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyecornerInnerRight" + 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=".0013 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset=".0013 0 0" /> + + + + </param_skeleton> </param> @@ -850,7 +1556,7 @@ id="655" group="1" name="Head Size" - label="Head Size" + label="Head Size" wearable="shape" edit_group="shape_head" label_min="Small Head" @@ -859,6 +1565,36 @@ value_min="-.25" value_max=".10"> <param_skeleton> + + <bone + name = "mFaceTeethLower" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceTeethUpper" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceEyecornerInnerLeft" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceEyecornerInnerRight" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceNoseBridge" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceNoseBase" + scale = "1 1 1" + offset = "0 0 0" /> <bone name="mSkull" scale="1 1 1" @@ -870,6 +1606,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 +1619,165 @@ 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="mFaceCheekLowerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekUpperLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekUpperRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceJaw" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceChin" + 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 +1851,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 +1938,47 @@ 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.7 0.5" + offset="-.003 0 -0.003" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0.7 0.5" + offset="-.003 0 -0.003" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0.7 0.5" + offset="-.003 0 0.003" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0.7 0.5" + offset="-.003 0 0.003" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="-0.005 -0.008 0.0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="-0.005 0.008 0.0" /> + </param_skeleton> </param> @@ -1028,6 +2010,22 @@ <bone name="mKneeLeft" scale="0 0 .2" /> + + <bone + name="mHindLimb1Left" + scale="0 0 .2" /> + + <bone + name="mHindLimb1Right" + scale="0 0 .2" /> + + <bone + name="mHindLimb2Right" + scale="0 0 .2" /> + + <bone + name="mHindLimb2Left" + scale="0 0 .2" /> </param_skeleton> </param> @@ -1084,7 +2082,8 @@ scale="0 0 .5" /> </param_skeleton> </param> - <param + + <param id="11001" group="0" name="Hover" @@ -1099,12 +2098,2022 @@ camera_distance="2.5"> <param_skeleton /> </param> + + <param + id="30002" + group="1" + name="Nose_Big_Out" + value_min="-0.8" + value_max="2.5"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.01 0.0 0.0" + scale = "0.10 0.3 0.0" /> + <bone + name = "mFaceNoseLeft" + offset = "0 0.0025 0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceNoseRight" + offset = "0 -0.0025 0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceNoseBridge" + offset = "0.006 0.0 0.0" + scale = "0.10 0.1 0.0" /> + + </param_skeleton> + </param> + + <param + id="30004" + group="1" + name="Broad_Nostrils" + value_min="-.5" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceNoseLeft" + offset = "0 0.005 0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceNoseRight" + offset = "0 -0.005 0" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30020" + group="1" + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5" + > + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.0 0.0 0.0" + scale = "0.2 0.4 0.2" /> + <bone + name = "mFaceNoseLeft" + scale = "0 0.3 0" + offset = "0 0.0015 0" + /> + <bone + name = "mFaceNoseRight" + scale = "0 0.3 0" + offset = "0 -0.0015 0" + /> + + </param_skeleton> + </param> + + <param + id="30517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.00 0.0 0.0" + scale = "0.10 0.85 0.0" /> + <bone + name = "mFaceNoseLeft" + scale = "0 0 0" + offset = "0.001 0.010 0"/> + <bone + name = "mFaceNoseRight" + scale = "0 0 0" + offset = "-0.001 -0.01 0" /> + </param_skeleton> + </param> + <param + id="30656" + group="1" + name="Crooked_Nose" + value_min="-2" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.009 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 0.007 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.002 0.0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.002 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceEyebrowInnerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.0008 0.0" /> + + <bone + name = "mFaceEyebrowInnerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.0008 0.0" /> + + <bone + name = "mFaceNoseBridge" + scale = "0.0 0.00 0.0" + offset = "0.0 0.004 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceEyecornerInnerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceEyecornerInnerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + </param_skeleton> + </param> + + <param + id="30155" + group="1" + name="Lip Width" + value_min="-0.9" + value_max="1.3" + value_default="0"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.005 0.0" /> + + </param_skeleton> + </param> + + <param + id="30653" + group="1" + name="Tall_Lips" + value_min="-1" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 0.0015" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 0.0025" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 0.0015" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 -0.0015" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 -0.0025" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 0.2" + offset = "-0.01 0.00 -0.0015" /> + + </param_skeleton> + </param> + + <param + id="30505" + group="1" + name="Lip_Thickness" + value_min="0" + value_max="0.7"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.012 0.00 -0.005" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 -0.6" + offset = "-0.015 0.00 -0.005" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 -0.6" + offset = "-0.012 0.00 -0.005" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + </param_skeleton> + </param> + + <param + id="31505" + group="1" + name="Lip_Thickness" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 0.1" + offset = "0.005 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 0.7" + offset = "0.004 0.00 0.006" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 0.7" + offset = "0.004 0.00 0.006" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 0.7" + offset = "0.004 0.00 0.006" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 0.1" + offset = "0.005 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + </param_skeleton> + </param> + + <param + id="30797" + group="1" + name="Fat_Upper_Lip" + value_min="0" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipUpperLeft" + scale = " 0.1 0 0.6" + offset = "-0.006 0.00 0.006" /> + + <bone + name = "mFaceLipUpperCenter" + scale = " 0.1 0 0.4" + offset = "-0.006 0.00 0.003" /> + + <bone + name = "mFaceLipUpperRight" + scale = " 0.1 0 0.6" + offset = "-0.006 0.00 0.006" /> + + <bone + name = "mFaceLipLowerLeft" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipLowerCenter" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipLowerRight" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + </param_skeleton> + </param> + + <param + id="30798" + group="1" + name="Fat_Lower_Lip" + value_min="0" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "-0.002 0.00 -0.002" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "-0.002 0.00 -0.002" /> + + <bone + name = "mFaceLipUpperLeft" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipUpperCenter" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipUpperRight" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerLeft" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + <bone + name = "mFaceLipLowerCenter" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + <bone + name = "mFaceLipLowerRight" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + </param_skeleton> + </param> + + <param + id="30506" + group="1" + name="Mouth_Height" + value_min="-2" + value_max="2"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipUpperLeft" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipUpperCenter" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipUpperRight" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipLowerLeft" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipLowerCenter" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceLipLowerRight" + scale = " 0 0 0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceTongueBase" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.001" /> + + </param_skeleton> + </param> + + <param + id="30658" + group="1" + name="Frown_Mouth" + value_min="0" + value_max="1.4"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0 -0.005" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "0 0 -0.005" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0 0 0" + offset = "0 0 0.001" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0 0 0" + offset = "0 0 0.002" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0 0 0" + offset = "0 0 0.001" /> + </param_skeleton> + </param> + + <param + id="30657" + group="1" + name="Smile_Mouth" + value_min="0" + value_max="1.4"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0.005 0.002" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "0 -0.005 0.002" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0.002 0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 0" + offset = "0 0 -0.0005" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 -0.002 0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0 0 0" + offset = "0 0.001 0" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0 0 0" + offset = "0 0 -0.001" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0 0 0" + offset = "0 -0.001 0" /> + + </param_skeleton> + </param> + + <param + id="30764" + group="1" + name="Lip_Cleft_Deep" + value_min="-1" + value_max="1.2"> + <param_skeleton> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0 0.002" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 0" + offset = "0 0 -0.001" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 0 0.002" /> + + </param_skeleton> + </param> + + <param + id="30025" + group="1" + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0.004 0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 -0.004 0" /> + + </param_skeleton> + </param> + + <param + id="31663" + group="1" + name="Shift_Mouth" + value_min="0" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.004 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.005 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.005 0.0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.006 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "-0.002 -0.005 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "-0.002 -0.005 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.007 0.0" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.01 0.0" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.0 0.00 0.0" + offset = "-0.002 -0.005 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "-0.002 -0.005 0.0" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "-0.002 -0.006 0.0" /> + + + + </param_skeleton> + </param> + + <param + id="32663" + group="1" + name="Shift_Mouth" + value_min="0" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 0.004 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "-0.002 0.005 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "-0.002 0.005 0.0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.006 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.0 0.00 0.0" + offset = "-0.002 0.005 0.0" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.01 0.0" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.007 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "-0.002 0.005 0.0" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "-0.002 0.006 0.0" /> + + + </param_skeleton> + </param> + + <param + id="30035" + group="1" + name="Big_Ears" + value_min="-1" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceEar1Left" + scale = "0.55 0.55 0.55" + offset = "0.0 -0.002 0.001" /> + <bone + name = "mFaceEar1Right" + scale = "0.55 0.55 0.55" + offset = "0.0 0.002 0.001" /> + </param_skeleton> + </param> + + <param + id="30015" + group="1" + name="Ears_Out" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + <!-- Place Holder. Can't do this unless we get rotation offset --> + <bone + name = "mFaceEar1Left" + offset = "0.0 -0.0 0.0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceEar1Right" + offset = "0.0 0.0 0.0" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30796" + group="1" + name="Pointy_Ears" + value_min="-.4" + value_max="3"> + <param_skeleton> + <bone + name = "mFaceEar2Left" + offset = "-0.0149 0.001 0.016" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceEar2Right" + offset = "-0.0149 -0.001 0.016" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceJaw" + offset = "0.0 0.00 -0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerRight" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerCenter" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceTongueBase" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + <param + id="40185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceJaw" + offset = "0.0 0.00 -0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerRight" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerCenter" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceTongueBase" + offset = "0.0 0.00 0.02" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="30760" + group="1" + name="Jaw_Angle" + value_min="-2" + value_max="2" + value_default="0"> + <param_skeleton> + <bone + name = "mFaceJaw" + offset = "0.0 0.00 0.03" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + offset = "0.0 0.00 -0.03" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerRight" + offset = "0.0 0.00 -0.03" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceLipLowerCenter" + offset = "0.0 0.00 -0.03" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceTongueBase" + offset = "0.0 0.00 -0.03" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceChin" + offset = "0.0 0.00 -0.03" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + + <param + id="30665" + group="1" + name="Jaw_Jut" + value_min="-2" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceJaw" + offset = "0.0085 0.00 0" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceTeethLower" + offset = "0.008 0 0" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="30006" + group="1" + name="Bulbous_Nose_Tip" + value_min="-1" + value_max="1.5"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.0 0.00 0.0" + scale = "0.1 0.1 0.1" /> + + </param_skeleton> + </param> + + <param + id="30007" + group="1" + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "-0.025 0.00 0.005" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="40007" + group="1" + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "-0.025 0.00 0.005" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="30008" + group="1" + name="Double_Chin" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "-0.002 0.0 -0.01" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + + <param + id="30024" + group="1" + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + <param_skeleton> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0 .003" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 0 .003" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0 -.003" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 0 -.003" /> + + </param_skeleton> + </param> + + <param + id="30650" + group="1" + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 0 .004" /> + </param_skeleton> + </param> + + <param + id="30880" + group="1" + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 0 .004" /> + </param_skeleton> + </param> + + <param + id="30765" + group="1" + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + <param_skeleton> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0.05 0.05 0.05" + offset="0 0 .0003" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0.05 0.05 0.05" + offset="0 0 .0003" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="31629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.08" + offset="0.02 0 0" /> + + <bone + name="mFaceForeheadCenter" + scale="0.01 0 0.08" + offset="0.002 0 0" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.08" + offset="0.02 0 0" /> + + </param_skeleton> + </param> + + <param + id="41629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.08" + offset="0.02 0 0" /> + + <bone + name="mFaceForeheadCenter" + scale="0.01 0 0.08" + offset="0.002 0 0" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.08" + offset="0.02 0 0" /> + + </param_skeleton> + </param> + + <param + id="30647" + group="1" + name="Squash_Stretch_Head" + value_min="-0.5" + value_max="1" + value_default="0"> + <param_skeleton> + + <bone + name="mFaceRoot" + scale="0 -0.07 0.07" + offset="0 0 -0.005" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 -0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 -0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 -0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 -0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 -0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 -0.00225 0.001" /> + + <bone + name="mFaceLipUpperRight" + scale="0 0 0" + offset="0 -0.0014 0.007" /> + <bone + name="mFaceLipUpperCenter" + scale="0 0 0" + offset="0 0 0.007" /> + + <bone + name="mFaceTeethUpper" + scale="0 0 0" + offset="0 0 0.007" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0 0 0.0005" /> + <bone + name="mFaceLipCornerRight" + scale="0 0 0" + offset="0 -0.00225 0.0075" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0.00225 0.001" /> + + <bone + name="mFaceLipUpperLeft" + scale="0 0 0" + offset="0 0.0014 0.007" /> + <bone + name="mFaceLipLowerCenter" + scale="0 0 0" + offset="0 0 0.001" /> + <bone + name="mFaceTeethLower" + scale="0 0 0" + offset="0 0 0.008" /> + <bone + name="mFaceLipLowerLeft" + scale="0 0 0" + offset="0 0.000 0.0005" /> + <bone + name="mFaceLipCornerLeft" + scale="0 0 0" + offset="0 0.00225 0.0075" /> + + <bone + name="mFaceTongueBase" + scale="0 0 0" + offset="0 0 0.00" /> + + <bone + name="mFaceJaw" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 0.0085" /> + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 0.005" /> + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 0.006" /> + + </param_skeleton> + </param> + <param + id="40647" + group="1" + name="Squash_Stretch_Head" + value_min="-0.5" + value_max="1" + value_default="0"> + <param_skeleton> + + <bone + name="mFaceRoot" + scale="0 -0.07 0.07" + offset="0 0 -0.005" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 -0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 -0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 -0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 -0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 -0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 -0.00225 0.001" /> + + <bone + name="mFaceLipUpperRight" + scale="0 0 0" + offset="0 -0.0014 0.007" /> + <bone + name="mFaceLipUpperCenter" + scale="0 0 0" + offset="0 0 0.007" /> + + <bone + name="mFaceTeethUpper" + scale="0 0 0" + offset="0 0 0.007" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0 -0.00225 0.0005" /> + <bone + name="mFaceLipCornerRight" + scale="0 0 0" + offset="0 -0.00225 0.0075" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0.00225 0.001" /> + + <bone + name="mFaceLipUpperLeft" + scale="0 0 0" + offset="0 0.0014 0.007" /> + <bone + name="mFaceLipLowerCenter" + scale="0 0 0" + offset="0 0 0.001" /> + <bone + name="mFaceTeethLower" + scale="0 0 0" + offset="0 0 0.008" /> + <bone + name="mFaceLipLowerLeft" + scale="0 0 0" + offset="0 0.00225 0.0004" /> + <bone + name="mFaceLipCornerLeft" + scale="0 0 0" + offset="0 0.00225 0.0075" /> + + <bone + name="mFaceTongueBase" + scale="0 0 0" + offset="0 0 0.00" /> + + <bone + name="mFaceJaw" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 0.0085" /> + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 0.005" /> + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 0.006" /> + + </param_skeleton> + </param> + + <param + id="32629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="-0.001 0 0.001" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 0 0.003" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0 0.003" /> + + </param_skeleton> + </param> + + <param + id="42629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="-0.001 0 0.001" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 0 0.003" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0 0.003" /> + + </param_skeleton> + </param> + + <param + id="30001" + group="1" + name="Big_Brow" + value_min="-.3" + value_max="2"> + <param_skeleton> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0.007 0 0.001" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0.004 0 0" /> + + </param_skeleton> + </param> + + <param + id="30011" + group="1" + name="Noble_Nose_Bridge" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0.15 0.01 0.7" + offset="0.009 0 -0.006" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0.001 0 0" /> + + </param_skeleton> + </param> + + <param + id="30758" + group="1" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0 0 0.2" + offset="0.0025 0 -0.001" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0.004 0 0.001" /> + + </param_skeleton> + </param> + + <param + id="30027" + group="1" + name="Wide_Nose_Bridge" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0 0.4 0" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30759" + group="1" + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> + <param_skeleton> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 -0.004" /> + + </param_skeleton> + + </param> + + + <param + id="30010" + group="1" + name="Sunken_Cheeks" + value_min="-1.5" + value_max="3"> + <param_skeleton> + + <bone + name="mFaceCheekLowerLeft" + scale="0 0.1 0" + offset="0.001 -0.01 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0.1 0" + offset="0.001 0.01 0" /> + + </param_skeleton> + </param> + + <param + id="30017" + group="1" + name="Square_Jaw" + value_min="-0.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceJaw" + scale="0.0 0.5 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceLipLowerRight" + scale="0.0 0.0 0.0" + offset="0.0 0.0038 0.0" /> + + <bone + name="mFaceLipLowerLeft" + scale="0.0 0.0 0.0" + offset="0.0 -0.0038 0.0" /> + + </param_skeleton> + </param> + <param + id="40017" + group="1" + name="Square_Jaw" + value_min="-0.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceJaw" + scale="0.0 0.5 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceLipLowerRight" + scale="0.0 0.0 0.0" + offset="0.0 0.0038 0.0" /> + + <bone + name="mFaceLipLowerLeft" + scale="0.0 0.0 0.0" + offset="0.0 -0.0038 0.0" /> + + </param_skeleton> + </param> + + + <param + id="30018" + group="1" + name="Puffy_Upper_Cheeks" + value_min="-1.5" + value_max="2.5"> + <param_skeleton> + + <bone + name="mFaceCheekUpperLeft" + scale="0.15 0.1 0.1" + offset="0.002 0 0.0015" /> + + <bone + name="mFaceCheekUpperRight" + scale="0.15 0.1 0.1" + offset="0.002 0 0.0015" /> + + </param_skeleton> + </param> + + <param + id="30021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + <param_skeleton> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0 -.006" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 0 -.006" /> + + </param_skeleton> + </param> + + <param + id="30023" + group="1" + name="Baggy_Eyes" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 .5" + offset="0 0 -.001" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 .5" + offset="0 0 -.001" /> + + </param_skeleton> + </param> + + <param + id="30014" + group="1" + name="High_Cheek_Bones" + value_min="-.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 0.02" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 0.02" /> + + </param_skeleton> + </param> + + <param + id="30019" + group="1" + name="Upturned_Nose_Tip" + value_min="-1.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0.001 0 -0.0015" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="-0.002 0 0.004" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0.001 0 -0.002" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0.001 0 -0.002" /> + + </param_skeleton> + </param> + + <param + id="30879" + group="1" + sex="male" + name="Male_Package" + value_min="-.5" + value_max="2"> + <param_skeleton> + + <bone + name = "mGroin" + offset = "0.0 0.0 0.0" + scale = ".5 .25 .1" /> + + </param_skeleton> + </param> + </skeleton> <mesh type="hairMesh" - lod="0" + lod="0" file_name="avatar_hair.llm" min_pixel_width="320"> <!-- begin morph targets --> @@ -1113,7 +4122,7 @@ group="1" name="Hair_Volume" label="Hair Volume" - show_simple="true" + show_simple="true" wearable="hair" clothing_morph="true" edit_group="hair_style" @@ -1920,95 +4929,184 @@ ############# --> <param - id="1" - group="0" + id="20001" + group="1" name="Big_Brow" - label="Brow Size" - wearable="shape" - edit_group="shape_head" - edit_group_order="7" - label_min="Small" - label_max="Large" value_min="-.3" - value_max="2" - camera_elevation=".1" - camera_distance=".4" - camera_angle="45"> + value_max="2"> <param_morph /> </param> <param - id="2" - group="0" + id="20002" + group="1" name="Nose_Big_Out" - label="Nose Size" - wearable="shape" - edit_group="shape_nose" - edit_group_order="1" - label_min="Small" - label_max="Large" - show_simple="true" value_min="-0.8" - value_max="2.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="50"> + value_max="2.5"> <param_morph /> </param> <param - id="4" - group="0" + id="20517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> + <param_morph /> + </param> + + <param + id="20020" + group="1" + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5"> + <param_morph /> + </param> + + <param + id="20656" + group="1" + name="Crooked_Nose" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="20004" + group="1" name="Broad_Nostrils" - label="Nostril Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="3" - label_min="Narrow" - label_max="Broad" value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> <param - id="759" - group="0" - name="Low_Septum_Nose" - label="Nostril Division" - wearable="shape" - edit_group="shape_nose" - edit_group_order="3.5" - label_min="High" - label_max="Low" + id="20653" + group="1" + name="Tall_Lips" value_min="-1" - value_max="1.5" - value_default="0.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="2"> <param_morph /> </param> + + <param + id="20506" + group="1" + name="Mouth_Height" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="20764" + group="1" + name="Lip_Cleft_Deep" + value_min="-.5" + value_max="1.2"> + <param_morph/> + </param> <param - id="517" - group="0" - name="Wide_Nose" - label="Nose Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="2" - label_min="Narrow" - label_max="Wide" - show_simple="true" + id="20025" + group="1" + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + <param_morph/> + </param> + + <param + id="20663" + group="1" + name="Shift_Mouth" + value_min="-2" + value_max="2" + value_default="0"> + <param_morph /> + </param> + + <param + id="20035" + group="1" + name="Big_Ears" + value_min="-1" + value_max="2"> + <param_morph/> + </param> + + <param + id="20015" + group="1" + name="Ears_Out" value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1.5"> + <param_morph/> + </param> + + <param + id="20796" + group="1" + name="Pointy_Ears" + value_min="-.4" + value_max="3"> + <param_morph /> + </param> + + <param + id="20185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <param_morph /> + </param> + + <param + id="20665" + group="1" + name="Jaw_Jut" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="20024" + group="1" + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + <param_morph /> + </param> + + <param + id="20650" + group="1" + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_morph /> + </param> + + <param + id="20765" + group="1" + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + <param_morph /> + </param> + + <param + id="20759" + group="1" + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> <param_morph /> </param> @@ -2031,111 +5129,56 @@ </param> <param - id="6" - group="0" + id="20006" + group="1" name="Bulbous_Nose_Tip" - label="Nose Tip Shape" - wearable="shape" - edit_group="shape_nose" - edit_group_order="8" - label_min="Pointy" - label_max="Bulbous" value_min="-.3" - value_max="1" - camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> + value_max="1"> <param_morph /> </param> <param - id="7" - group="0" + id="20007" + group="1" name="Weak_Chin" - label="Chin Angle" - wearable="shape" - edit_group="shape_chin" - edit_group_order="1" - label_min="Chin Out" - label_max="Chin In" value_min="-.5" - value_max=".5" - camera_elevation=".1" - camera_distance=".4" - camera_angle="45"> + value_max=".5"> <param_morph /> </param> <param - id="8" - group="0" + id="20008" + group="1" name="Double_Chin" - label="Chin-Neck" - wearable="shape" - edit_group="shape_chin" - edit_group_order="8" - label_min="Tight Chin" - label_max="Double Chin" value_min="-.5" - value_max="1.5" - camera_elevation="-.1" - camera_distance=".3" - camera_angle="60"> + value_max="1.5"> <param_morph /> </param> <param - id="10" - group="0" + id="20010" + group="1" name="Sunken_Cheeks" - label="Lower Cheeks" - wearable="shape" - edit_group="shape_head" - edit_group_order="9" - label_min="Well-Fed" - label_max="Sunken" - show_simple="true" value_min="-1.5" - value_max="3" - camera_elevation=".1" - camera_distance=".4" - camera_angle="5"> + value_max="3"> <param_morph /> </param> <param - id="11" - group="0" + id="20011" + group="1" name="Noble_Nose_Bridge" - label="Upper Bridge" - wearable="shape" - edit_group="shape_nose" - edit_group_order="5" - label_min="Low" - label_max="High" value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + value_max="1.5"> <param_morph /> </param> <param - id="758" - group="0" + id="20758" + group="1" name="Lower_Bridge_Nose" - label="Lower Bridge" - wearable="shape" - edit_group="shape_nose" - edit_group_order="5.5" - label_min="Low" - label_max="High" value_min="-1.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + value_max="1.5"> <param_morph /> </param> @@ -2175,38 +5218,11 @@ </param> <param - id="14" - group="0" + id="20014" + group="1" name="High_Cheek_Bones" - label="Cheek Bones" - wearable="shape" - edit_group="shape_head" - edit_group_order="10" - label_min="Low" - label_max="High" value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> - <param_morph /> - </param> - - <param - id="15" - group="0" - name="Ears_Out" - label="Ear Angle" - wearable="shape" - edit_group="shape_ears" - edit_group_order="2" - label_min="In" - label_max="Out" - value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> @@ -2229,91 +5245,38 @@ </param> <param - id="17" - group="0" + id="20017" + group="1" name="Square_Jaw" - label="Jaw Shape" - wearable="shape" - edit_group="shape_chin" - edit_group_order="2" - label_min="Pointy" - label_max="Square" value_min="-.5" - value_max="1" - camera_distance=".3" - camera_elevation=".04" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> <param - id="18" - group="0" + id="20018" + group="1" name="Puffy_Upper_Cheeks" - label="Upper Cheeks" - wearable="shape" - edit_group="shape_head" - edit_group_order="8" - label_min="Thin" - label_max="Puffy" value_min="-1.5" - value_max="2.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="2.5"> <param_morph /> </param> <param - id="19" - group="0" + id="20019" + group="1" name="Upturned_Nose_Tip" - label="Nose Tip Angle" - wearable="shape" - edit_group="shape_nose" - edit_group_order="7" - label_min="Downturned" - label_max="Upturned" value_min="-1.5" - value_max="1" - camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> - <param_morph /> - </param> - - <param - id="20" - group="0" - name="Bulbous_Nose" - label="Nose Thickness" - wearable="shape" - edit_group="shape_nose" - edit_group_order="4" - label_min="Thin Nose" - label_max="Bulbous Nose" - show_simple="true" - value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".3"> + value_max="1"> <param_morph /> </param> - + <param - id="21" - group="0" + id="20021" + group="1" name="Upper_Eyelid_Fold" - label="Upper Eyelid Fold" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="5" - label_min="Uncreased" - label_max="Creased" value_min="-0.2" - value_max="1.3" - camera_elevation=".1" - camera_distance=".35"> + value_max="1.3"> <param_morph /> </param> @@ -2336,88 +5299,11 @@ </param> <param - id="23" - group="0" + id="20023" + group="1" name="Baggy_Eyes" - label="Eye Bags" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="6" - label_min="Smooth" - label_max="Baggy" value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="765" - group="0" - name="Puffy_Lower_Lids" - label="Puffy Eyelids" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="6.1" - label_min="Flat" - label_max="Puffy" - value_min="-.3" - value_max="2.5" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="24" - group="0" - name="Wide_Eyes" - label="Eye Opening" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="1.1" - label_min="Narrow" - label_max="Wide" - value_min="-1.5" - value_max="2" - show_simple="true" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="25" - group="0" - name="Wide_Lip_Cleft" - label="Lip Cleft" - wearable="shape" - edit_group="shape_mouth" - edit_group_order="6" - label_min="Narrow" - label_max="Wide" - value_min="-.8" - value_max="1.5" - camera_elevation="0" - camera_distance=".28"> - <param_morph /> - </param> - - <param - id="764" - group="0" - name="Lip_Cleft_Deep" - label="Lip Cleft Depth" - wearable="shape" - edit_group="shape_mouth" - edit_group_order="5.8" - label_min="Shallow" - label_max="Deep" - value_min="-.5" - value_max="1.2" - camera_elevation="0" - camera_distance=".28"> + value_max="1.5"> <param_morph /> </param> @@ -2433,20 +5319,11 @@ </param> <param - id="27" - group="0" + id="20027" + group="1" name="Wide_Nose_Bridge" - label="Bridge Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="6" - label_min="Narrow" - label_max="Wide" value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1.2"> <param_morph /> </param> @@ -2517,60 +5394,6 @@ </param> <param - id="35" - group="0" - name="Big_Ears" - label="Ear Size" - wearable="shape" - edit_group="shape_ears" - edit_group_order="1" - label_min="Small" - label_max="Large" - value_min="-1" - value_max="2" - camera_elevation=".1" - camera_distance=".3" - camera_angle="45"> - <param_morph /> - </param> - - <param - id="796" - group="0" - name="Pointy_Ears" - label="Ear Tips" - wearable="shape" - edit_group="shape_ears" - edit_group_order="4" - label_min="Flat" - label_max="Pointy" - value_min="-.4" - value_max="3" - camera_elevation=".1" - camera_distance=".3" - camera_angle="45"> - <param_morph /> - </param> - - <param - id="185" - group="0" - name="Deep_Chin" - label="Chin Depth" - wearable="shape" - edit_group="shape_chin" - edit_group_order="3" - label_min="Shallow" - label_max="Deep" - value_min="-1" - value_max="1" - camera_elevation=".1" - camera_distance=".4" - camera_angle="30"> - <param_morph /> - </param> - - <param id="186" group="1" name="Egg_Head" @@ -2667,24 +5490,6 @@ </param> <param - id="506" - group="0" - name="Mouth_Height" - wearable="shape" - label="Mouth Position" - show_simple="true" - edit_group="shape_mouth" - edit_group_order="4" - label_min="High" - label_max="Low" - value_min="-2" - value_max="2" - camera_distance=".3" - camera_elevation=".04"> - <param_morph /> - </param> - - <param id="633" group="1" name="Fat_Head" @@ -2726,76 +5531,14 @@ </param> <param - id="650" - group="0" - name="Eyelid_Corner_Up" - label="Outer Eye Corner" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="4" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".30"> - <param_morph /> - </param> - - <param - id="880" - group="0" + id="20880" + group="1" name="Eyelid_Inner_Corner_Up" - label="Inner Eye Corner" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="4.2" - label_min="Corner Down" - label_max="Corner Up" value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".30"> + value_max="1.2"> <param_morph /> </param> - - <param - id="653" - group="0" - name="Tall_Lips" - wearable="shape" - label="Lip Fullness" - show_simple="true" - edit_group="shape_mouth" - edit_group_order="2" - label_min="Less Full" - label_max="More Full" - value_min="-1" - value_max="2" - camera_distance=".3" - camera_elevation=".04"> - <param_morph /> - </param> - - <param - id="656" - group="0" - name="Crooked_Nose" - wearable="shape" - label="Crooked Nose" - edit_group="shape_nose" - edit_group_order="9" - label_min="Nose Left" - label_max="Nose Right" - value_min="-2" - value_max="2" - camera_distance=".3" - camera_elevation=".04" - camera_angle="-20"> - <param_morph /> - </param> - <param id="657" group="1" @@ -2899,25 +5642,6 @@ </param> <param - id="663" - group="0" - name="Shift_Mouth" - wearable="shape" - label="Shift Mouth" - edit_group="shape_mouth" - edit_group_order="7" - label_min="Shift Left" - label_max="Shift Right" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".35" - camera_elevation=".04" - camera_angle="-20"> - <param_morph /> - </param> - - <param id="664" group="0" name="Pop_Eye" @@ -2936,40 +5660,12 @@ </param> <param - id="760" - group="0" + id="20760" + group="1" name="Jaw_Angle" - wearable="shape" - label="Jaw Angle" - edit_group="shape_chin" - edit_group_order="3.5" - label_min="Low Jaw" - label_max="High Jaw" value_min="-1.2" value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04" - camera_angle="70"> - <param_morph /> - </param> - - <param - id="665" - group="0" - name="Jaw_Jut" - wearable="shape" - label="Jaw Jut" - edit_group="shape_chin" - edit_group_order="4" - label_min="Overbite" - label_max="Underbite" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04" - camera_angle="70"> + value_default="0"> <param_morph /> </param> @@ -3413,41 +6109,6 @@ <param shared="1" - id="21" - group="0" - name="Upper_Eyelid_Fold" - label="Upper Eyelid Fold" - wearable="shape" - edit_group="shape_eyes" - label_min="Uncreased" - label_max="Creased" - value_min="-0.2" - value_max="1.3" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - shared="1" - id="24" - group="0" - name="Wide_Eyes" - label="Eye Opening" - wearable="shape" - edit_group="shape_eyes" - label_min="Narrow" - label_max="Wide" - show_simple="true" - value_min="-1.5" - value_max="2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - <param - shared="1" id="186" group="1" name="Egg_Head" @@ -3515,41 +6176,6 @@ <param shared="1" - id="650" - group="0" - name="Eyelid_Corner_Up" - label="Outer Eye Corner" - wearable="shape" - edit_group="shape_eyes" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - - <param - shared="1" - id="880" - group="0" - name="Eyelid_Inner_Corner_Up" - label="Inner Eye Corner" - wearable="shape" - edit_group="shape_eyes" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - <param - shared="1" id="686" group="1" name="Head_Eyes_Big" @@ -3917,7 +6543,51 @@ group="1" name="Muscular_Torso" label="Torso Muscles" - show_simple="true" + sex="male" + show_simple="true" + wearable="shape" + edit_group="shape_torso" + label_min="Regular" + label_max="Muscular" + value_min="0" + value_max="1.4" + camera_elevation=".3" + camera_distance="1.2"> + <param_morph> + <volume_morph + name="L_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> + <volume_morph + name="L_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> + <volume_morph + name="L_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> + <volume_morph + name="R_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> + <volume_morph + name="R_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> + <volume_morph + name="R_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> + </param_morph> + </param> + + <param + id="107" + group="1" + name="Muscular_Torso" + label="Torso Muscles" + sex="female" + show_simple="true" wearable="shape" edit_group="shape_torso" label_min="Regular" @@ -5030,21 +7700,12 @@ </param> <param - id="879" - group="0" + id="20879" + group="1" sex="male" name="Male_Package" - label="Package" - wearable="shape" - edit_group="shape_legs" - edit_group_order="4.6" - label_min="Coin Purse" - label_max="Duffle Bag" - value_default="0" value_min="-.5" - value_max="2" - camera_angle="60" - camera_distance=".6"> + value_max="2"> <param_morph /> </param> @@ -9384,6 +12045,825 @@ render_pass="bump"> <driver_parameters> <param + id="2" + group="0" + name="Nose_Big_Out" + label="Nose Size" + wearable="shape" + edit_group="shape_nose" + edit_group_order="1" + label_min="Small" + label_max="Large" + show_simple="true" + value_min="-0.8" + value_max="2.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="50"> + <param_driver> + <driven + id="20002" /> + <driven + id="30002" /> + </param_driver> + </param> + + <param + id="4" + group="0" + name="Broad_Nostrils" + label="Nostril Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="3" + label_min="Narrow" + label_max="Broad" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20004" /> + <driven + id="30004" /> + </param_driver> + </param> + + <param + id="517" + group="0" + name="Wide_Nose" + label="Nose Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="2" + label_min="Narrow" + label_max="Wide" + show_simple="true" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20517" /> + <driven + id="30517" /> + </param_driver> + </param> + + <param + id="20" + group="0" + name="Bulbous_Nose" + label="Nose Thickness" + wearable="shape" + edit_group="shape_nose" + edit_group_order="4" + label_min="Thin Nose" + label_max="Bulbous Nose" + show_simple="true" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".3"> + <param_driver> + <driven + id="20020" /> + <driven + id="30020" /> + </param_driver> + </param> + + <param + id="656" + group="0" + name="Crooked_Nose" + wearable="shape" + label="Crooked Nose" + edit_group="shape_nose" + edit_group_order="9" + label_min="Nose Left" + label_max="Nose Right" + value_min="-2" + value_max="2" + camera_distance=".3" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20656" /> + <driven + id="30656" /> + </param_driver> + </param> + + <param + id="653" + group="0" + name="Tall_Lips" + wearable="shape" + label="Lip Fullness" + show_simple="true" + edit_group="shape_mouth" + edit_group_order="2" + label_min="Less Full" + label_max="More Full" + value_min="-1" + value_max="2" + camera_distance=".3" + camera_elevation=".04"> + <param_driver> + <driven + id="20653" /> + <driven + id="30653" /> + </param_driver> + </param> + + <param + id="506" + group="0" + name="Mouth_Height" + wearable="shape" + label="Mouth Position" + show_simple="true" + edit_group="shape_mouth" + edit_group_order="4" + label_min="High" + label_max="Low" + value_min="-2" + value_max="2" + camera_distance=".3" + camera_elevation=".04"> + <param_driver> + <driven + id="20506" /> + <driven + id="30506" /> + </param_driver> + </param> + + <param + id="764" + group="0" + name="Lip_Cleft_Deep" + label="Lip Cleft Depth" + wearable="shape" + edit_group="shape_mouth" + edit_group_order="5.8" + label_min="Shallow" + label_max="Deep" + value_min="-.5" + value_max="1.2" + camera_elevation="0" + camera_distance=".28"> + <param_driver> + <driven + id="20764" /> + <driven + id="30764" /> + </param_driver> + </param> + + <param + id="25" + group="0" + name="Wide_Lip_Cleft" + label="Lip Cleft" + wearable="shape" + edit_group="shape_mouth" + edit_group_order="6" + label_min="Narrow" + label_max="Wide" + value_min="-.8" + value_max="1.5" + camera_elevation="0" + camera_distance=".28"> + <param_driver> + <driven + id="20025" /> + <driven + id="30025" /> + </param_driver> + </param> + + <param + id="663" + group="0" + name="Shift_Mouth" + wearable="shape" + label="Shift Mouth" + edit_group="shape_mouth" + edit_group_order="7" + label_min="Shift Left" + label_max="Shift Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".35" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20663" /> + + <driven + id="31663" + min1="-2" + max1="-2" + max2="-2" + min2="0" /> + <driven + id="32663" + min1="0" + max1="2" + max2="2" + min2="2" /> + </param_driver> + </param> + + <param + id="35" + group="0" + name="Big_Ears" + label="Ear Size" + wearable="shape" + edit_group="shape_ears" + edit_group_order="1" + label_min="Small" + label_max="Large" + value_min="-1" + value_max="2" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> + <param_driver> + <driven + id="20035" /> + <driven + id="30035" /> + </param_driver> + </param> + + <param + id="15" + group="0" + name="Ears_Out" + label="Ear Angle" + wearable="shape" + edit_group="shape_ears" + edit_group_order="2" + label_min="In" + label_max="Out" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20015" /> + <driven + id="30015" /> + </param_driver> + </param> + + <param + id="796" + group="0" + name="Pointy_Ears" + label="Ear Tips" + wearable="shape" + edit_group="shape_ears" + edit_group_order="4" + label_min="Flat" + label_max="Pointy" + value_min="-.4" + value_max="3" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> + <param_driver> + <driven + id="20796" /> + <driven + id="30796" /> + </param_driver> + </param> + + <param + id="185" + group="0" + name="Deep_Chin" + label="Chin Depth" + wearable="shape" + edit_group="shape_chin" + edit_group_order="3" + label_min="Shallow" + label_max="Deep" + value_min="-1" + value_max="1" + camera_elevation=".1" + camera_distance=".4" + camera_angle="30"> + <param_driver> + <driven + id="20185" /> + <driven + id="30185" /> + </param_driver> + </param> + + <param + id="760" + group="0" + name="Jaw_Angle" + wearable="shape" + label="Jaw Angle" + edit_group="shape_chin" + edit_group_order="3.5" + label_min="Low Jaw" + label_max="High Jaw" + value_min="-1.2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04" + camera_angle="70"> + <param_driver> + <driven + id="20760" /> + <driven + id="30760" /> + </param_driver> + </param> + + + <param + id="665" + group="0" + name="Jaw_Jut" + wearable="shape" + label="Jaw Jut" + edit_group="shape_chin" + edit_group_order="4" + label_min="Overbite" + label_max="Underbite" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04" + camera_angle="70"> + <param_driver> + <driven + id="20665" /> + <driven + id="30665" /> + </param_driver> + </param> + + <param + id="6" + group="0" + name="Bulbous_Nose_Tip" + label="Nose Tip Shape" + wearable="shape" + edit_group="shape_nose" + edit_group_order="8" + label_min="Pointy" + label_max="Bulbous" + value_min="-.3" + value_max="1" + camera_elevation=".1" + camera_distance=".35" + camera_angle="15"> + <param_driver> + <driven + id="20006" /> + <driven + id="30006" /> + </param_driver> + </param> + + <param + id="7" + group="0" + name="Weak_Chin" + label="Chin Angle" + wearable="shape" + edit_group="shape_chin" + edit_group_order="1" + label_min="Chin Out" + label_max="Chin In" + value_min="-.5" + value_max=".5" + camera_elevation=".1" + camera_distance=".4" + camera_angle="45"> + <param_driver> + <driven + id="20007" /> + <driven + id="30007" /> + </param_driver> + </param> + + <param + id="8" + group="0" + name="Double_Chin" + label="Chin-Neck" + wearable="shape" + edit_group="shape_chin" + edit_group_order="8" + label_min="Tight Chin" + label_max="Double Chin" + value_min="-.5" + value_max="1.5" + camera_elevation="-.1" + camera_distance=".3" + camera_angle="60"> + <param_driver> + <driven + id="20008" /> + <driven + id="30008" /> + </param_driver> + </param> + + + <param + id="24" + group="0" + name="Wide_Eyes" + label="Eye Opening" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="1.1" + label_min="Narrow" + label_max="Wide" + value_min="-1.5" + value_max="2" + show_simple="true" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20024" /> + <driven + id="30024" /> + </param_driver> + </param> + + <param + id="650" + group="0" + name="Eyelid_Corner_Up" + label="Outer Eye Corner" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="4" + label_min="Corner Down" + label_max="Corner Up" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".30"> + <param_driver> + <driven + id="20650" /> + <driven + id="30650" /> + </param_driver> + </param> + + <param + id="880" + group="0" + name="Eyelid_Inner_Corner_Up" + label="Inner Eye Corner" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="4.2" + label_min="Corner Down" + label_max="Corner Up" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".30"> + <param_driver> + <driven + id="20880" /> + <driven + id="30880" /> + </param_driver> + </param> + + <param + id="21" + group="0" + name="Upper_Eyelid_Fold" + label="Upper Eyelid Fold" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="5" + label_min="Uncreased" + label_max="Creased" + value_min="-0.2" + value_max="1.3" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20021" /> + <driven + id="30021" /> + </param_driver> + </param> + + <param + id="23" + group="0" + name="Baggy_Eyes" + label="Eye Bags" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="6" + label_min="Smooth" + label_max="Baggy" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20023" /> + <driven + id="30023" /> + </param_driver> + </param> + + <param + id="765" + group="0" + name="Puffy_Lower_Lids" + label="Puffy Eyelids" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="6.1" + label_min="Flat" + label_max="Puffy" + value_min="-.3" + value_max="2.5" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20765" /> + <driven + id="30765" /> + </param_driver> + </param> + + <param + id="1" + group="0" + name="Big_Brow" + label="Brow Size" + wearable="shape" + edit_group="shape_head" + edit_group_order="7" + label_min="Small" + label_max="Large" + value_min="-.3" + value_max="2" + camera_elevation=".1" + camera_distance=".4" + camera_angle="45"> + <param_driver> + <driven + id="20001" /> + <driven + id="30001" /> + </param_driver> + </param> + + <param + id="11" + group="0" + name="Noble_Nose_Bridge" + label="Upper Bridge" + wearable="shape" + edit_group="shape_nose" + edit_group_order="5" + label_min="Low" + label_max="High" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="70"> + <param_driver> + <driven + id="20011" /> + <driven + id="30011" /> + </param_driver> + </param> + + <param + id="758" + group="0" + name="Lower_Bridge_Nose" + label="Lower Bridge" + wearable="shape" + edit_group="shape_nose" + edit_group_order="5.5" + label_min="Low" + label_max="High" + value_min="-1.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="70"> + <param_driver> + <driven + id="20758" /> + <driven + id="30758" /> + </param_driver> + </param> + + <param + id="27" + group="0" + name="Wide_Nose_Bridge" + label="Bridge Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="6" + label_min="Narrow" + label_max="Wide" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20027" /> + <driven + id="30027" /> + </param_driver> + </param> + + <param + id="759" + group="0" + name="Low_Septum_Nose" + label="Nostril Division" + wearable="shape" + edit_group="shape_nose" + edit_group_order="3.5" + label_min="High" + label_max="Low" + value_min="-1" + value_max="1.5" + value_default="0.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20759" /> + <driven + id="30759" /> + </param_driver> + </param> + + + <param + id="10" + group="0" + name="Sunken_Cheeks" + label="Lower Cheeks" + wearable="shape" + edit_group="shape_head" + edit_group_order="9" + label_min="Well-Fed" + label_max="Sunken" + show_simple="true" + value_min="-1.5" + value_max="3" + camera_elevation=".1" + camera_distance=".4" + camera_angle="5"> + <param_driver> + <driven + id="20010" /> + <driven + id="30010" /> + </param_driver> + </param> + + <param + id="17" + group="0" + name="Square_Jaw" + label="Jaw Shape" + wearable="shape" + edit_group="shape_chin" + edit_group_order="2" + label_min="Pointy" + label_max="Square" + value_min="-.5" + value_max="1" + camera_distance=".3" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20017" /> + <driven + id="30017" /> + </param_driver> + </param> + + <param + id="18" + group="0" + name="Puffy_Upper_Cheeks" + label="Upper Cheeks" + wearable="shape" + edit_group="shape_head" + edit_group_order="8" + label_min="Thin" + label_max="Puffy" + value_min="-1.5" + value_max="2.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20018" /> + <driven + id="30018" /> + </param_driver> + </param> + + <param + id="14" + group="0" + name="High_Cheek_Bones" + label="Cheek Bones" + wearable="shape" + edit_group="shape_head" + edit_group_order="10" + label_min="Low" + label_max="High" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20014" /> + <driven + id="30014" /> + </param_driver> + </param> + + <param + id="19" + group="0" + name="Upturned_Nose_Tip" + label="Nose Tip Angle" + wearable="shape" + edit_group="shape_nose" + edit_group_order="7" + label_min="Downturned" + label_max="Upturned" + value_min="-1.5" + value_max="1" + camera_elevation=".1" + camera_distance=".35" + camera_angle="15"> + <param_driver> + <driven + id="20019" /> + <driven + id="30019" /> + </param_driver> + </param> + + <param id="828" group="0" name="Loose Upper Clothing" @@ -9807,6 +13287,20 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30505" + min1="0" + max1="0" + max2="0" + min2=".5" /> + <driven + id="31505" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -9817,8 +13311,8 @@ render_pass="bump"> edit_group="shape_mouth" edit_group_order="3.2" name="Lip Ratio" - label="Lip Ratio" - show_simple="true" + label="Lip Ratio" + show_simple="true" label_min="More Upper Lip" label_max="More Lower Lip" value_min="0" @@ -9841,6 +13335,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30797" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="30798" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -9866,6 +13375,10 @@ render_pass="bump"> <driven id="30" /> + + <driven + id="30155" /> + </param_driver> </param> @@ -10548,6 +14061,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="31629" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="32629" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -10574,6 +14102,29 @@ render_pass="bump"> <driven id="186" /> + + <driven + min1="-1.3" + max1="-1.3" + max2="-1.3" + min2="1" + id="40017" /> + + <driven + id="40185" /> + + <driven + id="41629" /> + + <driven + id="42629" /> + + <driven + id="40007" /> + + <driven + id="40647" /> + </param_driver> </param> @@ -10600,6 +14151,10 @@ render_pass="bump"> <driven id="187" /> + + <driven + id="30647" /> + </param_driver> </param> @@ -10630,7 +14185,7 @@ render_pass="bump"> min2=".5" /> <driven - id="106" + id="107" min1=".5" max1="1" max2="1" @@ -10759,7 +14314,22 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30658" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="30657" + min1=".5" + max1="1" + max2="1" + min2="1" /> </param_driver> + </param> <param @@ -10822,7 +14392,7 @@ render_pass="bump"> edit_group="shape_head" edit_group_order="1" name="Head Size" - label="Head Size" + label="Head Size" label_min="Small Head" label_max="Big Head" show_simple="true" @@ -10856,13 +14426,13 @@ render_pass="bump"> edit_group="shape_eyes" edit_group_order="1" name="Eye Size" - label="Eye Size" + label="Eye Size" label_min="Beady Eyes" label_max="Anime Eyes" value_min="0" value_max="1" value_default=".5" - show_simple="true" + show_simple="true" camera_elevation=".1" camera_distance=".35"> <param_driver> @@ -11169,6 +14739,31 @@ render_pass="bump"> </param> <param + id="879" + group="0" + sex="male" + name="Male_Package" + label="Package" + wearable="shape" + edit_group="shape_legs" + edit_group_order="4.6" + label_min="Coin Purse" + label_max="Duffle Bag" + value_default="0" + value_min="-.5" + value_max="2" + camera_angle="60" + camera_distance=".6"> + <param_driver> + <driven + id="20879" /> + + <driven + id="30879" /> + </param_driver> + </param> + + <param id="841" group="0" name="Bowed_Legs" diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml index 6b07bbc1d3..350ba7b841 100644 --- a/indra/newview/character/avatar_skeleton.xml +++ b/indra/newview/character/avatar_skeleton.xml @@ -1,81 +1,229 @@ -<?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="132" num_collision_volumes="26" version="2.0"> + <bone aliases="hip avatar_mPelvis" connected="false" end="0.000 0.000 0.084" group="Torso" 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"> + <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="Torso" 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="Torso" 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="Torso" 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="Torso" 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" connected="false" end="0.000 0.000 0.033" group="Extra" 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"/> + <bone aliases="avatar_mEyeRight" connected="false" end="0.100 0.000 0.000" group="Extra" 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"/> + <bone aliases="avatar_mEyeLeft" connected="false" end="0.100 0.000 0.000" group="Extra" 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"/> + <bone connected="false" end="0.100 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.100 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" 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"> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.022 0.015 0.001" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.022 -0.015 0.001" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"> + <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 connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.053 0.000 -0.032" pos="0.053 0.000 -0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + <bone connected="false" 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"/> + <bone connected="false" 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"/> + <bone connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.061 0.000 -0.010" group="Mouth" name="mFaceTeethLower" pivot="0.020 0.000 -0.044" pos="0.020 0.000 -0.044" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.061 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone aliases="lCollar avatar_mCollarLeft" connected="false" end="0.000 0.079 0.000" group="Arms" 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"> + <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="Arms" 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="Arms" 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="Arms" 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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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" connected="false" end="0.000 -0.079 0.000" group="Arms" 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"> + <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="Arms" 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="Arms" 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="Arms" 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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <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 connected="false" 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"> + <bone connected="false" 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"> + <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 connected="false" 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"> + <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" connected="false" end="-0.001 0.049 -0.491" group="Legs" 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"> + <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="Legs" 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="Legs" 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="Extra" 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="Extra" 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" connected="false" end="-0.001 -0.046 -0.491" group="Legs" 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"> + <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="Legs" 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="Legs" 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="Extra" 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="Extra" 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 connected="false" 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"> + <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 connected="false" 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"/> + <bone connected="false" 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"> + <bone connected="false" 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"> + <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.112 0.000 -0.061" 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 connected="true" end="0.105 0.008 0.001" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone connected="false" 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"> + <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.112 0.000 -0.061" 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 connected="true" end="0.105 0.008 0.001" group="Limb" name="mHindLimb4Right" pivot="0.112 -0.000 -0.061" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="extended" /> + </bone> + </bone> + </bone> + </bone> + </bone> +</linden_skeleton> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d933537d2e..b00c960822 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4176,6 +4176,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()) @@ -4193,6 +4195,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 { @@ -4222,8 +4225,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 100644 --- 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 b6d02ea2f8..5287f98827 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -99,6 +99,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 4c16c542d6..843cd9b249 100644 --- 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" @@ -56,8 +57,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; @@ -1461,7 +1460,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); @@ -1470,7 +1475,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); @@ -1482,7 +1488,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); } @@ -1496,9 +1503,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); @@ -1525,26 +1532,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 || @@ -1595,60 +1613,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; @@ -1728,34 +1705,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 e5df417ca9..d33a138e94 100644 --- 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 100644 --- 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 ffeebfd256..0f0fafcce6 100644 --- 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" @@ -489,10 +489,18 @@ void LLFloaterModelPreview::onClickCalculateBtn() bool upload_skinweights = childGetValue("upload_skin").asBoolean(); bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); + if (upload_joint_positions) + { + // Diagnostic message showing list of joints for which joint offsets are defined. + // FIXME - given time, would be much better to put this in the UI, in updateStatusMessages(). + mModelPreview->getPreviewAvatar()->showAttachmentPosOverrides(); + } + mUploadModelUrl.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false, + childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, + mUploadModelUrl, false, getWholeModelFeeObserverHandle()); toggleCalculateButton(false); @@ -1190,7 +1198,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mPhysicsSearchLOD( LLModel::LOD_PHYSICS ) , mResetJoints( false ) , mModelNoErrors( true ) -, mRigParityWithScene( false ) , mLastJointUpdate( false ) { mNeedsUpdate = TRUE; @@ -1731,6 +1738,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(); @@ -1773,6 +1794,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, @@ -1783,6 +1807,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")); @@ -3307,14 +3333,17 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLVector3 pos(vf.mPositions[i].getF32ptr()); const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this LLVector4 w(0,0,0,0); for (U32 i = 0; i < weight_list.size(); ++i) { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f); F32 joint = (F32) weight_list[i].mJointIdx; w.mV[i] = joint + wght; + llassert(w.mV[i]-(S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values + //should not cause floating point precision issues. } *(weights_strider++) = w; @@ -3368,19 +3397,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 ) @@ -3509,6 +3525,7 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget ) pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() ); } + //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- @@ -4002,20 +4019,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) @@ -4040,58 +4043,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); @@ -4125,6 +4102,22 @@ BOOL LLModelPreview::render() } } } + + if (joint_positions) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + gDebugProgram.bind(); + } + getPreviewAvatar()->renderCollisionVolumes(); + getPreviewAvatar()->renderBones(); + if (shader) + { + shader->bind(); + } + } + } } @@ -4261,7 +4254,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 a73ca50260..217ac35888 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -260,6 +260,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(); } @@ -300,11 +301,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; @@ -352,7 +349,6 @@ private: bool mLoading; U32 mLoadState; bool mResetJoints; - bool mRigParityWithScene; bool mModelNoErrors; std::map<std::string, bool> mViewOption; @@ -410,7 +406,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 36bdcf4d89..8429be2f49 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -364,6 +364,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, 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)); @@ -807,6 +808,16 @@ void LLFloaterPreference::onAvatarImpostorsEnable() 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() { @@ -1251,6 +1262,10 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); + 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"); @@ -2004,7 +2019,7 @@ void LLFloaterPreference::onClickAutoReplace() void LLFloaterPreference::onClickSpellChecker() { - LLFloaterReg::showInstance("prefs_spellchecker"); + LLFloaterReg::showInstance("prefs_spellchecker"); } void LLFloaterPreference::onClickAdvanced() diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index fa0c09e97a..fd45129c72 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -117,6 +117,8 @@ protected: void onVertexShaderEnable(); // callback for when client turns on impostors void onAvatarImpostorsEnable(); + // 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 100644 --- 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..732afdfa9a --- /dev/null +++ b/indra/newview/llskinningutil.cpp @@ -0,0 +1,364 @@ +/** +* @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->mJointRemap.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(); + + F32 wsum = 0.0; + for (U32 k=0; k<4; ++k) + { + S32 i = llfloor(w[k]); + llassert(i>=0); + llassert(i<max_joints); + wsum += w[k]-i; + } + llassert(wsum > 0.0f); + } + } +#endif +} + +// static +void LLSkinningUtil::getPerVertexSkinMatrix( + F32* weights, + LLMatrix4a* mat, + bool handle_bad_scale, + LLMatrix4a& final_mat, + U32 max_joints) +{ + bool valid_weights = true; + 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); + valid_weights = false; + } + 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); + } + // SL-366 - with weight validation/cleanup code, it should no longer be + // possible to hit the bad scale case. + llassert(valid_weights); +} + 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 b0eb4137a7..0fd36766b3 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -3213,6 +3213,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) @@ -3371,6 +3376,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); @@ -3661,6 +3671,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 88fbd233b8..79b5130bd3 100644 --- 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() @@ -194,6 +195,8 @@ #include "lltoolbarview.h" #include "llexperiencelog.h" +#include "llstacktrace.h" + #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -1216,7 +1219,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 100644 --- 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 16f40fb747..f2680ce25d 100644 --- 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 @@ -741,6 +755,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 100644 --- 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 100644 --- 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 100644 --- 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 100644 --- 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 99a9ed1d75..0b0d12c5b8 100644 --- 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 @@ -5998,6 +5998,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 { @@ -8984,6 +8996,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 100644 --- 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 100644 --- 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/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 0f73515b5d..8d482b2e34 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -70,7 +70,7 @@ private: }; // Private local functions -static std::string asset_id_to_filename(const LLUUID &asset_id); +static std::string asset_id_to_filename(const LLUUID &asset_id, const ELLPath dir_spec); LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) : LLWearable(), @@ -508,7 +508,7 @@ void LLViewerWearable::saveNewAsset() const // LL_INFOS() << "LLViewerWearable::saveNewAsset() type: " << getTypeName() << LL_ENDL; //LL_INFOS() << *this << LL_ENDL; - const std::string filename = asset_id_to_filename(mAssetID); + const std::string filename = asset_id_to_filename(mAssetID, LL_PATH_CACHE); if(! exportFile(filename)) { std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); @@ -520,6 +520,12 @@ void LLViewerWearable::saveNewAsset() const return; } + if (gSavedSettings.getBOOL("LogWearableAssetSave")) + { + const std::string log_filename = asset_id_to_filename(mAssetID, LL_PATH_LOGS); + exportFile(log_filename); + } + // save it out to database if( gAssetStorage ) { @@ -568,7 +574,7 @@ void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* } // Delete temp file - const std::string src_filename = asset_id_to_filename(new_asset_id); + const std::string src_filename = asset_id_to_filename(new_asset_id, LL_PATH_CACHE); LLFile::remove(src_filename); // delete the context data @@ -605,10 +611,10 @@ std::ostream& operator<<(std::ostream &s, const LLViewerWearable &w) return s; } -std::string asset_id_to_filename(const LLUUID &asset_id) +std::string asset_id_to_filename(const LLUUID &asset_id, const ELLPath dir_spec) { std::string asset_id_string; asset_id.toString(asset_id_string); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id_string) + ".wbl"; + std::string filename = gDirUtilp->getExpandedFilename(dir_spec,asset_id_string) + ".wbl"; return filename; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b9dd43f061..0728509bcd 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -106,6 +106,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; @@ -214,26 +216,8 @@ 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 +struct LLAppearanceMessageContents: public LLRefCount { LLAppearanceMessageContents(): mAppearanceVersion(-1), @@ -253,49 +237,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 @@ -1111,7 +1052,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) { @@ -1142,6 +1082,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")); } @@ -1395,18 +1338,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; @@ -1418,6 +1421,67 @@ void LLVOAvatar::renderCollisionVolumes() addDebugText(ostr.str()); } +void LLVOAvatar::renderBones() +{ + LLGLEnable blend(GL_BLEND); + + 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 LLVector3 RIGGED_COLOR_OCCLUDED(0.0f, 1.0f, 1.0f); + static LLVector3 RIGGED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + + static F32 SPHERE_SCALEF = 0.001f; + + for (; iter != end; ++iter) + { + LLJoint* jointp = *iter; + if (!jointp) + { + continue; + } + + jointp->updateWorldMatrix(); + LLJoint::SupportCategory sc = jointp->getSupport(); + LLVector3 occ_color, visible_color; + + if (jointIsRiggedTo(jointp->getName())) + { + occ_color = RIGGED_COLOR_OCCLUDED; + visible_color = RIGGED_COLOR_VISIBLE; + } + else + { + 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(); + } +} + + void LLVOAvatar::renderJoints() { std::ostringstream ostr; @@ -1525,7 +1589,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(); @@ -1734,6 +1798,116 @@ void LLVOAvatar::buildCharacter() mMeshValid = TRUE; } +//----------------------------------------------------------------------------- +// resetVisualParams() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetVisualParams() +{ + // Skeletal params + { + LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); + iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); + ++iter) + { + LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter; + LLPolySkeletalDistortion *param = dynamic_cast<LLPolySkeletalDistortion*>(getVisualParam(info->getID())); + *param = LLPolySkeletalDistortion(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + } + } + + // Driver parameters + for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) + { + LLDriverParamInfo *info = *iter; + LLDriverParam *param = dynamic_cast<LLDriverParam*>(getVisualParam(info->getID())); + LLDriverParam::entry_list_t driven_list = param->getDrivenList(); + *param = LLDriverParam(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + param->setDrivenList(driven_list); + } +} + +//----------------------------------------------------------------------------- +// resetSkeleton() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetSkeleton() +{ + LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL; + if (!mLastProcessedAppearance) + { + LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL; + return; + } + + // Clear all attachment pos overrides + clearAttachmentPosOverrides(); + + // Note that we call buildSkeleton twice in this function. The first time is + // just to get the right scale for the collision volumes, because + // this will be used in setting the mJointScales for the + // LLPolySkeletalDistortions of which the CVs are children. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset some params to default state, without propagating changes downstream. + resetVisualParams(); + + // Now we have to reset the skeleton again, because its state + // got clobbered by the resetVisualParams() calls + // above. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset attachment points (buildSkeleton only does bones and CVs) + bool ignore_hud_joints = true; + initAttachmentPoints(ignore_hud_joints); + + // Fix up collision volumes + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + LLPolyMorphTarget *poly_morph = dynamic_cast<LLPolyMorphTarget*>(param); + if (poly_morph) + { + // This is a kludgy way to correct for the fact that the + // collision volumes have been reset out from under the + // poly morph sliders. + F32 delta_weight = poly_morph->getLastWeight() - poly_morph->getDefaultWeight(); + poly_morph->applyVolumeChanges(delta_weight); + } + } + + // Reset tweakable params to preserved state + bool slam_params = true; + applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + + updateVisualParams(); + + // Restore attachment pos overrides + rebuildAttachmentPosOverrides(); + + // Restart animations + resetAnimations(); + + LL_DEBUGS("Avatar") << avString() << " reset ends" << LL_ENDL; +} //----------------------------------------------------------------------------- // releaseMeshData() @@ -1745,8 +1919,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(); @@ -1956,17 +2128,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) { @@ -2074,6 +2241,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 +3247,7 @@ void LLVOAvatar::idleUpdateBelowWater() void LLVOAvatar::slamPosition() { gAgent.setPositionAgent(getPositionAgent()); + // SL-315 mRoot->setWorldPosition(getPositionAgent()); // teleport setChanged(TRANSLATED); if (mDrawable.notNull()) @@ -3376,6 +3546,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() ); } @@ -3430,6 +3601,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (newPosition != mRoot->getXform()->getWorldPosition()) { mRoot->touch(); + // SL-315 mRoot->setWorldPosition( newPosition ); // regular update } @@ -3593,6 +3765,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) { LLVector3 pos = mDrawable->getPosition(); pos += getHoverOffset() * mDrawable->getRotation(); + // SL-315 mRoot->setPosition(pos); mRoot->setRotation(mDrawable->getRotation()); } @@ -3623,6 +3796,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) LLVector3 pos = mRoot->getWorldPosition(); pos.mV[VZ] += off_z; mRoot->touch(); + // SL-315 mRoot->setWorldPosition(pos); } } @@ -5097,8 +5271,66 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id) return false; } +bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name) +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && jointIsRiggedTo(joint_name, attached_object)) + { + return true; + } + } + } + return false; +} + +bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo) +{ + // Process all children + LLViewerObject::const_child_list_t& children = vo->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + if (jointIsRiggedTo(joint_name,childp)) + { + return true; + } + } + + const LLVOVolume *vobj = dynamic_cast<const LLVOVolume*>(vo); + if (!vobj) + { + return false; + } + + LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + + if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) + { + if (std::find(pSkinData->mJointNames.begin(), pSkinData->mJointNames.end(), joint_name) != + pSkinData->mJointNames.end()) + { + return true; + } + } + + return false; +} + 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(); @@ -5106,11 +5338,49 @@ void LLVOAvatar::clearAttachmentPosOverrides() for (; iter != end; ++iter) { LLJoint* pJoint = (*iter); - pJoint->clearAttachmentPosOverrides(); + if (pJoint) + { + pJoint->clearAttachmentPosOverrides(); + } } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + attachment_pt->clearAttachmentPosOverrides(); + } + } } //----------------------------------------------------------------------------- +// rebuildAttachmentPosOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::rebuildAttachmentPosOverrides() +{ + LLScopedContextString str("rebuildAttachmentPosOverrides " + getFullname()); + + // Attachment points + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); + at_it != attachment_pt->mAttachedObjects.end(); ++at_it) + { + addAttachmentPosOverridesForObject(*at_it); + } + } + } +} +//----------------------------------------------------------------------------- // addAttachmentPosOverridesForObject //----------------------------------------------------------------------------- void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) @@ -5120,7 +5390,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(); @@ -5148,9 +5420,13 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) { const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) + const int jointCnt = pSkinData->mJointNames.size(); + if ((bindCnt > 0) && (bindCnt != jointCnt)) + { + LL_WARNS_ONCE() << "invalid mesh, bindCnt " << bindCnt << "!= jointCnt " << jointCnt << ", joint overrides will be ignored." << LL_ENDL; + } + if ((bindCnt > 0) && (bindCnt == jointCnt)) { - const int jointCnt = pSkinData->mJointNames.size(); const F32 pelvisZOffset = pSkinData->mPelvisOffset; const LLUUID& mesh_id = pSkinData->mMeshID; bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; @@ -5164,14 +5440,14 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) { pJoint->setId( currentId ); const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() ); - - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { - pelvisGotSet = true; - } + //Set the joint position + pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() ); + + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pelvisGotSet = true; + } } } if (pelvisZOffset != 0.0F) @@ -5191,6 +5467,98 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) } //----------------------------------------------------------------------------- +// getAttachmentOverrideNames +//----------------------------------------------------------------------------- +void LLVOAvatar::getAttachmentOverrideNames(std::set<std::string>& names) const +{ + LLVector3 pos; + LLUUID mesh_id; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + names.insert(pJoint->getName()); + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + names.insert(attachment_pt->getName()); + } + } + +} + +//----------------------------------------------------------------------------- +// showAttachmentPosOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::showAttachmentPosOverrides(bool verbose) const +{ + std::set<std::string> joint_names; + getAttachmentOverrideNames(joint_names); + if (joint_names.size()) + { + std::stringstream ss; + std::copy(joint_names.begin(), joint_names.end(), std::ostream_iterator<std::string>(ss, ",")); + LL_INFOS() << getFullname() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL; + } + else + { + LL_INFOS() << getFullname() << " no attachment positions defined for any joints" << "\n" << LL_ENDL; + } + + if (!verbose) + { + return; + } + + LLVector3 pos; + LLUUID mesh_id; + S32 count = 0; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + pJoint->showAttachmentPosOverrides(getFullname()); + count++; + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + attachment_pt->showAttachmentPosOverrides(getFullname()); + count++; + } + } + + if (count) + { + LL_DEBUGS("Avatar") << avString() << " end of pos overrides" << LL_ENDL; + LL_DEBUGS("Avatar") << "=================================" << LL_ENDL; + } +} + +//----------------------------------------------------------------------------- // resetJointPositionsOnDetach //----------------------------------------------------------------------------- void LLVOAvatar::resetJointPositionsOnDetach(LLViewerObject *vo) @@ -5241,6 +5609,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) ); } } @@ -5372,83 +5741,99 @@ BOOL LLVOAvatar::loadSkeletonNode () return FALSE; } - // ATTACHMENTS - { - LLAvatarXmlInfo::attachment_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); - iter != sAvatarXmlInfo->mAttachmentInfoList.end(); - ++iter) - { - LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; - if (!isSelf() && info->mJointName == "mScreen") - { //don't process screen joint for other avatars - continue; - } + bool ignore_hud_joints = false; + initAttachmentPoints(ignore_hud_joints); - LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); + return TRUE; +} - attachment->setName(info->mName); - LLJoint *parentJoint = getJoint(info->mJointName); - if (!parentJoint) - { - LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } +//----------------------------------------------------------------------------- +// initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. +//----------------------------------------------------------------------------- +void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) +{ + LLAvatarXmlInfo::attachment_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++iter) + { + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; + if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) + { + //don't process hud joint for other avatars, or when doing a skeleton reset. + continue; + } - if (info->mHasPosition) - { - attachment->setOriginalPosition(info->mPosition); - } - - if (info->mHasRotation) - { - LLQuaternion rotation; - rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, - info->mRotationEuler.mV[VY] * DEG_TO_RAD, - info->mRotationEuler.mV[VZ] * DEG_TO_RAD); - attachment->setRotation(rotation); - } + S32 attachmentID = info->mAttachmentID; + if (attachmentID < 1 || attachmentID > 255) + { + LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL; + continue; + } - int group = info->mGroup; - if (group >= 0) - { - if (group < 0 || group >= 9) - { - LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL; - } - else - { - attachment->setGroup(group); - } - } + LLViewerJointAttachment* attachment = NULL; + bool newly_created = false; + if (mAttachmentPoints.find(attachmentID) == mAttachmentPoints.end()) + { + attachment = new LLViewerJointAttachment(); + newly_created = true; + } + else + { + attachment = mAttachmentPoints[attachmentID]; + } - S32 attachmentID = info->mAttachmentID; - if (attachmentID < 1 || attachmentID > 255) - { - LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } - if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end()) - { - LL_WARNS() << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } + attachment->setName(info->mName); + 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; + LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL; + } - attachment->setPieSlice(info->mPieMenuSlice); - attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); - attachment->setIsHUDAttachment(info->mIsHUDAttachment); + if (info->mHasPosition) + { + attachment->setOriginalPosition(info->mPosition); + attachment->setDefaultPosition(info->mPosition); + } + + if (info->mHasRotation) + { + LLQuaternion rotation; + rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, + info->mRotationEuler.mV[VY] * DEG_TO_RAD, + info->mRotationEuler.mV[VZ] * DEG_TO_RAD); + attachment->setRotation(rotation); + } - mAttachmentPoints[attachmentID] = attachment; + int group = info->mGroup; + if (group >= 0) + { + if (group < 0 || group > 9) + { + LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL; + } + else + { + attachment->setGroup(group); + } + } - // now add attachment joint - parentJoint->addChild(attachment); - } - } + 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); - return TRUE; + if (newly_created) + { + mAttachmentPoints[attachmentID] = attachment; + + // now add attachment joint + parent_joint->addChild(attachment); + } + } } //----------------------------------------------------------------------------- @@ -6017,6 +6402,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(); @@ -6075,6 +6461,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(); @@ -7121,9 +7508,10 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) wtype = vparam->getWearableType(); } S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight()); - apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n", + apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\" group=\"%d\"/>\n", viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(), - LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str() + LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str(), + viewer_param->getGroup() // param_location_name(vparam->getParamLocation()).c_str() ); } @@ -7190,7 +7578,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); @@ -7202,7 +7590,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; } @@ -7212,7 +7600,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 @@ -7273,7 +7661,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; } } } @@ -7302,9 +7690,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; } @@ -7313,8 +7701,7 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 //----------------------------------------------------------------------------- void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { - static S32 largestSelfCOFSeen(LLViewerInventoryCategory::VERSION_UNKNOWN); - LL_DEBUGS("Avatar") << "starts" << LL_ENDL; + static S32 largest_self_cof_seen(LLViewerInventoryCategory::VERSION_UNKNOWN); bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; @@ -7326,17 +7713,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mLastAppearanceMessageTimer.reset(); - ESex old_sex = getSex(); - - LLAppearanceMessageContents contents; - parseAppearanceMessage(mesgsys, contents); + LLPointer<LLAppearanceMessageContents> contents(new LLAppearanceMessageContents); + parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { - dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents); + dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents); } S32 appearance_version; - if (!resolve_appearance_version(contents, appearance_version)) + if (!resolve_appearance_version(*contents, appearance_version)) { LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL; return; @@ -7348,7 +7733,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) return; } - S32 this_update_cof_version = contents.mCOFVersion; + S32 this_update_cof_version = contents->mCOFVersion; S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion; if( isSelf() ) @@ -7357,18 +7742,18 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) << " last_update_request_cof_version " << last_update_request_cof_version << " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; - if (largestSelfCOFSeen > this_update_cof_version) + if (largest_self_cof_seen > this_update_cof_version) { LL_WARNS("Avatar") << "Already processed appearance for COF version " << - largestSelfCOFSeen << ", discarding appearance with COF " << this_update_cof_version << LL_ENDL; + largest_self_cof_seen << ", discarding appearance with COF " << this_update_cof_version << LL_ENDL; return; } - largestSelfCOFSeen = this_update_cof_version; + largest_self_cof_seen = this_update_cof_version; } else { - LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL; + //LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL; } // Check for stale update. @@ -7387,7 +7772,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } // SUNSHINE CLEANUP - is this case OK now? - S32 num_params = contents.mParamWeights.size(); + S32 num_params = contents->mParamWeights.size(); if (num_params <= 1) { // In this case, we have no reliable basis for knowing @@ -7406,7 +7791,17 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) // assumes that cof version is only updated with server-bake // appearance messages. mLastUpdateReceivedCOFVersion = this_update_cof_version; - + mLastProcessedAppearance = contents; + + bool slam_params = false; + applyParsedAppearanceMessage(*contents, slam_params); +} + +void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params) +{ + S32 num_params = contents.mParamWeights.size(); + ESex old_sex = getSex(); + if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE)) { updateVisualComplexity(); @@ -7436,8 +7831,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 ) { @@ -7450,7 +7845,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; @@ -7465,7 +7860,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) params_changed = TRUE; params_changed_count++; - if(is_first_appearance_message) + if(is_first_appearance_message || slam_params) { //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; param->setWeight(newWeight); @@ -7550,7 +7945,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } updateMeshTextures(); - //if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end"); } // static @@ -7681,7 +8075,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) @@ -7699,14 +8093,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) @@ -7894,6 +8288,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) @@ -7901,10 +8296,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 418cca519d..32a30c3aa8 100644 --- 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 // @@ -205,7 +203,12 @@ public: void addAttachmentPosOverridesForObject(LLViewerObject *vo); void resetJointPositionsOnDetach(const LLUUID& mesh_id); void resetJointPositionsOnDetach(LLViewerObject *vo); + bool jointIsRiggedTo(const std::string& joint_name); + bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo); void clearAttachmentPosOverrides(); + void rebuildAttachmentPosOverrides(); + void showAttachmentPosOverrides(bool verbose = false) const; + void getAttachmentOverrideNames(std::set<std::string>& names) const; /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); @@ -367,7 +370,10 @@ public: void postPelvisSetRecalc( void ); /*virtual*/ BOOL loadSkeletonNode(); + void initAttachmentPoints(bool ignore_hud_joints = false); /*virtual*/ void buildCharacter(); + void resetVisualParams(); + void resetSkeleton(); LLVector3 mCurRootToHeadOffset; LLVector3 mTargetRootToHeadOffset; @@ -404,6 +410,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(); @@ -668,9 +675,12 @@ protected: ** APPEARANCE **/ + LLPointer<LLAppearanceMessageContents> mLastProcessedAppearance; + public: void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg); void processAvatarAppearance(LLMessageSystem* mesgsys); + void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params); void hideSkirt(); void startAppearanceAnimation(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 5f48898cb1..b6655dd078 100644 --- 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" #include "llcorehttputil.h" #if LL_MSVC @@ -192,6 +193,7 @@ bool update_avatar_rez_metrics() return true; gAgentAvatarp->updateAvatarRezMetrics(false); + return false; } @@ -219,7 +221,6 @@ void LLVOAvatarSelf::initInstance() { mDebugBakedTextureTimes[i][0] = -1.0f; mDebugBakedTextureTimes[i][1] = -1.0f; - mInitialBakeIDs[i] = LLUUID::null; } status &= buildMenus(); @@ -340,6 +341,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; @@ -381,6 +383,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")); @@ -409,7 +415,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]) { @@ -494,7 +504,7 @@ BOOL LLVOAvatarSelf::buildMenus() ++iter) { LLViewerJointAttachment* attachment = iter->second; - if (attachment && attachment->getGroup() == 8) + if (attachment->getGroup() == 9) { LLMenuItemCallGL::Params item_params; std::string sub_piemenu_name = attachment->getName(); @@ -580,7 +590,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 a9c4ab26a9..f9f90bb323 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -103,17 +103,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 8f0b233f01..465f8fe0d6 100644 --- 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; @@ -4182,27 +4183,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) { @@ -4214,6 +4199,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); @@ -4223,40 +4209,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; @@ -4814,13 +4771,22 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) drawablep->clearState(LLDrawable::HAS_ALPHA); bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); bool is_rigged = false; + if (rigged && pAvatarVO) + { + pAvatarVO->addAttachmentPosOverridesForObject(vobj); + if (pAvatarVO->isSelf()) + { + //pAvatarVO->showAttachmentPosOverrides(); + } + } + //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { @@ -4837,8 +4803,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //sum up face verts and indices drawablep->updateFaceSize(i); - - if (rigged) { if (!facep->isState(LLFace::RIGGED)) @@ -4852,13 +4816,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //get drawpool of avatar with rigged face LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - // FIXME should this be inside the face loop? - // doesn't seem to depend on any per-face state. - if ( pAvatarVO ) - { - pAvatarVO->addAttachmentPosOverridesForObject(vobj); - } - if (pool) { const LLTextureEntry* te = facep->getTextureEntry(); diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 638a4e2da8..9a9101e0da 100644 --- 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 9e520b2d31..8771660bcf 100644 --- 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 100644 --- 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 fadacbf3cb..f89c0eadf8 100644 --- 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 100644 --- 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 0a492fb37b..ad7aca641b 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3528,6 +3528,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 492d963653..4daff340ac 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1416,6 +1416,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]. @@ -10354,6 +10361,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 100644 --- 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 a9b8e197bc..9e99916ca0 100644 --- 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" 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 100644 --- 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 100644 --- 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 ae63546082..72a6f09f92 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2255,6 +2255,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> @@ -2476,8 +2477,23 @@ 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="Left Hind Foot">Left Hind Foot</string> + <string name="Right Hind Foot">Right Hind Foot</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> diff --git a/scripts/content_tools/anim_tool.py b/scripts/content_tools/anim_tool.py new file mode 100644 index 0000000000..0cb1e1022e --- /dev/null +++ b/scripts/content_tools/anim_tool.py @@ -0,0 +1,595 @@ +#!runpy.sh + +"""\ + +This module contains tools for manipulating the .anim files supported +for Second Life animation upload. Note that this format is unrelated +to any non-Second Life formats of the same name. + +$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$ +""" + +import sys +import struct +import StringIO +import math +import argparse +import random +from lxml import etree + +U16MAX = 65535 +OOU16MAX = 1.0/(float)(U16MAX) + +LL_MAX_PELVIS_OFFSET = 5.0 + +class FilePacker(object): + def __init__(self): + self.data = StringIO.StringIO() + self.offset = 0 + + def write(self,filename): + f = open(filename,"wb") + f.write(self.data.getvalue()) + f.close() + + def pack(self,fmt,*args): + buf = struct.pack(fmt, *args) + self.offset += struct.calcsize(fmt) + self.data.write(buf) + + def pack_string(self,str,size=0): + buf = str + "\000" + if size and (len(buf) < size): + buf += "\000" * (size-len(buf)) + self.data.write(buf) + +class FileUnpacker(object): + def __init__(self, filename): + f = open(filename,"rb") + self.data = f.read() + self.offset = 0 + + def unpack(self,fmt): + result = struct.unpack_from(fmt, self.data, self.offset) + self.offset += struct.calcsize(fmt) + return result + + def unpack_string(self, size=0): + result = "" + i = 0 + while (self.data[self.offset+i] != "\000"): + result += self.data[self.offset+i] + i += 1 + i += 1 + if size: + # fixed-size field for the string + i = size + self.offset += i + return result + +# translated from the C++ version in lldefs.h +def llclamp(a, minval, maxval): + if a<minval: + return minval + if a>maxval: + return maxval + return a + +# translated from the C++ version in llquantize.h +def F32_to_U16(val, lower, upper): + val = llclamp(val, lower, upper); + # make sure that the value is positive and normalized to <0, 1> + val -= lower; + val /= (upper - lower); + + # return the U16 + return int(math.floor(val*U16MAX)) + +# translated from the C++ version in llquantize.h +def U16_to_F32(ival, lower, upper): + if ival < 0 or ival > U16MAX: + raise Exception("U16 out of range: "+ival) + val = ival*OOU16MAX + delta = (upper - lower) + val *= delta + val += lower + + max_error = delta*OOU16MAX; + + # make sure that zeroes come through as zero + if abs(val) < max_error: + val = 0.0 + return val; + +class BadFormat(Exception): + pass + +class RotKey(object): + def __init__(self): + pass + + def unpack(self, anim, fup): + (self.time_short, ) = fup.unpack("<H") + self.time = U16_to_F32(self.time_short, 0.0, anim.duration) + (x,y,z) = fup.unpack("<HHH") + self.rotation = [U16_to_F32(i, -1.0, 1.0) for i in (x,y,z)] + + def dump(self, f): + print >>f, " rot_key: t",self.time,"st",self.time_short,"rot",",".join([str(f) for f in self.rotation]) + + def pack(self, anim, fp): + if not hasattr(self,"time_short"): + self.time_short = F32_to_U16(self.time, 0.0, anim.duration) + fp.pack("<H",self.time_short) + (x,y,z) = [F32_to_U16(v, -1.0, 1.0) for v in self.rotation] + fp.pack("<HHH",x,y,z) + +class PosKey(object): + def __init__(self): + pass + + def unpack(self, anim, fup): + (self.time_short, ) = fup.unpack("<H") + self.time = U16_to_F32(self.time_short, 0.0, anim.duration) + (x,y,z) = fup.unpack("<HHH") + self.position = [U16_to_F32(i, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET) for i in (x,y,z)] + + def dump(self, f): + print >>f, " pos_key: t",self.time,"pos ",",".join([str(f) for f in self.position]) + + def pack(self, anim, fp): + if not hasattr(self,"time_short"): + self.time_short = F32_to_U16(self.time, 0.0, anim.duration) + fp.pack("<H",self.time_short) + (x,y,z) = [F32_to_U16(v, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET) for v in self.position] + fp.pack("<HHH",x,y,z) + +class Constraint(object): + def __init__(self): + pass + + def unpack(self, anim, fup): + (self.chain_length, self.constraint_type) = fup.unpack("<BB") + self.source_volume = fup.unpack_string(16) + self.source_offset = fup.unpack("<fff") + self.target_volume = fup.unpack_string(16) + self.target_offset = fup.unpack("<fff") + self.target_dir = fup.unpack("<fff") + fmt = "<ffff" + (self.ease_in_start, self.ease_in_stop, self.ease_out_start, self.ease_out_stop) = fup.unpack("<ffff") + + def pack(self, anim, fp): + fp.pack("<BB", self.chain_length, self.constraint_type) + fp.pack_string(self.source_volume, 16) + fp.pack("<fff", *self.source_offset) + fp.pack_string(self.target_volume, 16) + fp.pack("<fff", *self.target_offset) + fp.pack("<fff", *self.target_dir) + fp.pack("<ffff", self.ease_in_start, self.ease_in_stop, self.ease_out_start, self.ease_out_stop) + + def dump(self, f): + print >>f, " constraint:" + print >>f, " chain_length",self.chain_length + print >>f, " constraint_type",self.constraint_type + print >>f, " source_volume",self.source_volume + print >>f, " source_offset",self.source_offset + print >>f, " target_volume",self.target_volume + print >>f, " target_offset",self.target_offset + print >>f, " target_dir",self.target_dir + print >>f, " ease_in_start",self.ease_in_start + print >>f, " ease_in_stop",self.ease_in_stop + print >>f, " ease_out_start",self.ease_out_start + print >>f, " ease_out_stop",self.ease_out_stop + +class Constraints(object): + def __init__(self): + pass + + def unpack(self, anim, fup): + (self.num_constraints, ) = fup.unpack("<i") + self.constraints = [] + for i in xrange(self.num_constraints): + constraint = Constraint() + constraint.unpack(anim, fup) + self.constraints.append(constraint) + + def pack(self, anim, fp): + fp.pack("<i",self.num_constraints) + for c in self.constraints: + c.pack(anim,fp) + + def dump(self, f): + print >>f, "constraints:",self.num_constraints + for c in self.constraints: + c.dump(f) + +class PositionCurve(object): + def __init__(self): + self.num_pos_keys = 0 + self.keys = [] + + def is_static(self): + if self.keys: + k0 = self.keys[0] + for k in self.keys: + if k.position != k0.position: + return False + return True + + def unpack(self, anim, fup): + (self.num_pos_keys, ) = fup.unpack("<i") + self.keys = [] + for k in xrange(0,self.num_pos_keys): + pos_key = PosKey() + pos_key.unpack(anim, fup) + self.keys.append(pos_key) + + def pack(self, anim, fp): + fp.pack("<i",self.num_pos_keys) + for k in self.keys: + k.pack(anim, fp) + + def dump(self, f): + print >>f, " position_curve:" + print >>f, " num_pos_keys", self.num_pos_keys + for k in xrange(0,self.num_pos_keys): + self.keys[k].dump(f) + +class RotationCurve(object): + def __init__(self): + self.num_rot_keys = 0 + self.keys = [] + + def is_static(self): + if self.keys: + k0 = self.keys[0] + for k in self.keys: + if k.rotation != k0.rotation: + return False + return True + + def unpack(self, anim, fup): + (self.num_rot_keys, ) = fup.unpack("<i") + self.keys = [] + for k in xrange(0,self.num_rot_keys): + rot_key = RotKey() + rot_key.unpack(anim, fup) + self.keys.append(rot_key) + + def pack(self, anim, fp): + fp.pack("<i",self.num_rot_keys) + for k in self.keys: + k.pack(anim, fp) + + def dump(self, f): + print >>f, " rotation_curve:" + print >>f, " num_rot_keys", self.num_rot_keys + for k in xrange(0,self.num_rot_keys): + self.keys[k].dump(f) + +class JointInfo(object): + def __init__(self): + pass + + def unpack(self, anim, fup): + self.joint_name = fup.unpack_string() + (self.joint_priority, ) = fup.unpack("<i") + self.rotation_curve = RotationCurve() + self.rotation_curve.unpack(anim, fup) + self.position_curve = PositionCurve() + self.position_curve.unpack(anim, fup) + + def pack(self, anim, fp): + fp.pack_string(self.joint_name) + fp.pack("<i", self.joint_priority) + self.rotation_curve.pack(anim, fp) + self.position_curve.pack(anim, fp) + + def dump(self, f): + print >>f, "joint:" + print >>f, " joint_name:",self.joint_name + print >>f, " joint_priority:",self.joint_priority + self.rotation_curve.dump(f) + self.position_curve.dump(f) + +class Anim(object): + def __init__(self, filename=None): + if filename: + self.read(filename) + + def read(self, filename): + fup = FileUnpacker(filename) + self.unpack(fup) + + # various validity checks could be added - see LLKeyframeMotion::deserialize() + def unpack(self,fup): + (self.version, self.sub_version, self.base_priority, self.duration) = fup.unpack("@HHhf") + + if self.version == 0 and self.sub_version == 1: + self.old_version = True + raise BadFormat("old version not supported") + elif self.version == 1 and self.sub_version == 0: + self.old_version = False + else: + raise BadFormat("Bad combination of version, sub_version: %d %d" % (self.version, self.sub_version)) + + self.emote_name = fup.unpack_string() + + (self.loop_in_point, self.loop_out_point, self.loop, self.ease_in_duration, self.ease_out_duration, self.hand_pose, self.num_joints) = fup.unpack("@ffiffII") + + self.joints = [] + for j in xrange(0,self.num_joints): + joint_info = JointInfo() + joint_info.unpack(self, fup) + self.joints.append(joint_info) + print "unpacked joint",joint_info.joint_name + self.constraints = Constraints() + self.constraints.unpack(self, fup) + self.data = fup.data + + def pack(self, fp): + fp.pack("@HHhf", self.version, self.sub_version, self.base_priority, self.duration) + fp.pack_string(self.emote_name, 0) + fp.pack("@ffiffII", self.loop_in_point, self.loop_out_point, self.loop, self.ease_in_duration, self.ease_out_duration, self.hand_pose, self.num_joints) + for j in self.joints: + j.pack(anim, fp) + self.constraints.pack(anim, fp) + + def dump(self, filename="-"): + if filename=="-": + f = sys.stdout + else: + f = open(filename,"w") + print >>f, "versions: ", self.version, self.sub_version + print >>f, "base_priority: ", self.base_priority + print >>f, "duration: ", self.duration + print >>f, "emote_name: ", self.emote_name + print >>f, "loop_in_point: ", self.loop_in_point + print >>f, "loop_out_point: ", self.loop_out_point + print >>f, "loop: ", self.loop + print >>f, "ease_in_duration: ", self.ease_in_duration + print >>f, "ease_out_duration: ", self.ease_out_duration + print >>f, "hand_pose", self.hand_pose + print >>f, "num_joints", self.num_joints + for j in self.joints: + j.dump(f) + self.constraints.dump(f) + + def write(self, filename): + fp = FilePacker() + self.pack(fp) + fp.write(filename) + + def write_src_data(self, filename): + print "write file",filename + f = open(filename,"wb") + f.write(self.data) + f.close() + + def find_joint(self, name): + joints = [j for j in self.joints if j.joint_name == name] + if joints: + return joints[0] + else: + return None + + def add_joint(self, name, priority): + if not self.find_joint(name): + j = JointInfo() + j.joint_name = name + j.joint_priority = priority + j.rotation_curve = RotationCurve() + j.position_curve = PositionCurve() + self.joints.append(j) + self.num_joints = len(self.joints) + + def delete_joint(self, name): + j = self.find_joint(name) + if j: + anim.joints.remove(j) + anim.num_joints = len(self.joints) + + def summary(self): + nj = len(self.joints) + nz = len([j for j in self.joints if j.joint_priority > 0]) + nstatic = len([j for j in self.joints if j.rotation_curve.is_static() and j.position_curve.is_static()]) + print "summary: %d joints, non-zero priority %d, static %d" % (nj, nz, nstatic) + + def add_pos(self, joint_names, positions): + js = [joint for joint in self.joints if joint.joint_name in joint_names] + for j in js: + if args.verbose: + print "adding positions",j.joint_name,positions + j.joint_priority = 4 + j.position_curve.num_pos_keys = len(positions) + j.position_curve.keys = [] + for i,pos in enumerate(positions): + key = PosKey() + key.time = self.duration * i / (len(positions) - 1) + key.time_short = F32_to_U16(key.time, 0.0, self.duration) + key.position = pos + j.position_curve.keys.append(key) + + def add_rot(self, joint_names, rotations): + js = [joint for joint in self.joints if joint.joint_name in joint_names] + for j in js: + print "adding rotations",j.joint_name + j.joint_priority = 4 + j.rotation_curve.num_rot_keys = len(rotations) + j.rotation_curve.keys = [] + for i,pos in enumerate(rotations): + key = RotKey() + key.time = self.duration * i / (len(rotations) - 1) + key.time_short = F32_to_U16(key.time, 0.0, self.duration) + key.rotation = pos + j.rotation_curve.keys.append(key) + +def twistify(anim, joint_names, rot1, rot2): + js = [joint for joint in anim.joints if joint.joint_name in joint_names] + for j in js: + print "twisting",j.joint_name + print j.rotation_curve.num_rot_keys + j.joint_priority = 4 + j.rotation_curve.num_rot_keys = 2 + j.rotation_curve.keys = [] + key1 = RotKey() + key1.time_short = 0 + key1.time = U16_to_F32(key1.time_short, 0.0, anim.duration) + key1.rotation = rot1 + key2 = RotKey() + key2.time_short = U16MAX + key2.time = U16_to_F32(key2.time_short, 0.0, anim.duration) + key2.rotation = rot2 + j.rotation_curve.keys.append(key1) + j.rotation_curve.keys.append(key2) + +def float_triple(arg): + vals = arg.split() + if len(vals)==3: + return [float(x) for x in vals] + else: + raise Exception("arg %s does not resolve to a float triple" % arg) + +def get_joint_by_name(tree,name): + if tree is None: + return None + matches = [elt for elt in tree.getroot().iter() if \ + elt.get("name")==name and elt.tag in ["bone", "collision_volume", "attachment_point"]] + if len(matches)==1: + return matches[0] + elif len(matches)>1: + print "multiple matches for name",name + return None + else: + return None + +def get_elt_pos(elt): + if elt.get("pos"): + return float_triple(elt.get("pos")) + elif elt.get("position"): + return float_triple(elt.get("position")) + else: + return (0.0, 0.0, 0.0) + +def resolve_joints(names, skel_tree, lad_tree): + print "resolve joints, no_hud is",args.no_hud + if skel_tree and lad_tree: + all_elts = [elt for elt in skel_tree.getroot().iter()] + all_elts.extend([elt for elt in lad_tree.getroot().iter()]) + matches = [] + for elt in all_elts: + if elt.get("name") is None: + continue + print elt.get("name"),"hud",elt.get("hud") + if args.no_hud and elt.get("hud"): + print "skipping hud joint", elt.get("name") + continue + if elt.get("name") in names or elt.tag in names: + matches.append(elt.get("name")) + return list(set(matches)) + else: + return names + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="process SL animations") + parser.add_argument("--verbose", help="verbose flag", action="store_true") + parser.add_argument("--dump", help="dump to specified file") + parser.add_argument("--rot", help="specify sequence of rotations", type=float_triple, nargs="+") + parser.add_argument("--rand_pos", help="request random positions", action="store_true") + parser.add_argument("--reset_pos", help="request original positions", action="store_true") + parser.add_argument("--pos", help="specify sequence of positions", type=float_triple, nargs="+") + parser.add_argument("--delete_joints", help="specify joints to be deleted", nargs="+") + parser.add_argument("--joints", help="specify joints to be added or modified", nargs="+") + parser.add_argument("--summary", help="print summary of the output animation", action="store_true") + parser.add_argument("--skel", help="name of the avatar_skeleton file", default="avatar_skeleton.xml") + parser.add_argument("--lad", help="name of the avatar_lad file", default="avatar_lad.xml") + parser.add_argument("--set_version", nargs=2, type=int, help="set version and sub-version to specified values") + parser.add_argument("--no_hud", help="omit hud joints from list of attachments", action="store_true") + parser.add_argument("infilename", help="name of a .anim file to input") + parser.add_argument("outfilename", nargs="?", help="name of a .anim file to output") + args = parser.parse_args() + + print "anim_tool.py: " + " ".join(sys.argv) + print "dump is", args.dump + print "infilename",args.infilename,"outfilename",args.outfilename + print "rot",args.rot + print "pos",args.pos + print "joints",args.joints + + try: + anim = Anim(args.infilename) + skel_tree = None + lad_tree = None + joints = [] + if args.skel: + skel_tree = etree.parse(args.skel) + if skel_tree is None: + print "failed to parse",args.skel + exit(1) + if args.lad: + lad_tree = etree.parse(args.lad) + if lad_tree is None: + print "failed to parse",args.lad + exit(1) + if args.joints: + joints = resolve_joints(args.joints, skel_tree, lad_tree) + if args.verbose: + print "joints resolved to",joints + for name in joints: + anim.add_joint(name,0) + if args.delete_joints: + for name in args.delete_joints: + anim.delete_joint(name) + if joints and args.rot: + anim.add_rot(joints, args.rot) + if joints and args.pos: + anim.add_pos(joints, args.pos) + if joints and args.rand_pos: + for joint in joints: + pos_array = list(tuple(random.uniform(-1,1) for i in xrange(3)) for j in xrange(2)) + pos_array.append(pos_array[0]) + anim.add_pos([joint], pos_array) + if joints and args.reset_pos: + for joint in joints: + elt = get_joint_by_name(skel_tree,joint) + if elt is None: + elt = get_joint_by_name(lad_tree,joint) + if elt is not None: + pos_array = [] + pos_array.append(get_elt_pos(elt)) + pos_array.append(pos_array[0]) + anim.add_pos([joint], pos_array) + else: + print "no elt or no pos data for",joint + if args.set_version: + anim.version = args.set_version[0] + anim.sub_version = args.set_version[1] + if args.dump: + anim.dump(args.dump) + if args.summary: + anim.summary() + if args.outfilename: + anim.write(args.outfilename) + except: + raise + diff --git a/scripts/content_tools/dae_tool.py b/scripts/content_tools/dae_tool.py new file mode 100644 index 0000000000..823f69cb85 --- /dev/null +++ b/scripts/content_tools/dae_tool.py @@ -0,0 +1,119 @@ +#!runpy.sh + +"""\ + +This module contains tools for manipulating collada files + +$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$ +""" + +import argparse +import random + +# Need to pip install numpy and pycollada +import numpy as np +from collada import * +from lxml import etree + +def mesh_summary(mesh): + print "scenes",mesh.scenes + for scene in mesh.scenes: + print "scene",scene + for node in scene.nodes: + print "node",node + +def mesh_lock_offsets(tree, joints): + print "mesh_lock_offsets",tree,joints + for joint_node in tree.iter(): + if "node" not in joint_node.tag: + continue + if joint_node.get("type") != "JOINT": + continue + if joint_node.get("name") in joints or "bone" in joints: + for matrix_node in list(joint_node): + if "matrix" in matrix_node.tag: + floats = [float(x) for x in matrix_node.text.split()] + if len(floats) == 16: + floats[3] += 0.0001 + floats[7] += 0.0001 + floats[11] += 0.0001 + matrix_node.text = " ".join([str(f) for f in floats]) + print joint_node.get("name"),matrix_node.tag,"text",matrix_node.text,len(floats),floats + + +def mesh_random_offsets(tree, joints): + print "mesh_random_offsets",tree,joints + for joint_node in tree.iter(): + if "node" not in joint_node.tag: + continue + if joint_node.get("type") != "JOINT": + continue + if not joint_node.get("name"): + continue + if joint_node.get("name") in joints or "bone" in joints: + for matrix_node in list(joint_node): + if "matrix" in matrix_node.tag: + floats = [float(x) for x in matrix_node.text.split()] + print "randomizing",floats + if len(floats) == 16: + floats[3] += random.uniform(-1.0,1.0) + floats[7] += random.uniform(-1.0,1.0) + floats[11] += random.uniform(-1.0,1.0) + matrix_node.text = " ".join([str(f) for f in floats]) + print joint_node.get("name"),matrix_node.tag,"text",matrix_node.text,len(floats),floats + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="process SL animations") + parser.add_argument("--verbose", action="store_true",help="verbose flag") + parser.add_argument("infilename", help="name of a collada (dae) file to input") + parser.add_argument("outfilename", nargs="?", help="name of a collada (dae) file to output", default = None) + parser.add_argument("--lock_offsets", nargs="+", help="tweak position of listed joints to lock their offsets") + parser.add_argument("--random_offsets", nargs="+", help="random offset position for listed joints") + parser.add_argument("--summary", action="store_true", help="print summary info about input file") + args = parser.parse_args() + + mesh = None + tree = None + + if args.infilename: + print "reading",args.infilename + mesh = Collada(args.infilename) + tree = etree.parse(args.infilename) + + if args.summary: + print "summarizing",args.infilename + mesh_summary(mesh) + + if args.lock_offsets: + print "locking offsets for",args.lock_offsets + mesh_lock_offsets(tree, args.lock_offsets) + + if args.random_offsets: + print "adding random offsets for",args.random_offsets + mesh_random_offsets(tree, args.random_offsets) + + if args.outfilename: + print "writing",args.outfilename + f = open(args.outfilename,"w") + print >>f, etree.tostring(tree, pretty_print=True) #need update to get: , short_empty_elements=True) + diff --git a/scripts/content_tools/skel_tool.py b/scripts/content_tools/skel_tool.py new file mode 100644 index 0000000000..5d4ea0e059 --- /dev/null +++ b/scripts/content_tools/skel_tool.py @@ -0,0 +1,427 @@ +#!runpy.sh + +"""\ + +This module contains tools for manipulating and validating the avatar skeleton file. + +$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$ +""" + +import argparse + +from lxml import etree + +def get_joint_names(tree): + joints = [element.get('name') for element in tree.getroot().iter() if element.tag in ['bone','collision_volume']] + print "joints:",joints + return joints + +def get_aliases(tree): + aliases = {} + alroot = tree.getroot() + for element in alroot.iter(): + for key in element.keys(): + if key == 'aliases': + name = element.get('name') + val = element.get('aliases') + aliases[name] = val + return aliases + +def fix_name(element): + pass + +def enforce_precision_rules(element): + pass + +def float_tuple(str): + try: + return [float(e) for e in str.split(" ")] + except: + return (0,0,0) + +def check_symmetry(name, field, vec1, vec2): + if vec1[0] != vec2[0]: + print name,field,"x match fail" + if vec1[1] != -vec2[1]: + print name,field,"y mirror image fail" + if vec1[2] != vec2[2]: + print name,field,"z match fail" + +def enforce_symmetry(tree, element, field, fix=False): + name = element.get("name") + if not name: + return + if "Right" in name: + left_name = name.replace("Right","Left") + left_element = get_element_by_name(tree, left_name) + pos = element.get(field) + left_pos = left_element.get(field) + pos_tuple = float_tuple(pos) + left_pos_tuple = float_tuple(left_pos) + check_symmetry(name,field,pos_tuple,left_pos_tuple) + +def get_element_by_name(tree,name): + if tree is None: + return None + matches = [elt for elt in tree.getroot().iter() if elt.get("name")==name] + if len(matches)==1: + return matches[0] + elif len(matches)>1: + print "multiple matches for name",name + return None + else: + return None + +def list_skel_tree(tree): + for element in tree.getroot().iter(): + if element.tag == "bone": + print element.get("name"),"-",element.get("support") + +def validate_child_order(tree, ogtree, fix=False): + unfixable = 0 + + #print "validate_child_order am failing for NO RAISIN!" + #unfixable += 1 + + tofix = set() + for element in tree.getroot().iter(): + if element.tag != "bone": + continue + og_element = get_element_by_name(ogtree,element.get("name")) + if og_element is not None: + for echild,ochild in zip(list(element),list(og_element)): + if echild.get("name") != ochild.get("name"): + print "Child ordering error, parent",element.get("name"),echild.get("name"),"vs",ochild.get("name") + if fix: + tofix.add(element.get("name")) + children = {} + for name in tofix: + print "FIX",name + element = get_element_by_name(tree,name) + og_element = get_element_by_name(ogtree,name) + children = [] + # add children matching the original joints first, in the same order + for og_elt in list(og_element): + elt = get_element_by_name(tree,og_elt.get("name")) + if elt is not None: + children.append(elt) + print "b:",elt.get("name") + else: + print "b missing:",og_elt.get("name") + # then add children that are not present in the original joints + for elt in list(element): + og_elt = get_element_by_name(ogtree,elt.get("name")) + if og_elt is None: + children.append(elt) + print "e:",elt.get("name") + # if we've done this right, we have a rearranged list of the same length + if len(children)!=len(element): + print "children",[e.get("name") for e in children] + print "element",[e.get("name") for e in element] + print "children changes for",name,", cannot reconcile" + else: + element[:] = children + + return unfixable + +# Checklist for the final file, started from SL-276: +# - new "end" attribute on all bones +# - new "connected" attribute on all bones +# - new "support" tag on all bones and CVs +# - aliases where appropriate for backward compatibility. rFoot and lFoot associated with mAnkle bones (not mFoot bones) +# - correct counts of bones and collision volumes in header +# - check all comments +# - old fields of old bones and CVs should be identical to their previous values. +# - old bones and CVs should retain their previous ordering under their parent, with new joints going later in any given child list +# - corresponding right and left joints should be mirror symmetric. +# - childless elements should be in short form (<bone /> instead of <bone></bone>) +# - digits of precision should be consistent (again, except for old joints) +def validate_skel_tree(tree, ogtree, reftree, fix=False): + print "validate_skel_tree" + (num_bones,num_cvs) = (0,0) + unfixable = 0 + defaults = {"connected": "false", + "group": "Face" + } + for element in tree.getroot().iter(): + og_element = get_element_by_name(ogtree,element.get("name")) + ref_element = get_element_by_name(reftree,element.get("name")) + # Preserve values from og_file: + for f in ["pos","rot","scale","pivot"]: + if og_element is not None and og_element.get(f) and (str(element.get(f)) != str(og_element.get(f))): + print element.get("name"),"field",f,"has changed:",og_element.get(f),"!=",element.get(f) + if fix: + element.set(f, og_element.get(f)) + + # Pick up any other fields that we can from ogtree and reftree + fields = [] + if element.tag in ["bone","collision_volume"]: + fields = ["support","group"] + if element.tag == 'bone': + fields.extend(["end","connected"]) + for f in fields: + if not element.get(f): + print element.get("name"),"missing required field",f + if fix: + if og_element is not None and og_element.get(f): + print "fix from ogtree" + element.set(f,og_element.get(f)) + elif ref_element is not None and ref_element.get(f): + print "fix from reftree" + element.set(f,ref_element.get(f)) + else: + if f in defaults: + print "fix by using default value",f,"=",defaults[f] + element.set(f,defaults[f]) + elif f == "support": + if og_element is not None: + element.set(f,"base") + else: + element.set(f,"extended") + else: + print "unfixable:",element.get("name"),"no value for field",f + unfixable += 1 + + fix_name(element) + enforce_precision_rules(element) + for field in ["pos","pivot"]: + enforce_symmetry(tree, element, field, fix) + + if element.tag == "linden_skeleton": + num_bones = int(element.get("num_bones")) + num_cvs = int(element.get("num_collision_volumes")) + all_bones = [e for e in tree.getroot().iter() if e.tag=="bone"] + all_cvs = [e for e in tree.getroot().iter() if e.tag=="collision_volume"] + if num_bones != len(all_bones): + print "wrong bone count, expected",len(all_bones),"got",num_bones + if fix: + element.set("num_bones", str(len(all_bones))) + if num_cvs != len(all_cvs): + print "wrong cv count, expected",len(all_cvs),"got",num_cvs + if fix: + element.set("num_collision_volumes", str(len(all_cvs))) + + print "skipping child order code" + #unfixable += validate_child_order(tree, ogtree, fix) + + if fix and (unfixable > 0): + print "BAD FILE:", unfixable,"errs could not be fixed" + + +# Check contents of avatar_lad file relative to a specified skeleton +def validate_lad_tree(ladtree,skeltree,orig_ladtree): + print "validate_lad_tree" + bone_names = [elt.get("name") for elt in skeltree.iter("bone")] + bone_names.append("mScreen") + bone_names.append("mRoot") + cv_names = [elt.get("name") for elt in skeltree.iter("collision_volume")] + #print "bones\n ","\n ".join(sorted(bone_names)) + #print "cvs\n ","\n ".join(sorted(cv_names)) + for att in ladtree.iter("attachment_point"): + att_name = att.get("name") + #print "attachment",att_name + joint_name = att.get("joint") + if not joint_name in bone_names: + print "att",att_name,"linked to invalid joint",joint_name + for skel_param in ladtree.iter("param_skeleton"): + skel_param_id = skel_param.get("id") + skel_param_name = skel_param.get("name") + #if not skel_param_name and not skel_param_id: + # print "strange skel_param" + # print etree.tostring(skel_param) + # for k,v in skel_param.attrib.iteritems(): + # print k,"->",v + #print "skel_param",skel_param_name + for bone in skel_param.iter("bone"): + bone_name = bone.get("name") + if not bone_name in bone_names: + print "skel param references invalid bone",bone_name + print etree.tostring(bone) + drivers = {} + for driven_param in ladtree.iter("driven"): + driver = driven_param.getparent().getparent() + driven_id = driven_param.get("id") + driver_id = driver.get("id") + actual_param = next(param for param in ladtree.iter("param") if param.get("id")==driven_id) + if not driven_id in drivers: + drivers[driven_id] = set() + drivers[driven_id].add(driver_id) + if (actual_param.get("value_min") != driver.get("value_min") or \ + actual_param.get("value_max") != driver.get("value_max")): + if args.verbose: + print "MISMATCH min max:",driver.get("id"),"drives",driven_param.get("id"),"min",driver.get("value_min"),actual_param.get("value_min"),"max",driver.get("value_max"),actual_param.get("value_max") + + for driven_id in drivers: + dset = drivers[driven_id] + if len(dset) != 1: + print "driven_id",driven_id,"has multiple drivers",dset + else: + if args.verbose: + print "driven_id",driven_id,"has one driver",dset + if orig_ladtree: + # make sure expected message format is unchanged + orig_message_params_by_id = dict((int(param.get("id")),param) for param in orig_ladtree.iter("param") if param.get("group") in ["0","3"]) + orig_message_ids = sorted(orig_message_params_by_id.keys()) + #print "orig_message_ids",orig_message_ids + message_params_by_id = dict((int(param.get("id")),param) for param in ladtree.iter("param") if param.get("group") in ["0","3"]) + message_ids = sorted(message_params_by_id.keys()) + #print "message_ids",message_ids + if (set(message_ids) != set(orig_message_ids)): + print "mismatch in message ids!" + print "added",set(message_ids) - set(orig_message_ids) + print "removed",set(orig_message_ids) - set(message_ids) + else: + print "message ids OK" + +def remove_joint_by_name(tree, name): + print "remove joint:",name + elt = get_element_by_name(tree,name) + while elt is not None: + children = list(elt) + parent = elt.getparent() + print "graft",[e.get("name") for e in children],"into",parent.get("name") + print "remove",elt.get("name") + #parent_children = list(parent) + loc = parent.index(elt) + parent[loc:loc+1] = children + elt[:] = [] + print "parent now:",[e.get("name") for e in list(parent)] + elt = get_element_by_name(tree,name) + +def compare_skel_trees(atree,btree): + diffs = {} + realdiffs = {} + a_missing = set() + b_missing = set() + a_names = set(e.get("name") for e in atree.getroot().iter() if e.get("name")) + b_names = set(e.get("name") for e in btree.getroot().iter() if e.get("name")) + print "a_names\n ",str("\n ").join(sorted(list(a_names))) + print + print "b_names\n ","\n ".join(sorted(list(b_names))) + all_names = set.union(a_names,b_names) + for name in all_names: + if not name: + continue + a_element = get_element_by_name(atree,name) + b_element = get_element_by_name(btree,name) + if a_element is None or b_element is None: + print "something not found for",name,a_element,b_element + if a_element is not None and b_element is not None: + all_attrib = set.union(set(a_element.attrib.keys()),set(b_element.attrib.keys())) + print name,all_attrib + for att in all_attrib: + if a_element.get(att) != b_element.get(att): + if not att in diffs: + diffs[att] = set() + diffs[att].add(name) + print "tuples",name,att,float_tuple(a_element.get(att)),float_tuple(b_element.get(att)) + if float_tuple(a_element.get(att)) != float_tuple(b_element.get(att)): + print "diff in",name,att + if not att in realdiffs: + realdiffs[att] = set() + realdiffs[att].add(name) + for att in diffs: + print "Differences in",att + for name in sorted(diffs[att]): + print " ",name + for att in realdiffs: + print "Real differences in",att + for name in sorted(diffs[att]): + print " ",name + a_missing = b_names.difference(a_names) + b_missing = a_names.difference(b_names) + if len(a_missing) or len(b_missing): + print "Missing from comparison" + for name in a_missing: + print " ",name + print "Missing from infile" + for name in b_missing: + print " ",name + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="process SL avatar_skeleton/avatar_lad files") + parser.add_argument("--verbose", action="store_true",help="verbose flag") + parser.add_argument("--ogfile", help="specify file containing base bones") + parser.add_argument("--ref_file", help="specify another file containing replacements for missing fields") + parser.add_argument("--lad_file", help="specify avatar_lad file to check") + parser.add_argument("--orig_lad_file", help="specify avatar_lad file to compare to") + parser.add_argument("--aliases", help="specify file containing bone aliases") + parser.add_argument("--validate", action="store_true", help="check specified input file for validity") + parser.add_argument("--fix", action="store_true", help="try to correct errors") + parser.add_argument("--remove", nargs="+", help="remove specified joints") + parser.add_argument("--list", action="store_true", help="list joint names") + parser.add_argument("--compare", help="alternate skeleton file to compare") + parser.add_argument("infilename", help="name of a skel .xml file to input") + parser.add_argument("outfilename", nargs="?", help="name of a skel .xml file to output") + args = parser.parse_args() + + tree = etree.parse(args.infilename) + + aliases = {} + if args.aliases: + altree = etree.parse(args.aliases) + aliases = get_aliases(altree) + + # Parse input files + ogtree = None + reftree = None + ladtree = None + orig_ladtree = None + + if args.ogfile: + ogtree = etree.parse(args.ogfile) + + if args.ref_file: + reftree = etree.parse(args.ref_file) + + if args.lad_file: + ladtree = etree.parse(args.lad_file) + + if args.orig_lad_file: + orig_ladtree = etree.parse(args.orig_lad_file) + + if args.remove: + for name in args.remove: + remove_joint_by_name(tree,name) + + # Do processing + if args.validate and ogtree: + validate_skel_tree(tree, ogtree, reftree) + + if args.validate and ladtree: + validate_lad_tree(ladtree, tree, orig_ladtree) + + if args.fix and ogtree: + validate_skel_tree(tree, ogtree, reftree, True) + + if args.list and tree: + list_skel_tree(tree) + + if args.compare and tree: + compare_tree = etree.parse(args.compare) + compare_skel_trees(compare_tree,tree) + + if args.outfilename: + f = open(args.outfilename,"w") + print >>f, etree.tostring(tree, pretty_print=True) #need update to get: , short_empty_elements=True) + |