diff --git a/doc/contributions.txt b/doc/contributions.txt index 9b31e5032ad73da1c285e7606c344ff3aece315e..52ccdea456224b212c5951157556fcf5467a8311 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 d1eb38901316b25621b1666c1ee62297cc977a2f..2ce43436db0c35fe35cc000c470c5e44eac5e7c8 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 @@ class LLAvatarBoneInfo 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 @@ class LLAvatarSkeletonInfo 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 a0ef49b7cb520e75b6bc94a4b839e1909691703f..3865da709801543c91a486008ea8200208c47db0 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -66,7 +66,8 @@ class LLAvatarAppearance : public LLCharacter 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 @@ class LLAvatarAppearance : public LLCharacter 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 @@ class LLAvatarAppearance : public LLCharacter 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 @@ class LLAvatarAppearance : public LLCharacter 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 2ee3c65a01ddef2a2cde2a688fe40ffa5afb4261..29642be099a3d9c26c3fed801f332cf892ee948d 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 520ad775db7cbc46c59a1c95b5bf01167f69325f..7ca0928171f55ab33a00832b9ac8948baf84f715 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 e630c1118bc859c71c8c0911e3ceb6ec0d0a144b..e5e502b158fd72b3d7e3bc4bfce10bc9635d1da6 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 f71c930e5e3716fbf67683690f9f372fd5f02142..f278dcc2e29b0746afa157676bcf88603f832967 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -128,6 +128,10 @@ class LLDriverParam : public LLViewerVisualParam 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 @@ class LLDriverParam : public LLViewerVisualParam 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 e3992a080e4b02d93c0be859e9a69100ccb4ed01..2cb4c65d7c49a197f1e871397c010a6038c6265f 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 3c2c68079c39d29169dbc3083b96ab77aaa3da93..c6133cd83119605a7f2085db8ea9e1f37966658b 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -182,6 +182,8 @@ class LLPolyMorphTarget : public LLViewerVisualParam 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 fbc312c42642923f9700db09cb0898d27cd232f7..fdce8d97cee62416edcec2422b8595ed216d4b7a 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 5ca9f55ac8ce9d33fa2a4cb905e705cd5d5f538e..63069adcc866e33fad7c6371e9ff06b0af797d73 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 2573417b260536371d7a93c87e459514b597db37..a17a5b0aa6bee291b535ffb0bc257ed10708cad7 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 0d558aeaa2be3717b5f34188d5e1ac2af755c297..e906d81ce15229ae99aad55dd06c4bcecee4d5c6 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 f816b7627723bca0d18cedd545099a88835c34e5..47fe4090472bb4da83702239725a40909026bba6 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 @@ class LLBVHLoader 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 f4a37a139aa147e00fee9ee9e8ac64c492cd35b2..ddf89f30f22bb34f35df1ed65775c0ab39dd56d1 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 8fa08a2a6ce0ea7314e94973661c376164ec1eec..c4eda0b432b0fd9d39209627dbb3cc0378c4e8fe 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; @@ -169,6 +172,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. @@ -194,6 +218,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() //----------------------------------------------------------------------------- @@ -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())) @@ -384,6 +465,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() //-------------------------------------------------------------------- @@ -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 2abe1d6db1510cb6da94adf987e473a271c6da73..d2c573864bd787d476d22d2675bdd9416e2dce66 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 @@ class LLPosOverrideMap 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 @@ class LLJoint 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 @@ class LLJoint LLUUID mId; + LLVector3 mDefaultPosition; + public: U32 mDirtyFlags; BOOL mUpdateXform; @@ -104,6 +122,10 @@ class LLJoint // 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 @@ class LLJoint // 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 @@ class LLJoint 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 @@ class LLJoint 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 @@ class LLJoint // 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 @@ class LLJoint 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 cd201a65b4ef6b22a614d87759c0f7276e3f7ebe..052ca3be58910b87a3f6a2c599ad52686189eacd 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; @@ -1971,6 +2019,51 @@ U32 LLKeyframeMotion::getFileSize() return dp.getCurrentSize(); } +//----------------------------------------------------------------------------- +// 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() //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index b1422b2b903c742a0d4e13d1fd816666f0a3e9e1..f1fa56d731de6dcb821619095919902a50774b55 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -153,6 +153,7 @@ class LLKeyframeMotion : 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 fdeddf55e16538326b600342b7fa0b4e55d55b07..02c1d3cdbd75947c35fd4b0d2c13bbb0903cb489 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 4803f855de98853a96a0f5364ae98b6f4d47868d..697efc8157fde7bb4cd8132043a7fad589300516 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 5e37f094b8967ec53699ccfae4c797954a039ebf..2dfc3afc7f0964ba71fa7defcb69db4e3272573f 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -181,7 +181,7 @@ class LLMotion 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 e02b139608fc6cb2abd04b86dff83b645591cce8..d8185aa693e65ce3a0b993d55dda45ae32407f3f 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 2bd5271c4f73a0775985fa7f8eab83b8c3f7dfd7..72de3316947f1ce13fcca68848e087bf30e95e2d 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -223,7 +223,7 @@ class LLMotionController 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 b1a7ebb159612bdbde8e68b3178c6c8d2f62d383..fc95fafd61490f81a3b8494afdc4bc5ce24a2ea8 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 c6b97d7e8b4f18f0a0fddc2eb80ef09c6bf59c56..0ad063fd1e113109e612ddfd5064dced4a1caf53 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -150,6 +150,7 @@ class LLVisualParam 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 da151808f21c660f6e57c922d848af356f4889c8..617f31b0e46e5877198f25ce8263606ac93a9422 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 907dbab8f8a1ba1b3f5b07a3fa2f7fe7176911c7..c3242389c272c728f53799d642e77963b71735df 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 0000000000000000000000000000000000000000..c0d3104099f49cc7c87e856b50112fe9c3066399 --- /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 0000000000000000000000000000000000000000..834f89c471ea13a090dc2773fcf66e86bac4d5d1 --- /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 0000000000000000000000000000000000000000..8db291eed189aa7f9c3df8519c368a02139f269f --- /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 0000000000000000000000000000000000000000..1f7a7689d7671e0448cdc8ed6724263215ffe7d2 --- /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 0435cb8a08d9515afda8ea2316719b86822c2234..b024b47225a873814b081e773fa8e5c5efb1c829 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 d932eb53a0509dbf2050adc2ad980cd94a8e0b93..2918e2e27238beb2ea9561bcaed6232e20942da3 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 1da2d0c6b15f9ea47bed4f9c8b64b693625ddb3d..33e1403a14ebb783395061e6c527a273e99990d4 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -953,6 +953,10 @@ class LLVolumeFace // 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 720986a4110d0c35c023608ca4ec05f65c8e913c..38b061dd798b7f0b8d0b31c5acdf1affe2069801 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 27db5326d50ff8e17721dd19475d7b25b19d2c9a..4e990dbe5e51b887f40ec09501bdd8eabd4b9350 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -47,17 +47,19 @@ class LLDAELoader : public LLModelLoader 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 e494c55250145c74704fbc35690bb67b465c78e4..398f0997f37011db925579a2cfefdb8f1cc7b54f 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 ae602c09df55b8098f0e3479e1e85e49f33c5b99..5f98942340a51f1e8c8a43f3138d630c612869d0 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -46,7 +46,7 @@ class LLMeshSkinInfo 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 f86eceb98d8e5dc351c87db8568cdcff4e402146..816ebc558aedf52d971fca7f8c610c167e295068 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 bb4d06dca3c5f9a43de3b322d77d3f535c88207d..a902ca340465484d57c516bacf52ad1b22deeae7 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 @@ class LLModelLoader : public LLThread //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 @@ class LLModelLoader : public LLThread //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 @@ class LLModelLoader : public LLThread //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 @@ class LLModelLoader : public LLThread //----------------------------------------------------------------------------- bool isNodeAJoint(const char* name) { - return mJointMap.find(name) != mJointMap.end(); + return name != NULL && mJointMap.find(name) != mJointMap.end(); } protected: @@ -189,17 +188,14 @@ class LLModelLoader : public LLThread 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 8d863631cf1c1ac0b32373b7e78d4fbf911a82a8..769b86c2183633c0ed912017130e4de4d1ff410a 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 d13e837c8ecbbe09e8fe5676e097167fe79812fc..0062ac971805f7b700058db4bb0f5c5b771dda76 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 63c84e544db9134850205ed7bf9a29ec90e4694a..c24d2749ef90981257d4bf43c05d5426c022f86c 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 a8d42be2a1658e476347770bb70a0742e069e3cd..a7a15c9c7b90701d199bbe2fbb02a3e556289c3a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2193,6 +2193,17 @@ <string>String</string> <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> @@ -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 3060307b2113920734afcb18b7afca250ec86cde..8f754fe82b04d90fb61559f18985547d5c4cc802 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 7f7eaed38a13d9e945d4d740be6df4a6ad4efb78..38bcd88078aa56b9010ab73b16034f23fc94398e 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> @@ -605,10 +804,26 @@ name="mTorso" 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" @@ -684,6 +937,14 @@ name="mPelvis" 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" @@ -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 @@ -732,10 +1016,26 @@ name="mTorso" 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,2657 +1184,4216 @@ name="mEyeRight" scale="0 0 0" offset="0 0 -.004" /> - </param_skeleton> - </param> - - <param - id="772" - group="1" - name="EyeBone_Head_Elongate" - wearable="shape" - edit_group="shape_eyes" - label_min="Eyes Short Head" - label_max="Eyes Long Head" - value_min="-1" - value_max="1"> - <param_skeleton> + <bone - name="mEyeLeft" + name="mFaceEyeAltLeft" scale="0 0 0" - offset=".016 0 0" /> + offset="0 0 .004" /> <bone - name="mEyeRight" + name="mFaceEyeAltRight" scale="0 0 0" - offset=".016 0 0" /> - </param_skeleton> - </param> + offset="0 0 -.004" /> - <param - id="768" - group="1" - name="EyeBone_Bug" - wearable="shape" - edit_group="shape_eyes" - label_min="Eyes Sunken" - label_max="Eyes Bugged" - value_min="-2" - value_max="2"> - <param_skeleton> - <bone - name="mEyeLeft" + <bone + name="mFaceNoseRight" scale="0 0 0" - offset=".005 0 0" /> + offset="0 0 -.004" /> - <bone - name="mEyeRight" + <bone + name="mFaceNoseLeft" scale="0 0 0" - offset=".005 0 0" /> - </param_skeleton> - </param> + offset="0 0 .004" /> - <param - id="655" - group="1" - name="Head Size" - label="Head Size" - wearable="shape" - edit_group="shape_head" - label_min="Small Head" - label_max="Big Head" - show_simple="true" - value_min="-.25" - value_max=".10"> - <param_skeleton> - <bone - name="mSkull" - scale="1 1 1" - offset="0 0 0.1" /> + <bone + name="mFaceEar1Left" + scale="0 0 0" + offset="0 0 .004" /> + <bone + name="mFaceEar1Right" + scale="0 0 0" + offset="0 0 -.004" /> - <bone - name="mHead" - scale="1 1 1" - offset="0 0 0" /> + <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="mEyeLeft" - scale="1 1 1" - offset="0 0 0" /> + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 .004" /> - <bone - name="mEyeRight" - scale="1 1 1" - offset="0 0 0" /> - </param_skeleton> - </param> + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> - <param - id="197" - group="1" - wearable="shoes" - name="Shoe_Heels" - edit_group="shoes" - label_min="No Heels" - label_max="High Heels" - value_min="0" - value_max="1"> - <param_skeleton> - <bone - name="mFootRight" + <bone + name="mFaceCheekUpperRight" scale="0 0 0" - offset="0 0 -.08" /> + offset="0 0 -.004" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> - <bone - name="mFootLeft" + <bone + name="mFaceEyeLidUpperRight" scale="0 0 0" - offset="0 0 -.08" /> + 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> <param - id="502" + id="772" group="1" - wearable="shoes" - name="Shoe_Platform" - edit_group="shoes" - label_min="No Heels" - label_max="High Heels" - value_min="0" + name="EyeBone_Head_Elongate" + wearable="shape" + edit_group="shape_eyes" + label_min="Eyes Short Head" + label_max="Eyes Long Head" + value_min="-1" value_max="1"> <param_skeleton> <bone - name="mFootRight" + name="mEyeLeft" scale="0 0 0" - offset="0 0 -.07" /> + offset=".016 0 0" /> <bone - name="mFootLeft" + name="mEyeRight" scale="0 0 0" - offset="0 0 -.07" /> - </param_skeleton> - </param> + offset=".016 0 0" /> - <param - id="675" - group="0" - name="Hand Size" - wearable="shape" - edit_group="shape_torso" - edit_group_order="10" - label_min="Small Hands" - label_max="Large Hands" - value_min="-.3" - value_max=".3" - camera_elevation=".1" - camera_distance="1.4" - camera_angle="0"> - <param_skeleton> <bone - name="mWristRight" - scale="1 1 1" - offset="0 0 0" /> + name="mFaceEyeAltLeft" + scale="0 0 0" + offset=".016 0 0" /> <bone - name="mWristLeft" - scale="1 1 1" - offset="0 0 0" /> - </param_skeleton> - </param> + name="mFaceEyeAltRight" + scale="0 0 0" + offset=".016 0 0" /> - <param - id="683" - group="0" - name="Neck Thickness" - wearable="shape" - edit_group="shape_torso" - edit_group_order="2" - label_min="Skinny Neck" - label_max="Thick Neck" - value_min="-.4" - value_max=".2" - value_default="-.15" - camera_elevation=".3" - camera_distance=".8" - camera_angle="15"> - <param_skeleton> - <bone - name="mNeck" - scale="1 1 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> <param - id="689" + id="768" group="1" + name="EyeBone_Bug" wearable="shape" - name="EyeBone_Big_Eyes" edit_group="shape_eyes" - label_min="Eyes Back" - label_max="Eyes Forward" - value_min="-1" - value_max="1"> + label_min="Eyes Sunken" + label_max="Eyes Bugged" + value_min="-2" + value_max="2"> <param_skeleton> <bone name="mEyeLeft" scale="0 0 0" - offset="-.005 0 0" /> + offset=".005 0 0" /> <bone name="mEyeRight" scale="0 0 0" - offset="-.005 0 0" /> - </param_skeleton> - </param> + offset=".005 0 0" /> + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset=".005 0 0" /> - <param - id="692" - group="0" - name="Leg Length" - wearable="shape" - edit_group="shape_legs" - edit_group_order="2" - label_min="Short Legs" - label_max="Long Legs" - value_min="-1" - value_max="1" - camera_distance="2.5"> - <param_skeleton> <bone - name="mHipLeft" - scale="0 0 .2" /> + 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="mHipRight" - scale="0 0 .2" /> + name="mFaceEyecornerInnerLeft" + scale="0 0 0 " + offset=".005 0 0" /> <bone - name="mKneeRight" - scale="0 0 .2" /> + name="mFaceEyecornerInnerRight" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0 " + offset=".005 0 0" /> <bone - name="mKneeLeft" - scale="0 0 .2" /> + 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> <param - id="693" - group="0" - name="Arm Length" + id="655" + group="1" + name="Head Size" + label="Head Size" wearable="shape" - edit_group="shape_torso" - edit_group_order="9" - label_min="Short Arms" - label_max="Long arms" - value_min="-1" - value_max="1" - value_default=".6" - camera_distance="1.5"> + edit_group="shape_head" + label_min="Small Head" + label_max="Big Head" + show_simple="true" + value_min="-.25" + value_max=".10"> <param_skeleton> + <bone - name="mShoulderLeft" - scale="0 .2 0" /> + 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" + offset="0 0 0.1" /> <bone - name="mShoulderRight" - scale="0 .2 0" /> + name="mHead" + scale="1 1 1" + offset="0 0 0" /> <bone - name="mElbowRight" - scale="0 .3 0" /> + name="mFaceRoot" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mEyeLeft" + scale="1 1 1" + offset="0 0 0" /> <bone - name="mElbowLeft" - scale="0 .3 0" /> + 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> <param - id="756" - group="0" - name="Neck Length" - wearable="shape" - edit_group="shape_torso" - edit_group_order="3" - label_min="Short Neck" - label_max="Long Neck" - value_min="-1" - value_max="1" - value_default="0" - camera_elevation=".3" - camera_distance=".8" - camera_angle="15"> + id="197" + group="1" + wearable="shoes" + name="Shoe_Heels" + edit_group="shoes" + label_min="No Heels" + label_max="High Heels" + value_min="0" + value_max="1"> <param_skeleton> <bone - name="mNeck" - scale="0 0 .5" /> + name="mFootRight" + scale="0 0 0" + offset="0 0 -.08" /> + + <bone + name="mFootLeft" + scale="0 0 0" + offset="0 0 -.08" /> </param_skeleton> </param> - <param - id="11001" - group="0" - name="Hover" - wearable="shape" - edit_group="shape_body" - edit_group_order="4" - label_min="Lower" - label_max="Higher" - value_min="-2" - value_max="2" - value_default="0" - camera_distance="2.5"> - <param_skeleton /> - </param> - - </skeleton> - <mesh - type="hairMesh" - lod="0" - file_name="avatar_hair.llm" - min_pixel_width="320"> - <!-- begin morph targets --> <param - id="180" + id="502" group="1" - name="Hair_Volume" - label="Hair Volume" - show_simple="true" - wearable="hair" - clothing_morph="true" - edit_group="hair_style" - label_min="Less" - label_max="More" + wearable="shoes" + name="Shoe_Platform" + edit_group="shoes" + label_min="No Heels" + label_max="High Heels" value_min="0" - value_max="1.3" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + value_max="1"> + <param_skeleton> + <bone + name="mFootRight" + scale="0 0 0" + offset="0 0 -.07" /> - <param - id="761" - group="1" - name="Hair_Volume_Small" - label="Hair Volume" - show_simple="true" - wearable="hair" - edit_group="hair_style" - label_min="Less" - label_max="More" - value_min="0" - value_max="1.3" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + <bone + name="mFootLeft" + scale="0 0 0" + offset="0 0 -.07" /> + </param_skeleton> </param> <param - id="181" + id="675" group="0" - name="Hair_Big_Front" - label="Big Hair Front" - wearable="hair" - edit_group="hair_style" - edit_group_order="5" - label_min="Less" - label_max="More" - value_min="-1" - value_max="1" - value_default="0.14" + name="Hand Size" + wearable="shape" + edit_group="shape_torso" + edit_group_order="10" + label_min="Small Hands" + label_max="Large Hands" + value_min="-.3" + value_max=".3" camera_elevation=".1" - camera_distance=".5" - camera_angle="90"> - <param_morph /> + camera_distance="1.4" + camera_angle="0"> + <param_skeleton> + <bone + name="mWristRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + 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> <param - id="182" + id="683" group="0" - name="Hair_Big_Top" - label="Big Hair Top" - wearable="hair" - edit_group="hair_style" - edit_group_order="6" - label_min="Less" - label_max="More" - value_min="-1" - value_max="1" - value_default=".7" - camera_elevation=".1" - camera_distance=".5" - camera_angle="90"> - <param_morph /> + name="Neck Thickness" + wearable="shape" + edit_group="shape_torso" + edit_group_order="2" + label_min="Skinny Neck" + label_max="Thick Neck" + value_min="-.4" + value_max=".2" + value_default="-.15" + camera_elevation=".3" + camera_distance=".8" + camera_angle="15"> + <param_skeleton> + <bone + name="mNeck" + scale="1 1 0" + offset="0 0 0" /> + </param_skeleton> </param> <param - id="183" - group="0" - name="Hair_Big_Back" - clothing_morph="true" - label="Big Hair Back" - wearable="hair" - edit_group="hair_style" - edit_group_order="7" - label_min="Less" - label_max="More" + id="689" + group="1" + wearable="shape" + name="EyeBone_Big_Eyes" + edit_group="shape_eyes" + label_min="Eyes Back" + label_max="Eyes Forward" value_min="-1" - value_max="1" - value_default="0.05" - camera_elevation=".1" - camera_distance=".7" - camera_angle="90"> - <param_morph /> + value_max="1"> + <param_skeleton> + <bone + name="mEyeLeft" + scale="0 0 0" + offset="-.005 0 0" /> + + <bone + 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> <param - id="184" + id="692" group="0" - name="Hair_Spiked" - label="Spiked Hair" - show_simple="true" - wearable="hair" - clothing_morph="true" - edit_group="hair_style" - edit_group_order="15" - label_min="No Spikes" - label_max="Big Spikes" - value_min="0" + name="Leg Length" + wearable="shape" + edit_group="shape_legs" + edit_group_order="2" + label_min="Short Legs" + label_max="Long Legs" + value_min="-1" value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + camera_distance="2.5"> + <param_skeleton> + <bone + name="mHipLeft" + scale="0 0 .2" /> + + <bone + name="mHipRight" + scale="0 0 .2" /> + + <bone + name="mKneeRight" + scale="0 0 .2" /> + + <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> <param - id="140" + id="693" group="0" - name="Hair_Part_Middle" - label="Middle Part" - wearable="hair" - edit_group="hair_style" - edit_group_order="17" - label_min="No Part" - label_max="Part" - value_min="0" - value_max="2" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> + name="Arm Length" + wearable="shape" + edit_group="shape_torso" + edit_group_order="9" + label_min="Short Arms" + label_max="Long arms" + value_min="-1" + value_max="1" + value_default=".6" + camera_distance="1.5"> + <param_skeleton> + <bone + name="mShoulderLeft" + scale="0 .2 0" /> + + <bone + name="mShoulderRight" + scale="0 .2 0" /> + + <bone + name="mElbowRight" + scale="0 .3 0" /> + + <bone + name="mElbowLeft" + scale="0 .3 0" /> + </param_skeleton> </param> <param - id="141" + id="756" group="0" - name="Hair_Part_Right" - label="Right Part" - wearable="hair" - edit_group="hair_style" - edit_group_order="18" - label_min="No Part" - label_max="Part" - value_min="0" - value_max="2" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> + name="Neck Length" + wearable="shape" + edit_group="shape_torso" + edit_group_order="3" + label_min="Short Neck" + label_max="Long Neck" + value_min="-1" + value_max="1" + value_default="0" + camera_elevation=".3" + camera_distance=".8" + camera_angle="15"> + <param_skeleton> + <bone + name="mNeck" + scale="0 0 .5" /> + </param_skeleton> </param> - + <param - id="142" + id="11001" group="0" - name="Hair_Part_Left" - label="Left Part" - wearable="hair" - edit_group="hair_style" - edit_group_order="19" - label_min="No Part" - label_max="Part" - value_min="0" + name="Hover" + wearable="shape" + edit_group="shape_body" + edit_group_order="4" + label_min="Lower" + label_max="Higher" + value_min="-2" value_max="2" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> + value_default="0" + camera_distance="2.5"> + <param_skeleton /> </param> - + <param - id="143" - group="0" - name="Hair_Sides_Full" - label="Full Hair Sides" - show_simple="true" - wearable="hair" - edit_group="hair_style" - edit_group_order="11" - label_min="Mowhawk" - label_max="Full Sides" - value_min="-4" - value_max="1.5" - value_default="0.125" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </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="144" + id="30004" group="1" - name="Bangs_Front_Up" - label="Front Bangs Up" - wearable="hair" - edit_group="hair_style" - label_min="Bangs" - label_max="Bangs Up" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + 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="145" + id="30020" group="1" - clothing_morph="true" - name="Bangs_Front_Down" - label="Front Bangs Down" - wearable="hair" - edit_group="hair_style" - label_min="Bangs" - label_max="Bangs Down" - value_min="0" - value_max="5" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="146" + id="30517" group="1" - name="Bangs_Sides_Up" - label="Side Bangs Up" - wearable="hair" - edit_group="hair_style" - label_min="Side Bangs" - label_max="Side Bangs Up" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + 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="147" + id="30656" group="1" - clothing_morph="true" - name="Bangs_Sides_Down" - label="Side Bangs Down" - wearable="hair" - edit_group="hair_style" - label_min="Side Bangs" - label_max="Side Bangs Down" - value_min="0" - value_max="2" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="148" + id="30155" group="1" - name="Bangs_Back_Up" - label="Back Bangs Up" - wearable="hair" - edit_group="hair_style" - label_min="Back Bangs" - label_max="Back Bangs Up" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="150"> - <param_morph /> + 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="149" + id="30653" group="1" - name="Bangs_Back_Down" - label="Back Bangs Down" - clothing_morph="true" - wearable="hair" - edit_group="hair_style" - label_min="Back Bangs" - label_max="Back Bangs Down" - value_min="0" - value_max="2" - camera_elevation=".1" - camera_distance=".5" - camera_angle="150"> - <param_morph /> - </param> + 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="171" + id="30505" group="1" - name="Hair_Front_Down" - label="Front Hair Down" - wearable="hair" - edit_group="hair_style" - label_min="Front Hair" - label_max="Front Hair Down" + name="Lip_Thickness" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="172" + id="31505" group="1" - name="Hair_Front_Up" - label="Front Hair Up" - wearable="hair" - edit_group="hair_style" - label_min="Front Hair" - label_max="Front Hair Up" + name="Lip_Thickness" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="173" + id="30797" group="1" - name="Hair_Sides_Down" - label="Sides Hair Down" - wearable="hair" - edit_group="hair_style" - label_min="Sides Hair" - label_max="Sides Hair Down" + name="Fat_Upper_Lip" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + 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="174" + id="30798" group="1" - name="Hair_Sides_Up" - label="Sides Hair Up" - wearable="hair" - edit_group="hair_style" - label_min="Sides Hair" - label_max="Sides Hair Up" + name="Fat_Lower_Lip" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="175" + id="30506" group="1" - name="Hair_Back_Down" - label="Back Hair Down" - clothing_morph="true" - wearable="hair" - edit_group="hair_style" - label_min="Back Hair" - label_max="Back Hair Down" - value_min="0" - value_max="3" - camera_elevation=".1" - camera_distance=".5" - camera_angle="150"> - <param_morph /> - </param> + 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="176" + id="30658" group="1" - name="Hair_Back_Up" - label="Back Hair Up" - wearable="hair" - edit_group="hair_style" - label_min="Back Hair" - label_max="Back Hair Up" + name="Frown_Mouth" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="150"> - <param_morph /> - </param> + value_max="1.4"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0 -0.005" /> - <param - id="177" - group="0" - name="Hair_Rumpled" - label="Rumpled Hair" - show_simple="true" - wearable="hair" - clothing_morph="true" - edit_group="hair_style" - edit_group_order="14.5" - label_min="Smooth Hair" - label_max="Rumpled Hair" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> + <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="178" + id="30657" group="1" - name="Hair_Swept_Back" - label="Swept Back Hair" - wearable="hair" - edit_group="hair_style" - label_min="NotHair" - label_max="Swept Back" + name="Smile_Mouth" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="90"> - <param_morph /> + 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="179" + id="30025" group="1" - name="Hair_Swept_Forward" - label="Swept Forward Hair" - wearable="hair" - edit_group="hair_style" - label_min="Hair" - label_max="Swept Forward" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="90"> - <param_morph /> - </param> + 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="190" + id="31663" group="1" - name="Hair_Tilt_Right" - label="Hair Tilted Right" - wearable="hair" - edit_group="hair_style" - label_min="Hair" - label_max="Tilt Right" + name="Shift_Mouth" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> + 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="191" + id="32663" group="1" - name="Hair_Tilt_Left" - label="Hair Tilted Left" - wearable="hair" - edit_group="hair_style" - label_min="Hair" - label_max="Tilt Left" + name="Shift_Mouth" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> - </param> + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> - <param - id="192" - group="0" - name="Bangs_Part_Middle" - label="Part Bangs" - wearable="hair" - edit_group="hair_style" - edit_group_order="20" - label_min="No Part" - label_max="Part Bangs" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="0"> - <param_morph /> - </param> + <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="640" + id="30035" group="1" - name="Hair_Egg_Head" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" - value_min="-1.3" - value_max="1"> - <param_morph /> + 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="641" + id="30015" group="1" - name="Hair_Squash_Stretch_Head" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" + name="Ears_Out" value_min="-.5" - value_max="1"> - <param_morph /> - </param> - + 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="642" + id="30796" group="1" - name="Hair_Square_Head" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" - value_min="0" - value_max="1"> - <param_morph /> + 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="643" + id="30185" group="1" - name="Hair_Round_Head" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" - value_min="0" + name="Deep_Chin" + value_min="-1" value_max="1"> - <param_morph /> - </param> + <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="644" + id="40185" group="1" - name="Hair_Forehead_Round" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" - value_min="0" + name="Deep_Chin" + value_min="-1" value_max="1"> - <param_morph /> - </param> + <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="645" + id="30760" group="1" - name="Hair_Forehead_Slant" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" - value_min="0" - value_max="1"> - <param_morph /> - </param> + 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="774" + id="30665" group="1" - name="Shear_Head_Hair" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" + name="Jaw_Jut" value_min="-2" value_max="2"> - <param_morph /> - </param> + <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="771" + id="30006" group="1" - name="Elongate_Head_Hair" - wearable="hair" - edit_group="hair_style" - cross_wearable="true" + name="Bulbous_Nose_Tip" value_min="-1" - value_max="1"> - <param_morph /> + 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="674" - group="0" - name="Hair_Shear_Back" - wearable="hair" - edit_group="hair_style" - edit_group_order="12" - label="Shear Back" - label_min="Full Back" - label_max="Sheared Back" - value_min="-1" - value_max="2" - value_default="-0.3" - camera_elevation=".1" - camera_distance=".5" - camera_angle="100"> - <param_morph /> - </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="762" - group="0" - name="Hair_Shear_Front" - wearable="hair" - edit_group="hair_style" - edit_group_order="11.8" - label="Shear Front" - show_simple="true" - label_min="Full Front" - label_max="Sheared Front" - value_min="0" - value_max="3" - camera_elevation=".1" - camera_distance=".5" - camera_angle="30"> - <param_morph /> - </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="754" - group="0" - name="Hair_Taper_Back" - wearable="hair" - edit_group="hair_style" - edit_group_order="14" - label="Taper Back" - label_min="Wide Back" - label_max="Narrow Back" - value_min="-1" - value_max="2" - value_default="0" - camera_elevation=".1" - camera_distance=".5" - camera_angle="160"> - <param_morph /> + 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="755" - group="0" - name="Hair_Taper_Front" - wearable="hair" - edit_group="hair_style" - edit_group_order="13" - label="Taper Front" - label_min="Wide Front" - label_max="Narrow Front" + id="30024" + group="1" + name="Wide_Eyes" value_min="-1.5" - value_max="1.5" - value_default="0.05" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph /> - </param> + 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="782" + id="30650" group="1" - clothing_morph="true" - name="Hair_Pigtails_Short" - wearable="hair" - edit_group="hair_style" - value_min="0" - value_max="1"> - <param_morph /> + 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="783" + id="30765" group="1" - clothing_morph="true" - name="Hair_Pigtails_Med" - wearable="hair" - edit_group="hair_style" - value_min="0" - value_max="1"> - <param_morph /> + 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="790" + id="31629" group="1" - clothing_morph="true" - name="Hair_Pigtails_Medlong" - wearable="hair" - edit_group="hair_style" + name="Forehead Angle" value_min="0" value_max="1"> - <param_morph /> - </param> + <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="784" + id="41629" group="1" - clothing_morph="true" - name="Hair_Pigtails_Long" - wearable="hair" - edit_group="hair_style" + name="Forehead Angle" value_min="0" value_max="1"> - <param_morph /> - </param> + <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="786" + id="30647" group="1" - name="Hair_Ponytail_Short" - wearable="hair" - edit_group="hair_style" + 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_morph /> + <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="787" + id="42629" group="1" - name="Hair_Ponytail_Med" - wearable="hair" - edit_group="hair_style" + name="Forehead Angle" value_min="0" value_max="1"> - <param_morph /> + <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="788" + id="30001" group="1" - name="Hair_Ponytail_Long" - clothing_morph="true" - wearable="hair" - edit_group="hair_style" - value_min="0" - value_max="1"> - <param_morph /> + 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> - <!-- #end morph targets --> - </mesh> + <bone + name="mFaceNoseBridge" + scale="0.15 0.01 0.7" + offset="0.009 0 -0.006" /> - <mesh - type="hairMesh" - lod="1" - file_name="avatar_hair_1.llm" - min_pixel_width="160" - reference="avatar_hair.llm"> - </mesh> + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0.001 0 0" /> - <mesh - type="hairMesh" - lod="2" - file_name="avatar_hair_2.llm" - min_pixel_width="80" - reference="avatar_hair.llm"> - </mesh> + </param_skeleton> + </param> - <mesh - type="hairMesh" - lod="3" - file_name="avatar_hair_3.llm" - min_pixel_width="40" - reference="avatar_hair.llm"> - </mesh> + <param + id="30758" + group="1" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + <param_skeleton> - <mesh - type="hairMesh" - lod="4" - file_name="avatar_hair_4.llm" - min_pixel_width="20" - reference="avatar_hair.llm"> - </mesh> + <bone + name="mFaceNoseBridge" + scale="0 0 0.2" + offset="0.0025 0 -0.001" /> - <mesh - type="hairMesh" - lod="5" - file_name="avatar_hair_5.llm" - min_pixel_width="0" - reference="avatar_hair.llm"> - </mesh> + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0.004 0 0.001" /> - <mesh - type="headMesh" - lod="0" - file_name="avatar_head.llm" - min_pixel_width="320"> - <!-- - begin morph targets - ############# - tweakable morphs - ############# - --> - <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_morph /> + </param_skeleton> </param> <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_morph /> - </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="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" + 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" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> - <param_morph /> + 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="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" + 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" + file_name="avatar_hair.llm" + min_pixel_width="320"> + <!-- begin morph targets --> + <param + id="180" + group="1" + name="Hair_Volume" + label="Hair Volume" + show_simple="true" + wearable="hair" + clothing_morph="true" + edit_group="hair_style" + label_min="Less" + label_max="More" + value_min="0" + value_max="1.3" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + camera_angle="20"> <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" - value_min="-.5" - value_max="1" + id="761" + group="1" + name="Hair_Volume_Small" + label="Hair Volume" + show_simple="true" + wearable="hair" + edit_group="hair_style" + label_min="Less" + label_max="More" + value_min="0" + value_max="1.3" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - id="5" + id="181" group="0" - name="Cleft_Chin" - label="Chin Cleft" - wearable="shape" - edit_group="shape_chin" - edit_group_order="6" - label_min="Round" - label_max="Cleft" - value_min="-.1" + name="Hair_Big_Front" + label="Big Hair Front" + wearable="hair" + edit_group="hair_style" + edit_group_order="5" + label_min="Less" + label_max="More" + value_min="-1" value_max="1" - camera_elevation="0" - camera_distance=".28" - camera_angle="-20"> + value_default="0.14" + camera_elevation=".1" + camera_distance=".5" + camera_angle="90"> <param_morph /> </param> <param - id="6" + id="182" 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" + name="Hair_Big_Top" + label="Big Hair Top" + wearable="hair" + edit_group="hair_style" + edit_group_order="6" + label_min="Less" + label_max="More" + value_min="-1" value_max="1" + value_default=".7" camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> + camera_distance=".5" + camera_angle="90"> <param_morph /> </param> <param - id="7" + id="183" 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" + name="Hair_Big_Back" + clothing_morph="true" + label="Big Hair Back" + wearable="hair" + edit_group="hair_style" + edit_group_order="7" + label_min="Less" + label_max="More" + value_min="-1" + value_max="1" + value_default="0.05" camera_elevation=".1" - camera_distance=".4" - camera_angle="45"> + camera_distance=".7" + camera_angle="90"> <param_morph /> </param> <param - id="8" + id="184" 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_morph /> - </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" + name="Hair_Spiked" + label="Spiked Hair" + show_simple="true" + wearable="hair" + clothing_morph="true" + edit_group="hair_style" + edit_group_order="15" + label_min="No Spikes" + label_max="Big Spikes" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".4" - camera_angle="5"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - id="11" + id="140" 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" + name="Hair_Part_Middle" + label="Middle Part" + wearable="hair" + edit_group="hair_style" + edit_group_order="17" + label_min="No Part" + label_max="Part" + value_min="0" + value_max="2" camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + camera_distance=".5" + camera_angle="0"> <param_morph /> </param> <param - id="758" + id="141" 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" + name="Hair_Part_Right" + label="Right Part" + wearable="hair" + edit_group="hair_style" + edit_group_order="18" + label_min="No Part" + label_max="Part" + value_min="0" + value_max="2" camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + camera_distance=".5" + camera_angle="0"> <param_morph /> </param> <param - id="12" + id="142" group="0" - name="Jowls" - wearable="shape" - edit_group="shape_chin" - edit_group_order="5" - label_min="Less" - label_max="More" - value_min="-.5" - value_max="2.5" + name="Hair_Part_Left" + label="Left Part" + wearable="hair" + edit_group="hair_style" + edit_group_order="19" + label_min="No Part" + label_max="Part" + value_min="0" + value_max="2" camera_elevation=".1" - camera_distance=".4" + camera_distance=".5" camera_angle="0"> <param_morph /> </param> <param - id="13" + id="143" group="0" - name="Cleft_Chin_Upper" - label="Upper Chin Cleft" - wearable="shape" - edit_group="shape_chin" - edit_group_order="7" - label_min="Round" - label_max="Cleft" - value_min="0" + name="Hair_Sides_Full" + label="Full Hair Sides" + show_simple="true" + wearable="hair" + edit_group="hair_style" + edit_group_order="11" + label_min="Mowhawk" + label_max="Full Sides" + value_min="-4" value_max="1.5" - camera_elevation="0" - camera_distance=".28" - camera_angle="-20"> + value_default="0.125" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> <param_morph /> </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" + id="144" + group="1" + name="Bangs_Front_Up" + label="Front Bangs Up" + wearable="hair" + edit_group="hair_style" + label_min="Bangs" + label_max="Bangs Up" + value_min="0" value_max="1" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + 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" + id="145" + group="1" + clothing_morph="true" + name="Bangs_Front_Down" + label="Front Bangs Down" + wearable="hair" + edit_group="hair_style" + label_min="Bangs" + label_max="Bangs Down" + value_min="0" + value_max="5" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> - <!--Pointy eyebrows became a driver/driven param with new max value for backwards compatibility between 1.0 and 1.1--> <param - id="870" + id="146" group="1" - name="Pointy_Eyebrows" - label="Eyebrow Points" + name="Bangs_Sides_Up" + label="Side Bangs Up" wearable="hair" - edit_group="hair_eyebrows" - edit_group_order="4" - label_min="Smooth" - label_max="Pointy" - value_min="-.5" + edit_group="hair_style" + label_min="Side Bangs" + label_max="Side Bangs Up" + value_min="0" value_max="1" camera_elevation=".1" - camera_distance=".3"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </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"> + id="147" + group="1" + clothing_morph="true" + name="Bangs_Sides_Down" + label="Side Bangs Down" + wearable="hair" + edit_group="hair_style" + label_min="Side Bangs" + label_max="Side Bangs Down" + value_min="0" + value_max="2" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> <param_morph /> </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" + id="148" + group="1" + name="Bangs_Back_Up" + label="Back Bangs Up" + wearable="hair" + edit_group="hair_style" + label_min="Back Bangs" + label_max="Back Bangs Up" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + camera_angle="150"> <param_morph /> </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" + id="149" + group="1" + name="Bangs_Back_Down" + label="Back Bangs Down" + clothing_morph="true" + wearable="hair" + edit_group="hair_style" + label_min="Back Bangs" + label_max="Back Bangs Down" + value_min="0" + value_max="2" camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> + camera_distance=".5" + camera_angle="150"> <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" + id="171" + group="1" + name="Hair_Front_Down" + label="Front Hair Down" + wearable="hair" + edit_group="hair_style" + label_min="Front Hair" + label_max="Front Hair Down" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".3"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </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" + id="172" + group="1" + name="Hair_Front_Up" + label="Front Hair Up" + wearable="hair" + edit_group="hair_style" + label_min="Front Hair" + label_max="Front Hair Up" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".35"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - id="22" - group="0" - name="Attached_Earlobes" - label="Attached Earlobes" - wearable="shape" - edit_group="shape_ears" - edit_group_order="3" - label_min="Unattached" - label_max="Attached" + id="173" + group="1" + name="Hair_Sides_Down" + label="Sides Hair Down" + wearable="hair" + edit_group="hair_style" + label_min="Sides Hair" + label_max="Sides Hair Down" value_min="0" value_max="1" camera_elevation=".1" - camera_distance=".3" - camera_angle="45"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </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" + id="174" + group="1" + name="Hair_Sides_Up" + label="Sides Hair Up" + wearable="hair" + edit_group="hair_style" + label_min="Sides Hair" + label_max="Sides Hair Up" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".35"> + camera_distance=".5" + camera_angle="20"> <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" + id="175" + group="1" + name="Hair_Back_Down" + label="Back Hair Down" + clothing_morph="true" + wearable="hair" + edit_group="hair_style" + label_min="Back Hair" + label_max="Back Hair Down" + value_min="0" + value_max="3" camera_elevation=".1" - camera_distance=".35"> + camera_distance=".5" + camera_angle="150"> <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" + id="176" + group="1" + name="Hair_Back_Up" + label="Back Hair Up" + wearable="hair" + edit_group="hair_style" + label_min="Back Hair" + label_max="Back Hair Up" + value_min="0" + value_max="1" 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"> + camera_distance=".5" + camera_angle="150"> <param_morph /> </param> <param - id="764" + id="177" 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"> + name="Hair_Rumpled" + label="Rumpled Hair" + show_simple="true" + wearable="hair" + clothing_morph="true" + edit_group="hair_style" + edit_group_order="14.5" + label_min="Smooth Hair" + label_max="Rumpled Hair" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - id="26" + id="178" group="1" - wearable="shape" - name="Lips_Thin" - edit_group="driven" + name="Hair_Swept_Back" + label="Swept Back Hair" + wearable="hair" + edit_group="hair_style" + label_min="NotHair" + label_max="Swept Back" value_min="0" - value_max=".7"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="90"> <param_morph /> </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" + id="179" + group="1" + name="Hair_Swept_Forward" + label="Swept Forward Hair" + wearable="hair" + edit_group="hair_style" + label_min="Hair" + label_max="Swept Forward" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + camera_distance=".5" + camera_angle="90"> <param_morph /> </param> <param - id="28" + id="190" group="1" - name="Lips_Fat" - wearable="shape" - edit_group="driven" + name="Hair_Tilt_Right" + label="Hair Tilted Right" + wearable="hair" + edit_group="hair_style" + label_min="Hair" + label_max="Tilt Right" value_min="0" - value_max="2"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> <param_morph /> </param> <param - id="29" + id="191" group="1" - name="Wide_Upper_Lip" - wearable="shape" - edit_group="driven" - value_min="-.7" - value_max="1.3"> + name="Hair_Tilt_Left" + label="Hair Tilted Left" + wearable="hair" + edit_group="hair_style" + label_min="Hair" + label_max="Tilt Left" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> <param_morph /> </param> <param - id="30" - group="1" - name="Wide_Lower_Lip" - wearable="shape" - edit_group="driven" - value_min="-.7" - value_max="1.3"> + id="192" + group="0" + name="Bangs_Part_Middle" + label="Part Bangs" + wearable="hair" + edit_group="hair_style" + edit_group_order="20" + label_min="No Part" + label_max="Part Bangs" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> <param_morph /> </param> - <!--Arced eyebrows became a driver/driven param with new max value for backwards compatibility between 1.0 and 1.1--> <param - id="872" + id="640" group="1" - name="Arced_Eyebrows" - label="Eyebrow Arc" + name="Hair_Egg_Head" wearable="hair" - edit_group="hair_eyebrows" - edit_group_order="3" - label_min="Flat" - label_max="Arced" - value_min="0" + edit_group="hair_style" + cross_wearable="true" + value_min="-1.3" value_max="1"> <param_morph /> </param> - <!--Lower eyebrows became a driver/driven param with new min value for backwards compatibility between 1.0 and 1.1--> <param - id="871" + id="641" group="1" - name="Lower_Eyebrows" - label="Eyebrow Height" - show_simple="true" + name="Hair_Squash_Stretch_Head" wearable="hair" - edit_group="hair_eyebrows" - edit_group_order="2.5" - label_min="Higher" - label_max="Lower" - value_min="-2" - value_max="2"> - <param_morph /> - </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"> + edit_group="hair_style" + cross_wearable="true" + value_min="-.5" + value_max="1"> <param_morph /> </param> <param - id="186" + id="642" group="1" - name="Egg_Head" - label="Egg Head" - wearable="shape" - edit_group="shape_head" - label_min="Chin Heavy" - label_max="Forehead Heavy" - value_min="-1.3" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> + name="Hair_Square_Head" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" + value_min="0" + value_max="1"> <param_morph /> </param> <param - id="187" + id="643" group="1" - name="Squash_Stretch_Head" - label="Squash/Stretch Head" - wearable="shape" - edit_group="shape_head" - label_min="Squash Head" - label_max="Stretch Head" - value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> - <param_morph> - <volume_morph - name="HEAD" - scale="-0.008 -0.006 0.015"/> - </param_morph> + name="Hair_Round_Head" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" + value_min="0" + value_max="1"> + <param_morph /> </param> <param - id="188" + id="644" group="1" - name="Square_Head" - wearable="shape" - label_min="Less Square" - label_max="More Square" + name="Hair_Forehead_Round" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" value_min="0" - value_max=".7" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> + value_max="1"> <param_morph /> </param> <param - id="189" + id="645" group="1" - wearable="shape" - name="Round_Head" - label_min="Less Round" - label_max="More Round" + name="Hair_Forehead_Slant" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5" - camera_angle="20"> + value_max="1"> <param_morph /> </param> <param - id="194" + id="774" group="1" - name="Eye_Spread" - wearable="shape" - edit_group="shape_eyes" - label_min="Eyes Together" - label_max="Eyes Spread" + name="Shear_Head_Hair" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" value_min="-2" value_max="2"> <param_morph /> </param> <param - id="400" - sex="male" + id="771" group="1" - name="Displace_Hair_Facial" - label="Hair Thickess" + name="Elongate_Head_Hair" wearable="hair" - edit_group="hair_facial" - label_min="Cropped Hair" - label_max="Bushy Hair" - value_min="0" - value_max="2"> + edit_group="hair_style" + cross_wearable="true" + value_min="-1" + value_max="1"> <param_morph /> </param> <param - id="506" + id="674" 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" - label="Fat Head" - wearable="shape" - edit_group="shape_body" - label_min="Skinny" - label_max="Fat" - value_min="0" - value_max="1" - camera_elevation=".3"> - <param_morph/> - </param> - - <param - id="630" - group="1" - name="Forehead_Round" - label="Round Forehead" - wearable="shape" - label_min="Less" - label_max="More" - value_min="0" - value_max="1"> + name="Hair_Shear_Back" + wearable="hair" + edit_group="hair_style" + edit_group_order="12" + label="Shear Back" + label_min="Full Back" + label_max="Sheared Back" + value_min="-1" + value_max="2" + value_default="-0.3" + camera_elevation=".1" + camera_distance=".5" + camera_angle="100"> <param_morph /> </param> <param - id="631" - group="1" - name="Forehead_Slant" - label="Slanted Forehead" - wearable="shape" - label_min="Less" - label_max="More" + id="762" + group="0" + name="Hair_Shear_Front" + wearable="hair" + edit_group="hair_style" + edit_group_order="11.8" + label="Shear Front" + show_simple="true" + label_min="Full Front" + label_max="Sheared Front" value_min="0" - value_max="1"> + value_max="3" + camera_elevation=".1" + camera_distance=".5" + camera_angle="30"> <param_morph /> </param> <param - id="650" + id="754" 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" + name="Hair_Taper_Back" + wearable="hair" + edit_group="hair_style" + edit_group_order="14" + label="Taper Back" + label_min="Wide Back" + label_max="Narrow Back" + value_min="-1" + value_max="2" + value_default="0" camera_elevation=".1" - camera_distance=".30"> - <param_morph /> - </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"> + camera_distance=".5" + camera_angle="160"> <param_morph /> </param> - <param - id="653" + id="755" 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"> + name="Hair_Taper_Front" + wearable="hair" + edit_group="hair_style" + edit_group_order="13" + label="Taper Front" + label_min="Wide Front" + label_max="Narrow Front" + value_min="-1.5" + value_max="1.5" + value_default="0.05" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> <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"> + id="782" + group="1" + clothing_morph="true" + name="Hair_Pigtails_Short" + wearable="hair" + edit_group="hair_style" + value_min="0" + value_max="1"> <param_morph /> </param> <param - id="657" + id="783" group="1" - name="Smile_Mouth" - wearable="shape" - label="Mouth Corner" - edit_group="shape_mouth" - label_min="Corner Normal" - label_max="Corner Up" + clothing_morph="true" + name="Hair_Pigtails_Med" + wearable="hair" + edit_group="hair_style" value_min="0" - value_max="1.4" - camera_distance=".3" - camera_elevation=".04"> + value_max="1"> <param_morph /> </param> <param - id="658" + id="790" group="1" - name="Frown_Mouth" - wearable="shape" - label="Mouth Corner" - edit_group="shape_mouth" - label_min="Corner Normal" - label_max="Corner Down" + clothing_morph="true" + name="Hair_Pigtails_Medlong" + wearable="hair" + edit_group="hair_style" value_min="0" - value_max="1.2" - camera_distance=".3" - camera_elevation=".04"> + value_max="1"> <param_morph /> </param> <param - id="797" + id="784" group="1" - name="Fat_Upper_Lip" - wearable="shape" - label="Fat Upper Lip" - edit_group="shape_mouth" - label_min="Normal Upper" - label_max="Fat Upper" + clothing_morph="true" + name="Hair_Pigtails_Long" + wearable="hair" + edit_group="hair_style" value_min="0" - value_max="1.5" - camera_distance=".3" - camera_elevation=".04"> + value_max="1"> <param_morph /> </param> <param - id="798" + id="786" group="1" - name="Fat_Lower_Lip" - wearable="shape" - label="Fat Lower Lip" - edit_group="shape_mouth" - label_min="Normal Lower" - label_max="Fat Lower" + name="Hair_Ponytail_Short" + wearable="hair" + edit_group="hair_style" value_min="0" - value_max="1.5" - camera_distance=".3" - camera_elevation=".04"> + value_max="1"> <param_morph /> </param> <param - id="660" + id="787" group="1" - name="Shear_Head" - wearable="shape" - label="Shear Face" - edit_group="shape_head" - label_min="Shear Left" - label_max="Shear Right" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04"> + name="Hair_Ponytail_Med" + wearable="hair" + edit_group="hair_style" + value_min="0" + value_max="1"> <param_morph /> </param> <param - id="770" + id="788" group="1" - name="Elongate_Head" - wearable="shape" - label="Shear Face" - edit_group="shape_head" - label_min="Flat Head" - label_max="Long Head" - value_min="-1" - value_max="1" - value_default="0" - camera_distance=".5" - camera_elevation=".04"> - <param_morph> - <volume_morph - name="HEAD" - scale="0.02 0.0 0.0"/> - </param_morph> + name="Hair_Ponytail_Long" + clothing_morph="true" + wearable="hair" + edit_group="hair_style" + value_min="0" + value_max="1"> + <param_morph /> </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> + <!-- #end morph targets --> + </mesh> + + <mesh + type="hairMesh" + lod="1" + file_name="avatar_hair_1.llm" + min_pixel_width="160" + reference="avatar_hair.llm"> + </mesh> + + <mesh + type="hairMesh" + lod="2" + file_name="avatar_hair_2.llm" + min_pixel_width="80" + reference="avatar_hair.llm"> + </mesh> + + <mesh + type="hairMesh" + lod="3" + file_name="avatar_hair_3.llm" + min_pixel_width="40" + reference="avatar_hair.llm"> + </mesh> + + <mesh + type="hairMesh" + lod="4" + file_name="avatar_hair_4.llm" + min_pixel_width="20" + reference="avatar_hair.llm"> + </mesh> + + <mesh + type="hairMesh" + lod="5" + file_name="avatar_hair_5.llm" + min_pixel_width="0" + reference="avatar_hair.llm"> + </mesh> + <mesh + type="headMesh" + lod="0" + file_name="avatar_head.llm" + min_pixel_width="320"> + <!-- + begin morph targets + ############# + tweakable morphs + ############# + --> <param - id="664" - group="0" - name="Pop_Eye" - wearable="shape" - label="Eye Pop" - edit_group="shape_eyes" - edit_group_order="8" - label_min="Pop Right Eye" - label_max="Pop Left Eye" - value_min="-1.3" - value_max="1.3" - value_default="0" - camera_elevation=".1" - camera_distance=".35"> + id="20001" + group="1" + name="Big_Brow" + value_min="-.3" + value_max="2"> <param_morph /> </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"> + id="20002" + group="1" + name="Nose_Big_Out" + value_min="-0.8" + value_max="2.5"> <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"> + id="20517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> <param_morph /> </param> <param - id="686" + id="20020" group="1" - name="Head_Eyes_Big" - wearable="shape" - label="Eye Size" - edit_group="shape_eyes" - label_min="Beady Eyes" - label_max="Anime Eyes" - show_simple="true" - value_min="-2" - value_max="2" - value_default="0"> + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5"> <param_morph /> </param> - + <param - id="767" + id="20656" group="1" - name="Bug_Eyed_Head" - wearable="shape" - label="Eye Depth" - edit_group="shape_eyes" - edit_group_order="4.5" - label_min="Sunken Eyes" - label_max="Bug Eyes" + name="Crooked_Nose" value_min="-2" - value_max="2" - value_default="0"> + value_max="2"> <param_morph /> </param> - - <!-- - #Fat_Lips = Fat_Lips 34 1 0 1 - #Wide_Lips = Wide_Lips 35 1 0 1 - #Wide_Nose = Wide_Nose 36 1 0 1 - --> - <!-- - ############## - # Facial Expression morphs - ############## - --> + <param - id="300" + id="20004" group="1" - name="Express_Closed_Mouth" - value_default="1" - value_min="0" + name="Broad_Nostrils" + value_min="-.5" value_max="1"> <param_morph /> </param> <param - id="301" + id="20653" group="1" - name="Express_Tongue_Out" - value_min="0" - value_max="1"> + name="Tall_Lips" + value_min="-1" + value_max="2"> <param_morph /> </param> - + <param - id="302" + id="20506" group="1" - name="Express_Surprise_Emote" - value_min="0" - value_max="1"> + name="Mouth_Height" + value_min="-2" + value_max="2"> <param_morph /> </param> - + <param - id="303" + id="20764" group="1" - name="Express_Wink_Emote" - value_min="0" - value_max="1"> - <param_morph /> - </param> + name="Lip_Cleft_Deep" + value_min="-.5" + value_max="1.2"> + <param_morph/> + </param> <param - id="304" + id="20025" group="1" - name="Express_Embarrassed_Emote" - value_min="0" - value_max="1"> - <param_morph /> + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + <param_morph/> </param> - + <param - id="305" + id="20663" group="1" - name="Express_Shrug_Emote" - value_min="0" - value_max="1"> + name="Shift_Mouth" + value_min="-2" + value_max="2" + value_default="0"> <param_morph /> </param> - + <param - id="306" + id="20035" group="1" - name="Express_Kiss" - value_min="0" - value_max="1"> - <param_morph /> + name="Big_Ears" + value_min="-1" + value_max="2"> + <param_morph/> </param> - + <param - id="307" + id="20015" group="1" - name="Express_Bored_Emote" - value_min="0" - value_max="1"> - <param_morph /> + name="Ears_Out" + value_min="-.5" + value_max="1.5"> + <param_morph/> </param> - + <param - id="308" + id="20796" group="1" - name="Express_Repulsed_Emote" - value_min="0" - value_max="1"> + name="Pointy_Ears" + value_min="-.4" + value_max="3"> <param_morph /> </param> - + <param - id="309" + id="20185" group="1" - name="Express_Disdain" - value_min="0" + name="Deep_Chin" + value_min="-1" value_max="1"> <param_morph /> </param> - + <param - id="310" + id="20665" group="1" - name="Express_Afraid_Emote" - value_min="0" - value_max="1"> + name="Jaw_Jut" + value_min="-2" + value_max="2"> <param_morph /> </param> - + <param - id="311" + id="20024" group="1" - name="Express_Worry_Emote" - value_min="0" - value_max="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="312" + id="20759" group="1" - name="Express_Cry_Emote" - value_min="0" - value_max="1"> + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> <param_morph /> </param> <param - id="313" + id="5" + group="0" + name="Cleft_Chin" + label="Chin Cleft" + wearable="shape" + edit_group="shape_chin" + edit_group_order="6" + label_min="Round" + label_max="Cleft" + value_min="-.1" + value_max="1" + camera_elevation="0" + camera_distance=".28" + camera_angle="-20"> + <param_morph /> + </param> + + <param + id="20006" group="1" - name="Express_Sad_Emote" - value_min="0" + name="Bulbous_Nose_Tip" + value_min="-.3" value_max="1"> <param_morph /> </param> <param - id="314" + id="20007" group="1" - name="Express_Anger_Emote" - value_min="0" - value_max="1"> + name="Weak_Chin" + value_min="-.5" + value_max=".5"> <param_morph /> </param> <param - id="315" + id="20008" group="1" - name="Express_Frown" - value_min="0" - value_max="1"> + name="Double_Chin" + value_min="-.5" + value_max="1.5"> <param_morph /> </param> <param - id="316" + id="20010" group="1" - name="Express_Laugh_Emote" - value_min="0" - value_max="1"> + name="Sunken_Cheeks" + value_min="-1.5" + value_max="3"> <param_morph /> </param> <param - id="317" + id="20011" group="1" - name="Express_Toothsmile" - value_min="0" - value_max="1"> + name="Noble_Nose_Bridge" + value_min="-.5" + value_max="1.5"> <param_morph /> </param> <param - id="318" + id="20758" group="1" - name="Express_Smile" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + <param_morph /> + </param> + + <param + id="12" + group="0" + name="Jowls" + wearable="shape" + edit_group="shape_chin" + edit_group_order="5" + label_min="Less" + label_max="More" + value_min="-.5" + value_max="2.5" + camera_elevation=".1" + camera_distance=".4" + camera_angle="0"> + <param_morph /> + </param> + + <param + id="13" + group="0" + name="Cleft_Chin_Upper" + label="Upper Chin Cleft" + wearable="shape" + edit_group="shape_chin" + edit_group_order="7" + label_min="Round" + label_max="Cleft" value_min="0" - value_max="1"> + value_max="1.5" + camera_elevation="0" + camera_distance=".28" + camera_angle="-20"> <param_morph /> </param> <param - id="632" + id="20014" group="1" - name="Express_Open_Mouth" - value_min="0" + name="High_Cheek_Bones" + value_min="-.5" value_max="1"> <param_morph /> </param> - <!-- - ############## - # Lipsync morphs - ############## - --> + <!--Pointy eyebrows became a driver/driven param with new max value for backwards compatibility between 1.0 and 1.1--> + <param + id="870" + group="1" + name="Pointy_Eyebrows" + label="Eyebrow Points" + wearable="hair" + edit_group="hair_eyebrows" + edit_group_order="4" + label_min="Smooth" + label_max="Pointy" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3"> + <param_morph /> + </param> <param - id="70" + id="20017" group="1" - name="Lipsync_Aah" - value_min="0" + name="Square_Jaw" + value_min="-.5" value_max="1"> <param_morph /> </param> <param - id="71" + id="20018" group="1" - name="Lipsync_Ooh" - value_min="0" - value_max="1"> + name="Puffy_Upper_Cheeks" + value_min="-1.5" + value_max="2.5"> <param_morph /> </param> - <!-- - ############## - # other morphs (not user controlled) - ############## - --> <param - id="40" + id="20019" group="1" - name="Male_Head" - wearable="shape" - edit_group="driven" - value_min="0" + name="Upturned_Nose_Tip" + value_min="-1.5" value_max="1"> <param_morph /> </param> - + <param - id="41" + id="20021" group="1" - name="Old" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + <param_morph /> + </param> + + <param + id="22" + group="0" + name="Attached_Earlobes" + label="Attached Earlobes" + wearable="shape" + edit_group="shape_ears" + edit_group_order="3" + label_min="Unattached" + label_max="Attached" value_min="0" - value_max="1"> + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> <param_morph /> </param> - <!-- - ############## - # animatable morphs - ############## - --> <param - id="51" + id="20023" group="1" - name="Furrowed_Eyebrows" - value_min="0" - value_max="1"> + name="Baggy_Eyes" + value_min="-.5" + value_max="1.5"> <param_morph /> </param> <param - id="53" + id="26" group="1" - name="Surprised_Eyebrows" + wearable="shape" + name="Lips_Thin" + edit_group="driven" value_min="0" - value_max="1"> + value_max=".7"> <param_morph /> </param> <param - id="54" + id="20027" group="1" - name="Worried_Eyebrows" - value_min="0" - value_max="1"> + name="Wide_Nose_Bridge" + value_min="-1.3" + value_max="1.2"> <param_morph /> </param> <param - id="55" + id="28" group="1" - name="Frown_Mouth" + name="Lips_Fat" + wearable="shape" + edit_group="driven" value_min="0" - value_max="1"> + value_max="2"> <param_morph /> </param> <param - id="57" + id="29" group="1" - name="Smile_Mouth" - value_min="0" - value_max="1"> + name="Wide_Upper_Lip" + wearable="shape" + edit_group="driven" + value_min="-.7" + value_max="1.3"> <param_morph /> </param> <param - id="58" + id="30" group="1" - name="Blink_Left" - value_min="0" - value_max="1"> + name="Wide_Lower_Lip" + wearable="shape" + edit_group="driven" + value_min="-.7" + value_max="1.3"> <param_morph /> </param> + <!--Arced eyebrows became a driver/driven param with new max value for backwards compatibility between 1.0 and 1.1--> <param - id="59" + id="872" group="1" - name="Blink_Right" + name="Arced_Eyebrows" + label="Eyebrow Arc" + wearable="hair" + edit_group="hair_eyebrows" + edit_group_order="3" + label_min="Flat" + label_max="Arced" value_min="0" value_max="1"> <param_morph /> </param> - <!-- - #end morph targets - --> - </mesh> - - <mesh - type="headMesh" - lod="1" - file_name="avatar_head_1.llm" - min_pixel_width="160" - reference="avatar_head.llm"> - </mesh> - - <mesh - type="headMesh" - lod="2" - file_name="avatar_head_2.llm" - min_pixel_width="80" - reference="avatar_head.llm"> - </mesh> - - <mesh - type="headMesh" - lod="3" - file_name="avatar_head_3.llm" - min_pixel_width="40" - reference="avatar_head.llm"> - </mesh> - - <mesh - type="headMesh" - lod="4" - file_name="avatar_head_4.llm" - min_pixel_width="0" - reference="avatar_head.llm"> - </mesh> - - <mesh - type="eyelashMesh" - lod="0" - file_name="avatar_eyelashes.llm" - min_pixel_width="320"> - <param - shared="1" - id="660" - group="1" - name="Shear_Head" - wearable="shape" - label="Shear Face" - edit_group="shape_head" - label_min="Shear Left" - label_max="Shear Right" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04"> - <param_morph /> - </param> - + <!--Lower eyebrows became a driver/driven param with new min value for backwards compatibility between 1.0 and 1.1--> <param - shared="1" - id="770" + id="871" group="1" - name="Elongate_Head" - wearable="shape" - label="Shear Face" - edit_group="shape_head" - label_min="Flat Head" - label_max="Long Head" - value_min="-1" - value_max="1" - value_default="0" - camera_distance=".5" - camera_elevation=".04"> - <param_morph /> - </param> - - <param - shared="1" - id="664" - group="0" - name="Pop_Eye" - wearable="shape" - label="Eye Pop" - edit_group="shape_eyes" - edit_group_order="8" - label_min="Pop Right Eye" - label_max="Pop Left Eye" + name="Lower_Eyebrows" + label="Eyebrow Height" + show_simple="true" + wearable="hair" + edit_group="hair_eyebrows" + edit_group_order="2.5" + label_min="Higher" + label_max="Lower" value_min="-2" - value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04" - camera_angle="-20"> - <param_morph /> - </param> - - <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"> + value_max="2"> <param_morph /> </param> <param - shared="1" id="186" group="1" name="Egg_Head" @@ -3465,7 +5411,6 @@ </param> <param - shared="1" id="187" group="1" name="Squash_Stretch_Head" @@ -3479,102 +5424,276 @@ camera_elevation=".1" camera_distance=".5" camera_angle="20"> - <param_morph /> + <param_morph> + <volume_morph + name="HEAD" + scale="-0.008 -0.006 0.015"/> + </param_morph> </param> <param - shared="1" - id="194" + id="188" group="1" - name="Eye_Spread" - edit_group="shape_eyes" - label_min="Eyes Together" - label_max="Eyes Spread" - value_min="-2" - value_max="2"> + name="Square_Head" + wearable="shape" + label_min="Less Square" + label_max="More Square" + value_min="0" + value_max=".7" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - id="518" - group="0" - name="Eyelashes_Long" + id="189" + group="1" wearable="shape" - label="Eyelash Length" - edit_group="shape_eyes" - edit_group_order="7" - label_min="Short" - label_max="Long" - value_min="-.3" - value_max="1.5" + name="Round_Head" + label_min="Less Round" + label_max="More Round" + value_min="0" + value_max="1" camera_elevation=".1" - camera_distance=".30" - camera_angle="-20"> + camera_distance=".5" + camera_angle="20"> <param_morph /> </param> <param - shared="1" - id="650" - group="0" - name="Eyelid_Corner_Up" - label="Outer Eye Corner" + id="194" + group="1" + name="Eye_Spread" 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"> + label_min="Eyes Together" + label_max="Eyes Spread" + value_min="-2" + value_max="2"> <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"> + id="400" + sex="male" + group="1" + name="Displace_Hair_Facial" + label="Hair Thickess" + wearable="hair" + edit_group="hair_facial" + label_min="Cropped Hair" + label_max="Bushy Hair" + value_min="0" + value_max="2"> <param_morph /> </param> <param - shared="1" - id="686" + id="633" group="1" - name="Head_Eyes_Big" + name="Fat_Head" + label="Fat Head" wearable="shape" - label="Eye Size" - edit_group="shape_eyes" - label_min="Beady Eyes" - label_max="Anime Eyes" - value_min="-2" - value_max="2" - show_simple="true" - value_default="0"> - <param_morph /> + edit_group="shape_body" + label_min="Skinny" + label_max="Fat" + value_min="0" + value_max="1" + camera_elevation=".3"> + <param_morph/> </param> <param - shared="1" - id="767" + id="630" group="1" - name="Bug_Eyed_Head" + name="Forehead_Round" + label="Round Forehead" wearable="shape" - label="Eye Depth" - edit_group="shape_eyes" - edit_group_order="4.5" - label_min="Sunken Eyes" + label_min="Less" + label_max="More" + value_min="0" + value_max="1"> + <param_morph /> + </param> + + <param + id="631" + group="1" + name="Forehead_Slant" + label="Slanted Forehead" + wearable="shape" + label_min="Less" + label_max="More" + value_min="0" + value_max="1"> + <param_morph /> + </param> + + <param + id="20880" + group="1" + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_morph /> + </param> + + <param + id="657" + group="1" + name="Smile_Mouth" + wearable="shape" + label="Mouth Corner" + edit_group="shape_mouth" + label_min="Corner Normal" + label_max="Corner Up" + value_min="0" + value_max="1.4" + camera_distance=".3" + camera_elevation=".04"> + <param_morph /> + </param> + + <param + id="658" + group="1" + name="Frown_Mouth" + wearable="shape" + label="Mouth Corner" + edit_group="shape_mouth" + label_min="Corner Normal" + label_max="Corner Down" + value_min="0" + value_max="1.2" + camera_distance=".3" + camera_elevation=".04"> + <param_morph /> + </param> + + <param + id="797" + group="1" + name="Fat_Upper_Lip" + wearable="shape" + label="Fat Upper Lip" + edit_group="shape_mouth" + label_min="Normal Upper" + label_max="Fat Upper" + value_min="0" + value_max="1.5" + camera_distance=".3" + camera_elevation=".04"> + <param_morph /> + </param> + + <param + id="798" + group="1" + name="Fat_Lower_Lip" + wearable="shape" + label="Fat Lower Lip" + edit_group="shape_mouth" + label_min="Normal Lower" + label_max="Fat Lower" + value_min="0" + value_max="1.5" + camera_distance=".3" + camera_elevation=".04"> + <param_morph /> + </param> + + <param + id="660" + group="1" + name="Shear_Head" + wearable="shape" + label="Shear Face" + edit_group="shape_head" + label_min="Shear Left" + label_max="Shear Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> + <param_morph /> + </param> + + <param + id="770" + group="1" + name="Elongate_Head" + wearable="shape" + label="Shear Face" + edit_group="shape_head" + label_min="Flat Head" + label_max="Long Head" + value_min="-1" + value_max="1" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> + <param_morph> + <volume_morph + name="HEAD" + scale="0.02 0.0 0.0"/> + </param_morph> + </param> + + <param + id="664" + group="0" + name="Pop_Eye" + wearable="shape" + label="Eye Pop" + edit_group="shape_eyes" + edit_group_order="8" + label_min="Pop Right Eye" + label_max="Pop Left Eye" + value_min="-1.3" + value_max="1.3" + value_default="0" + camera_elevation=".1" + camera_distance=".35"> + <param_morph /> + </param> + + <param + id="20760" + group="1" + name="Jaw_Angle" + value_min="-1.2" + value_max="2" + value_default="0"> + <param_morph /> + </param> + + <param + id="686" + group="1" + name="Head_Eyes_Big" + wearable="shape" + label="Eye Size" + edit_group="shape_eyes" + label_min="Beady Eyes" + label_max="Anime Eyes" + show_simple="true" + value_min="-2" + value_max="2" + value_default="0"> + <param_morph /> + </param> + + <param + id="767" + group="1" + name="Bug_Eyed_Head" + wearable="shape" + label="Eye Depth" + edit_group="shape_eyes" + edit_group_order="4.5" + label_min="Sunken Eyes" label_max="Bug Eyes" value_min="-2" value_max="2" @@ -3582,13 +5701,27 @@ <param_morph /> </param> + <!-- + #Fat_Lips = Fat_Lips 34 1 0 1 + #Wide_Lips = Wide_Lips 35 1 0 1 + #Wide_Nose = Wide_Nose 36 1 0 1 + --> <!-- ############## # Facial Expression morphs ############## --> <param - shared="1" + id="300" + group="1" + name="Express_Closed_Mouth" + value_default="1" + value_min="0" + value_max="1"> + <param_morph /> + </param> + + <param id="301" group="1" name="Express_Tongue_Out" @@ -3598,7 +5731,6 @@ </param> <param - shared="1" id="302" group="1" name="Express_Surprise_Emote" @@ -3608,7 +5740,6 @@ </param> <param - shared="1" id="303" group="1" name="Express_Wink_Emote" @@ -3618,7 +5749,6 @@ </param> <param - shared="1" id="304" group="1" name="Express_Embarrassed_Emote" @@ -3628,7 +5758,6 @@ </param> <param - shared="1" id="305" group="1" name="Express_Shrug_Emote" @@ -3638,7 +5767,6 @@ </param> <param - shared="1" id="306" group="1" name="Express_Kiss" @@ -3648,7 +5776,6 @@ </param> <param - shared="1" id="307" group="1" name="Express_Bored_Emote" @@ -3658,7 +5785,6 @@ </param> <param - shared="1" id="308" group="1" name="Express_Repulsed_Emote" @@ -3668,7 +5794,6 @@ </param> <param - shared="1" id="309" group="1" name="Express_Disdain" @@ -3678,7 +5803,6 @@ </param> <param - shared="1" id="310" group="1" name="Express_Afraid_Emote" @@ -3688,7 +5812,15 @@ </param> <param - shared="1" + id="311" + group="1" + name="Express_Worry_Emote" + value_min="0" + value_max="1"> + <param_morph /> + </param> + + <param id="312" group="1" name="Express_Cry_Emote" @@ -3698,7 +5830,6 @@ </param> <param - shared="1" id="313" group="1" name="Express_Sad_Emote" @@ -3708,7 +5839,6 @@ </param> <param - shared="1" id="314" group="1" name="Express_Anger_Emote" @@ -3718,7 +5848,6 @@ </param> <param - shared="1" id="315" group="1" name="Express_Frown" @@ -3728,7 +5857,6 @@ </param> <param - shared="1" id="316" group="1" name="Express_Laugh_Emote" @@ -3738,7 +5866,6 @@ </param> <param - shared="1" id="317" group="1" name="Express_Toothsmile" @@ -3748,7 +5875,6 @@ </param> <param - shared="1" id="318" group="1" name="Express_Smile" @@ -3757,16 +5883,10 @@ <param_morph /> </param> - <!-- - ############## - # other morphs (not user controlled) - ############## - --> <param - shared="1" - id="41" + id="632" group="1" - name="Old" + name="Express_Open_Mouth" value_min="0" value_max="1"> <param_morph /> @@ -3774,835 +5894,544 @@ <!-- ############## - # animatable morphs + # Lipsync morphs ############## - --> + --> + <param - shared="1" - id="58" + id="70" group="1" - name="Blink_Left" + name="Lipsync_Aah" value_min="0" value_max="1"> <param_morph /> </param> <param - shared="1" - id="59" + id="71" group="1" - name="Blink_Right" + name="Lipsync_Ooh" value_min="0" value_max="1"> <param_morph /> </param> - </mesh> - <!-- - #headMesh2 = - #headMesh3 = - --> - <mesh - type="upperBodyMesh" - lod="0" - file_name="avatar_upper_body.llm" - min_pixel_width="320"> <!-- - #begin morph targets - ############# - # tweakable morphs - ############# + ############## + # other morphs (not user controlled) + ############## --> <param - id="104" + id="40" group="1" - name="Big_Belly_Torso" + name="Male_Head" wearable="shape" edit_group="driven" value_min="0" value_max="1"> - <param_morph> - <volume_morph - name="BELLY" - scale="0.075 0.04 0.03" - pos="0.07 0 -0.07"/> - <volume_morph - name="PELVIS" - scale="0.075 0.04 0.03" - pos="0.07 0 -0.02"/> - </param_morph> + <param_morph /> </param> <param - id="626" - sex="female" + id="41" group="1" - name="Big_Chest" - label="Chest Size" - wearable="shape" - edit_group="shape_torso" - label_min="Small" - label_max="Large" + name="Old" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance="1" - camera_angle="15"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0273 0.0273 0.0273" - pos="0.038 0.024 -0.016"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0273 0.0273 0.0273" - pos="0.038 -0.024 -0.016"/> - </param_morph> + value_max="1"> + <param_morph /> </param> + <!-- + ############## + # animatable morphs + ############## + --> <param - id="627" - sex="female" + id="51" group="1" - name="Small_Chest" - label="Chest Size" - wearable="shape" - edit_group="shape_torso" - label_min="Large" - label_max="Small" + name="Furrowed_Eyebrows" value_min="0" - value_max="1" - camera_elevation="0" - camera_distance=".28"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="-0.05 0.0 0.0" - pos="-0.01 -0.01 -0.02"/> - <volume_morph - name="RIGHT_PEC" - scale="-0.05 0.0 0.0" - pos="-0.01 -0.01 -0.02"/> - </param_morph> + value_max="1"> + <param_morph /> </param> <param - id="843" - sex="female" + id="53" group="1" - name="No_Chest" - label="Chest Size" - wearable="shape" - edit_group="shape_torso" - label_min="Some" - label_max="None" + name="Surprised_Eyebrows" value_min="0" - value_max="1" - camera_elevation="0" - camera_distance=".28"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="-0.051 0.0 0.0" - pos="-0.02 -0.01 -0.03"/> - <volume_morph - name="RIGHT_PEC" - scale="-0.051 0.0 0.0" - pos="-0.02 -0.01 -0.03"/> - </param_morph> + value_max="1"> + <param_morph /> </param> <param - id="106" + id="54" group="1" - name="Muscular_Torso" - label="Torso Muscles" - show_simple="true" - wearable="shape" - edit_group="shape_torso" - label_min="Regular" - label_max="Muscular" + name="Worried_Eyebrows" 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> + value_max="1"> + <param_morph /> </param> <param - id="648" + id="55" group="1" - sex="female" - name="Scrawny_Torso" - label="Torso Muscles" - show_simple="true" - wearable="shape" - edit_group="shape_torso" - label_min="Regular" - label_max="Scrawny" + name="Frown_Mouth" value_min="0" - value_max="1.3" - camera_elevation=".3" - camera_distance="1.2"> - <param_morph> - <volume_morph - name="BELLY" - scale="0.0 -0.01 0.0" - pos="0.0 0.0 0"/> - <volume_morph - name="UPPER_BACK" - scale="-0.01 -0.01 0.0" - pos="0.0 0.0 0"/> - <volume_morph - name="CHEST" - scale="-0.01 -0.01 0.0" - pos="0.01 0.0 0"/> - <volume_morph - name="L_CLAVICLE" - scale="0.0 -0.03 -0.005" - pos="0.0 0 -0.005"/> - <volume_morph - name="L_UPPER_ARM" - scale="-0.01 -0.01 -0.02" - pos="0 0 0"/> - <volume_morph - name="L_LOWER_ARM" - scale="-0.005 0.0 -0.01" - pos="-0.005 0 0"/> - <volume_morph - name="R_CLAVICLE" - scale="0.0 -0.03 -0.005" - pos="0.0 0 -0.005"/> - <volume_morph - name="R_UPPER_ARM" - scale="-0.01 -0.01 -0.02" - pos="0 0 0"/> - <volume_morph - name="R_LOWER_ARM" - scale="-0.005 0.0 -0.01" - pos="-0.005 0 0"/> - </param_morph> + value_max="1"> + <param_morph /> </param> <param - id="677" + id="57" group="1" - sex="male" - name="Scrawny_Torso_Male" - label="Torso Scrawny" - wearable="shape" - edit_group="shape_torso" - label_min="Regular" - label_max="Scrawny" + name="Smile_Mouth" value_min="0" - value_max="1.3" - camera_elevation=".3" - camera_distance="1.2"> - <param_morph> - <volume_morph - name="BELLY" - scale="-0.01 -0.01 0.0" - pos="0.01 0.0 0"/> - <volume_morph - name="UPPER_BACK" - scale="-0.01 -0.01 0.0" - pos="0.0 0.0 0"/> - <volume_morph - name="CHEST" - scale="-0.02 -0.02 0.0" - pos="0.01 0.0 0"/> - <volume_morph - name="L_CLAVICLE" - scale="0.0 -0.03 -0.005" - pos="0.0 0 -0.005"/> - <volume_morph - name="L_UPPER_ARM" - scale="-0.01 -0.01 -0.02" - pos="0 0 0"/> - <volume_morph - name="L_LOWER_ARM" - scale="-0.005 0.0 -0.01" - pos="-0.005 0 0"/> - <volume_morph - name="R_CLAVICLE" - scale="0.0 -0.03 -0.005" - pos="0.0 0 -0.005"/> - <volume_morph - name="R_UPPER_ARM" - scale="-0.01 -0.01 -0.02" - pos="0 0 0"/> - <volume_morph - name="R_LOWER_ARM" - scale="-0.005 0.0 -0.01" - pos="-0.005 0 0"/> - </param_morph> + value_max="1"> + <param_morph /> </param> <param - id="634" + id="58" group="1" - name="Fat_Torso" - label="Fat Torso" - wearable="shape" - edit_group="shape_body" - label_min="skinny" - label_max="fat" + name="Blink_Left" value_min="0" - value_max="1" - camera_elevation=".3"> - <param_morph> - <volume_morph - name="CHEST" - scale="0.02 0.03 0.03" - pos="0 0 -0.03"/> - <volume_morph - name="PELVIS" - scale="0.02 0.03 0.03" - pos="0 0 -0.03"/> - <volume_morph - name="UPPER_BACK" - scale="0.01 0.03 0.0" - pos="-0.03 0 0"/> - <volume_morph - name="LOWER_BACK" - scale="0.04 0.06 0.0" - pos="-0.06 0 0"/> - <volume_morph - name="LEFT_HANDLE" - pos="0.0 0.08 0.0"/> - <volume_morph - name="RIGHT_HANDLE" - pos="0.0 -0.08 0.0"/> - <volume_morph - name="LEFT_PEC" - scale="0.0367 0.0367 0.016" - pos="0.00 -0.005 -0.013"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0367 0.0367 0.016" - pos="0.00 0.005 -0.013"/> - <volume_morph - name="BELLY" - scale="0.09 0.08 0.07" - pos="0 0 -0.05"/> - <volume_morph - name="L_CLAVICLE" - scale="0.0 0.0 0.015"/> - <volume_morph - name="L_UPPER_ARM" - scale="0.02 0.0 0.02" - pos="0.0 0.0 -0.02"/> - <volume_morph - name="L_LOWER_ARM" - scale="0.01 0.0 0.01" - pos="0.0 0.0 -0.01"/> - <volume_morph - name="R_CLAVICLE" - scale="0.0 0.0 0.015"/> - <volume_morph - name="R_UPPER_ARM" - scale="0.02 0.0 0.02" - pos="0.0 0.0 -0.02"/> - <volume_morph - name="R_LOWER_ARM" - scale="0.01 0.0 0.01" - pos="0.0 0.0 -0.01"/> - <volume_morph - name="NECK" - scale="0.015 0.01 0.0"/> - <volume_morph - name="HEAD" - scale="0.0 0.0 0.01" - pos="0 0 -0.01"/> - </param_morph> + value_max="1"> + <param_morph /> </param> <param - id="507" - group="0" - sex="female" - name="Breast_Gravity" - label="Breast Buoyancy" - wearable="shape" - edit_group="shape_torso" - edit_group_order="7" - label_min="Less Gravity" - label_max="More Gravity" - value_default="0" - value_min="-1.5" - value_max="2" - camera_elevation=".3" - camera_distance=".8"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.004 0.0 -0.01"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.004 0.0 -0.01"/> - </param_morph> - </param> - - <param - id="628" + id="59" group="1" - name="Displace_Loose_Upperbody" - label="Shirt Fit" - wearable="shirt" - edit_group="driven" - clothing_morph="true" + name="Blink_Right" value_min="0" - value_max="1" - value_default="0"> + value_max="1"> <param_morph /> </param> + <!-- + #end morph targets + --> + </mesh> + + <mesh + type="headMesh" + lod="1" + file_name="avatar_head_1.llm" + min_pixel_width="160" + reference="avatar_head.llm"> + </mesh> + + <mesh + type="headMesh" + lod="2" + file_name="avatar_head_2.llm" + min_pixel_width="80" + reference="avatar_head.llm"> + </mesh> + + <mesh + type="headMesh" + lod="3" + file_name="avatar_head_3.llm" + min_pixel_width="40" + reference="avatar_head.llm"> + </mesh> + + <mesh + type="headMesh" + lod="4" + file_name="avatar_head_4.llm" + min_pixel_width="0" + reference="avatar_head.llm"> + </mesh> + + <mesh + type="eyelashMesh" + lod="0" + file_name="avatar_eyelashes.llm" + min_pixel_width="320"> <param - id="840" - group="0" - name="Shirtsleeve_flair" - label="Sleeve Looseness" - show_simple="true" - wearable="shirt" - edit_group="shirt" - edit_group_order="6" - clothing_morph="true" - label_min="Tight Sleeves" - label_max="Loose Sleeves" - value_min="0" - value_max="1.5" - camera_distance="1.8" - camera_angle="30" - camera_elevation="-.3"> + shared="1" + id="660" + group="1" + name="Shear_Head" + wearable="shape" + label="Shear Face" + edit_group="shape_head" + label_min="Shear Left" + label_max="Shear Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> <param_morph /> </param> <param - id="855" + shared="1" + id="770" group="1" - name="Love_Handles" + name="Elongate_Head" wearable="shape" - edit_group="driven" - value_default="0" + label="Shear Face" + edit_group="shape_head" + label_min="Flat Head" + label_max="Long Head" value_min="-1" - value_max="2"> - <param_morph> - <volume_morph - name="BELLY" - scale="0.0 0.02 0.0"/> - <volume_morph - name="LOWER_BACK" - scale="0.0 0.02 0.0"/> - <volume_morph - name="LEFT_HANDLE" - pos="0.0 0.025 0.0"/> - <volume_morph - name="RIGHT_HANDLE" - pos="0.0 -0.025 0.0"/> - </param_morph> + value_max="1" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> + <param_morph /> </param> <param - id="684" + shared="1" + id="664" group="0" - sex="female" - name="Breast_Female_Cleavage" - label="Breast Cleavage" + name="Pop_Eye" wearable="shape" - edit_group="shape_torso" + label="Eye Pop" + edit_group="shape_eyes" edit_group_order="8" - label_min="Separate" - label_max="Join" + label_min="Pop Right Eye" + label_max="Pop Left Eye" + value_min="-2" + value_max="2" value_default="0" - value_min="-.3" - value_max="1.3" - camera_elevation=".3" - camera_distance=".8"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 -0.026 0.0"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.026 0.0"/> - </param_morph> + camera_distance=".5" + camera_elevation=".04" + camera_angle="-20"> + <param_morph /> </param> - + <param - id="685" - group="0" - sex="male" - name="Chest_Male_No_Pecs" - label="Pectorals" + shared="1" + id="186" + group="1" + name="Egg_Head" + label="Egg Head" wearable="shape" - edit_group="shape_torso" - edit_group_order="5" - label_min="Big Pectorals" - label_max="Sunken Chest" - value_default="0" - value_min="-0.5" - value_max="1.1" - camera_elevation=".3" - camera_distance="1.2"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="-0.03 -0.024 -0.01"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="-0.03 0.024 -0.01"/> - </param_morph> + edit_group="shape_head" + label_min="Chin Heavy" + label_max="Forehead Heavy" + value_min="-1.3" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + <param_morph /> </param> - <!-- ############# # - other morphs (not user controlled) - ############# --> <param - id="100" + shared="1" + id="187" group="1" - name="Male_Torso" - wearable="shape" - edit_group="driven" - label_min="Male_Torso" - value_min="0" - value_max="1"> - <param_morph> - <volume_morph - name="CHEST" - scale="0.03 0.04 0.02" - pos="-0.03 0 -0.01"/> - <volume_morph - name="BELLY" - scale="0.03 0.03 0.0" - pos="-0.03 0 0.02"/> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.008 -0.03 0.01"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.008 0.03 0.01"/> - <volume_morph - name="L_CLAVICLE" - scale="0.02 0.0 0.01" - pos="-0.02 0 0"/> - <volume_morph - name="L_UPPER_ARM" - scale="0.01 0.0 0.01" - pos="0.0 0.0 -0.01"/> - <volume_morph - name="L_LOWER_ARM" - scale="0.005 0.0 0.005" - pos="0.0 0.0 -0.005"/> - <volume_morph - name="R_CLAVICLE" - scale="0.02 0.0 0.01" - pos="-0.02 0 0"/> - <volume_morph - name="R_UPPER_ARM" - scale="0.01 0.0 0.01" - pos="0.0 0.0 -0.01"/> - <volume_morph - name="R_LOWER_ARM" - scale="0.005 0.0 0.005" - pos="0.0 0.0 -0.005"/> - <volume_morph - name="NECK" - scale="0.015 0.01 0.0"/> - <volume_morph - name="HEAD" - scale="0.0 0.0 0.01" - pos="0 0 -0.01"/> - </param_morph> + name="Squash_Stretch_Head" + label="Squash/Stretch Head" + wearable="shape" + edit_group="shape_head" + label_min="Squash Head" + label_max="Stretch Head" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + <param_morph /> + </param> + + <param + shared="1" + id="194" + group="1" + name="Eye_Spread" + edit_group="shape_eyes" + label_min="Eyes Together" + label_max="Eyes Spread" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="518" + group="0" + name="Eyelashes_Long" + wearable="shape" + label="Eyelash Length" + edit_group="shape_eyes" + edit_group_order="7" + label_min="Short" + label_max="Long" + value_min="-.3" + value_max="1.5" + camera_elevation=".1" + camera_distance=".30" + camera_angle="-20"> + <param_morph /> + </param> + + <param + shared="1" + id="686" + group="1" + name="Head_Eyes_Big" + wearable="shape" + label="Eye Size" + edit_group="shape_eyes" + label_min="Beady Eyes" + label_max="Anime Eyes" + value_min="-2" + value_max="2" + show_simple="true" + value_default="0"> + <param_morph /> + </param> + + <param + shared="1" + id="767" + group="1" + name="Bug_Eyed_Head" + wearable="shape" + label="Eye Depth" + edit_group="shape_eyes" + edit_group_order="4.5" + label_min="Sunken Eyes" + label_max="Bug Eyes" + value_min="-2" + value_max="2" + value_default="0"> + <param_morph /> </param> <!-- ############## - # animatable morphs + # Facial Expression morphs ############## --> <param - id="101" + shared="1" + id="301" group="1" - name="Hands_Relaxed" + name="Express_Tongue_Out" value_min="0" value_max="1"> <param_morph /> </param> <param - id="102" + shared="1" + id="302" group="1" - name="Hands_Point" + name="Express_Surprise_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="103" + shared="1" + id="303" group="1" - name="Hands_Fist" + name="Express_Wink_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="666" + shared="1" + id="304" group="1" - name="Hands_Relaxed_L" + name="Express_Embarrassed_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="667" + shared="1" + id="305" group="1" - name="Hands_Point_L" + name="Express_Shrug_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="668" + shared="1" + id="306" group="1" - name="Hands_Fist_L" + name="Express_Kiss" value_min="0" value_max="1"> <param_morph /> </param> <param - id="669" + shared="1" + id="307" group="1" - name="Hands_Relaxed_R" + name="Express_Bored_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="670" + shared="1" + id="308" group="1" - name="Hands_Point_R" + name="Express_Repulsed_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="671" + shared="1" + id="309" group="1" - name="Hands_Fist_R" + name="Express_Disdain" value_min="0" value_max="1"> <param_morph /> </param> <param - id="672" + shared="1" + id="310" group="1" - name="Hands_Typing" + name="Express_Afraid_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="766" + shared="1" + id="312" group="1" - name="Hands_Salute_R" + name="Express_Cry_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="791" + shared="1" + id="313" group="1" - name="Hands_Peace_R" + name="Express_Sad_Emote" value_min="0" value_max="1"> <param_morph /> </param> <param - id="792" + shared="1" + id="314" group="1" - name="Hands_Spread_R" + name="Express_Anger_Emote" value_min="0" value_max="1"> <param_morph /> </param> - <!-- - ############# - # physics morphs (not user controlled) - ############# - --> <param - id="1200" + shared="1" + id="315" group="1" - sex="female" - name="Breast_Physics_UpDown_Driven" - wearable="physics" - edit_group="driven" - value_default="0" - value_min="-3" - value_max="3"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.0 -0.01"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.0 -0.01"/> - </param_morph> + name="Express_Frown" + value_min="0" + value_max="1"> + <param_morph /> </param> <param - id="1201" + shared="1" + id="316" group="1" - sex="female" - name="Breast_Physics_InOut_Driven" - wearable="physics" - edit_group="driven" - value_default="0" - value_min="-1.25" - value_max="1.25"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 -0.026 0.0"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.026 -0.0"/> - </param_morph> + name="Express_Laugh_Emote" + value_min="0" + value_max="1"> + <param_morph /> </param> <param - id="1204" + shared="1" + id="317" group="1" - name="Belly_Physics_Torso_UpDown_Driven" - wearable="physics" - edit_group="driven" - value_default="0" - value_min="-1" + name="Express_Toothsmile" + value_min="0" value_max="1"> - <param_morph> - <volume_morph - name="BELLY" - scale="0.0 0.0 0.0" - pos="0.0 0.0 0.05"/> - </param_morph> + <param_morph /> </param> <param - id="1207" + shared="1" + id="318" group="1" - name="Breast_Physics_LeftRight_Driven" - wearable="physics" - edit_group="driven" - value_default="0" - value_min="-2" - value_max="2"> - <param_morph> - <volume_morph - name="LEFT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.03 0.0"/> - <volume_morph - name="RIGHT_PEC" - scale="0.0 0.0 0.0" - pos="0.0 0.03 0.0"/> - </param_morph> + name="Express_Smile" + value_min="0" + value_max="1"> + <param_morph /> </param> <!-- - #end morph targets - --> - - </mesh> - - <mesh - type="upperBodyMesh" - lod="1" - file_name="avatar_upper_body_1.llm" - min_pixel_width="160" - reference="avatar_upper_body.llm"> - </mesh> - - <mesh - type="upperBodyMesh" - lod="2" - file_name="avatar_upper_body_2.llm" - min_pixel_width="80" - reference="avatar_upper_body.llm"> - </mesh> + ############## + # other morphs (not user controlled) + ############## + --> + <param + shared="1" + id="41" + group="1" + name="Old" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <mesh - type="upperBodyMesh" - lod="3" - file_name="avatar_upper_body_3.llm" - min_pixel_width="40" - reference="avatar_upper_body.llm"> - </mesh> + <!-- + ############## + # animatable morphs + ############## + --> + <param + shared="1" + id="58" + group="1" + name="Blink_Left" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <mesh - type="upperBodyMesh" - lod="4" - file_name="avatar_upper_body_4.llm" - min_pixel_width="0" - reference="avatar_upper_body.llm"> + <param + shared="1" + id="59" + group="1" + name="Blink_Right" + value_min="0" + value_max="1"> + <param_morph /> + </param> </mesh> <!-- - #upperBodyMesh2 = - #upperBodyMesh3 = + #headMesh2 = + #headMesh3 = --> <mesh - type="lowerBodyMesh" + type="upperBodyMesh" lod="0" - file_name="avatar_lower_body.llm" + file_name="avatar_upper_body.llm" min_pixel_width="320"> <!-- #begin morph targets @@ -4611,315 +6440,412 @@ ############# --> <param - id="156" + id="104" group="1" - name="Big_Belly_Legs" + name="Big_Belly_Torso" wearable="shape" edit_group="driven" value_min="0" value_max="1"> - <param_morph /> + <param_morph> + <volume_morph + name="BELLY" + scale="0.075 0.04 0.03" + pos="0.07 0 -0.07"/> + <volume_morph + name="PELVIS" + scale="0.075 0.04 0.03" + pos="0.07 0 -0.02"/> + </param_morph> </param> - <param - id="151" + id="626" + sex="female" group="1" - name="Big_Butt_Legs" - label="Butt Size" + name="Big_Chest" + label="Chest Size" wearable="shape" - edit_group="shape_legs" - label_min="Regular" + edit_group="shape_torso" + label_min="Small" label_max="Large" value_min="0" - value_max="1"> + value_max="1" + camera_elevation=".1" + camera_distance="1" + camera_angle="15"> <param_morph> <volume_morph - name="PELVIS" - scale="0.03 0.0 0.02" - pos="-0.03 0 -0.025"/> - </param_morph> + name="LEFT_PEC" + scale="0.0273 0.0273 0.0273" + pos="0.038 0.024 -0.016"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0273 0.0273 0.0273" + pos="0.038 -0.024 -0.016"/> + </param_morph> </param> <param - id="794" + id="627" + sex="female" group="1" - name="Small_Butt" - label="Butt Size" + name="Small_Chest" + label="Chest Size" wearable="shape" - edit_group="shape_legs" - label_min="Regular" + edit_group="shape_torso" + label_min="Large" label_max="Small" value_min="0" - value_max="1"> + value_max="1" + camera_elevation="0" + camera_distance=".28"> <param_morph> <volume_morph - name="PELVIS" - scale="-0.01 0.0 0.0" - pos="0.01 0 0.0"/> + name="LEFT_PEC" + scale="-0.05 0.0 0.0" + pos="-0.01 -0.01 -0.02"/> <volume_morph - name="BUTT" - scale="0.0 0.0886 0.0" - pos="0.03 0 0.0"/> - </param_morph> + name="RIGHT_PEC" + scale="-0.05 0.0 0.0" + pos="-0.01 -0.01 -0.02"/> + </param_morph> </param> <param - id="152" + id="843" + sex="female" group="1" - name="Muscular_Legs" - label="Leg Muscles" - show_simple="true" + name="No_Chest" + label="Chest Size" wearable="shape" - edit_group="shape_legs" - label_min="Regular Muscles" - label_max="More Muscles" + edit_group="shape_torso" + label_min="Some" + label_max="None" value_min="0" - value_max="1.5" - camera_distance="1.3" - camera_elevation="-.5"> + value_max="1" + camera_elevation="0" + camera_distance=".28"> <param_morph> <volume_morph - name="L_UPPER_LEG" - scale="0.015 0.015 0.0" - pos="0.0 0 0.0"/> - <volume_morph - name="L_LOWER_LEG" - scale="0.01 0.01 0.0" - pos="0.0 0 0.0"/> + name="LEFT_PEC" + scale="-0.051 0.0 0.0" + pos="-0.02 -0.01 -0.03"/> <volume_morph - name="R_UPPER_LEG" - scale="0.015 0.015 0.0" - pos="0.0 0 0.0"/> - <volume_morph - name="R_LOWER_LEG" - scale="0.01 0.01 0.0" - pos="0.0 0 0.0"/> - </param_morph> + name="RIGHT_PEC" + scale="-0.051 0.0 0.0" + pos="-0.02 -0.01 -0.03"/> + </param_morph> </param> <param - id="651" + id="106" group="1" - name="Scrawny_Legs" - label="Scrawny Leg" + name="Muscular_Torso" + label="Torso Muscles" + sex="male" + show_simple="true" wearable="shape" - edit_group="shape_legs" - label_min="Regular Muscles" - label_max="Less Muscles" + edit_group="shape_torso" + label_min="Regular" + label_max="Muscular" value_min="0" - value_max="1.5" - camera_distance="1.3" - camera_elevation="-.5"> + value_max="1.4" + camera_elevation=".3" + camera_distance="1.2"> <param_morph> <volume_morph - name="L_UPPER_LEG" - scale="-0.03 -0.03 0.0" - pos="0.0 0 0.0"/> + name="L_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> <volume_morph - name="L_LOWER_LEG" - scale="-0.015 -0.015 0.0" - pos="0.0 0 0.0"/> + name="L_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> <volume_morph - name="R_UPPER_LEG" - scale="-0.03 -0.03 0.0" - pos="0.0 0 0.0"/> + name="L_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> <volume_morph - name="R_LOWER_LEG" - scale="-0.015 -0.015 0.0" - pos="0.0 0 0.0"/> + 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="853" - group="1" - name="Bowed_Legs" - label="Knee Angle" + id="107" + group="1" + name="Muscular_Torso" + label="Torso Muscles" + sex="female" + show_simple="true" wearable="shape" - value_min="-1" - value_max="1"> + 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_UPPER_LEG" - pos="0.0 0.03 0.0"/> + name="L_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> <volume_morph - name="L_LOWER_LEG" - pos="0.0 0.03 0.0"/> + name="L_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> <volume_morph - name="R_UPPER_LEG" - pos="0.0 -0.03 0.0"/> + name="L_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> <volume_morph - name="R_LOWER_LEG" - pos="0.0 -0.03 0.0"/> + 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="500" + id="648" group="1" - name="Shoe_Heel_Height" - label="Heel Height" - wearable="shoes" - edit_group="shoes" - label_min="Low Heels" - label_max="High Heels" + sex="female" + name="Scrawny_Torso" + label="Torso Muscles" + show_simple="true" + wearable="shape" + edit_group="shape_torso" + label_min="Regular" + label_max="Scrawny" value_min="0" - value_max="1" - camera_distance="1.5" - camera_elevation="-.5"> - <param_morph /> + value_max="1.3" + camera_elevation=".3" + camera_distance="1.2"> + <param_morph> + <volume_morph + name="BELLY" + scale="0.0 -0.01 0.0" + pos="0.0 0.0 0"/> + <volume_morph + name="UPPER_BACK" + scale="-0.01 -0.01 0.0" + pos="0.0 0.0 0"/> + <volume_morph + name="CHEST" + scale="-0.01 -0.01 0.0" + pos="0.01 0.0 0"/> + <volume_morph + name="L_CLAVICLE" + scale="0.0 -0.03 -0.005" + pos="0.0 0 -0.005"/> + <volume_morph + name="L_UPPER_ARM" + scale="-0.01 -0.01 -0.02" + pos="0 0 0"/> + <volume_morph + name="L_LOWER_ARM" + scale="-0.005 0.0 -0.01" + pos="-0.005 0 0"/> + <volume_morph + name="R_CLAVICLE" + scale="0.0 -0.03 -0.005" + pos="0.0 0 -0.005"/> + <volume_morph + name="R_UPPER_ARM" + scale="-0.01 -0.01 -0.02" + pos="0 0 0"/> + <volume_morph + name="R_LOWER_ARM" + scale="-0.005 0.0 -0.01" + pos="-0.005 0 0"/> + </param_morph> </param> <param - id="501" + id="677" group="1" - name="Shoe_Platform_Height" - label="Platform Height" - wearable="shoes" - edit_group="shoes" - label_min="Low Platforms" - label_max="High Platforms" + sex="male" + name="Scrawny_Torso_Male" + label="Torso Scrawny" + wearable="shape" + edit_group="shape_torso" + label_min="Regular" + label_max="Scrawny" value_min="0" - value_max="1" - camera_distance="1.5" - camera_elevation="-.5"> - <param_morph /> - </param> - - <param - id="508" - group="0" - name="Shoe_Platform_Width" - label="Platform Width" - wearable="shoes" - edit_group="shoes" - edit_group_order="7" - label_min="Narrow" - label_max="Wide" - value_min="-1" - value_max="2" - camera_angle="15" - camera_distance="1.5" - camera_elevation="-1"> - <param_morph /> + value_max="1.3" + camera_elevation=".3" + camera_distance="1.2"> + <param_morph> + <volume_morph + name="BELLY" + scale="-0.01 -0.01 0.0" + pos="0.01 0.0 0"/> + <volume_morph + name="UPPER_BACK" + scale="-0.01 -0.01 0.0" + pos="0.0 0.0 0"/> + <volume_morph + name="CHEST" + scale="-0.02 -0.02 0.0" + pos="0.01 0.0 0"/> + <volume_morph + name="L_CLAVICLE" + scale="0.0 -0.03 -0.005" + pos="0.0 0 -0.005"/> + <volume_morph + name="L_UPPER_ARM" + scale="-0.01 -0.01 -0.02" + pos="0 0 0"/> + <volume_morph + name="L_LOWER_ARM" + scale="-0.005 0.0 -0.01" + pos="-0.005 0 0"/> + <volume_morph + name="R_CLAVICLE" + scale="0.0 -0.03 -0.005" + pos="0.0 0 -0.005"/> + <volume_morph + name="R_UPPER_ARM" + scale="-0.01 -0.01 -0.02" + pos="0 0 0"/> + <volume_morph + name="R_LOWER_ARM" + scale="-0.005 0.0 -0.01" + pos="-0.005 0 0"/> + </param_morph> </param> <param - id="509" + id="634" group="1" - name="Shoe_Heel_Point" - label="Heel Shape" - wearable="shoes" - edit_group="shoes" - label_min="Default Heels" - label_max="Pointy Heels" - value_min="0" - value_max="1" - camera_distance="1.3" - camera_elevation="-.5"> - <param_morph /> - </param> - - <param - id="510" - group="1" - name="Shoe_Heel_Thick" - label="Heel Shape" - wearable="shoes" - edit_group="shoes" - label_min="default Heels" - label_max="Thick Heels" - value_min="0" - value_max="1" - camera_distance="1.3" - camera_elevation="-.5"> - <param_morph /> - </param> - - <param - id="511" - group="1" - name="Shoe_Toe_Point" - label="Toe Shape" - wearable="shoes" - edit_group="shoes" - label_min="Default Toe" - label_max="Pointy Toe" - value_min="0" - value_max="1" - camera_distance="1.3" - camera_elevation="-.5"> - <param_morph /> - </param> - - <param - id="512" - group="1" - name="Shoe_Toe_Square" - label="Toe Shape" - wearable="shoes" - edit_group="shoes" - label_min="Default Toe" - label_max="Square Toe" + name="Fat_Torso" + label="Fat Torso" + wearable="shape" + edit_group="shape_body" + label_min="skinny" + label_max="fat" value_min="0" value_max="1" - camera_distance="1.5" - camera_elevation="-.5"> - <param_morph /> - </param> - - <param - id="654" - group="0" - name="Shoe_Toe_Thick" - label="Toe Thickness" - wearable="shoes" - edit_group="shoes" - edit_group_order="5" - label_min="Flat Toe" - label_max="Thick Toe" - value_min="0" - value_max="2" - camera_angle="15" - camera_distance="1.5" - camera_elevation="-1"> - <param_morph /> + camera_elevation=".3"> + <param_morph> + <volume_morph + name="CHEST" + scale="0.02 0.03 0.03" + pos="0 0 -0.03"/> + <volume_morph + name="PELVIS" + scale="0.02 0.03 0.03" + pos="0 0 -0.03"/> + <volume_morph + name="UPPER_BACK" + scale="0.01 0.03 0.0" + pos="-0.03 0 0"/> + <volume_morph + name="LOWER_BACK" + scale="0.04 0.06 0.0" + pos="-0.06 0 0"/> + <volume_morph + name="LEFT_HANDLE" + pos="0.0 0.08 0.0"/> + <volume_morph + name="RIGHT_HANDLE" + pos="0.0 -0.08 0.0"/> + <volume_morph + name="LEFT_PEC" + scale="0.0367 0.0367 0.016" + pos="0.00 -0.005 -0.013"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0367 0.0367 0.016" + pos="0.00 0.005 -0.013"/> + <volume_morph + name="BELLY" + scale="0.09 0.08 0.07" + pos="0 0 -0.05"/> + <volume_morph + name="L_CLAVICLE" + scale="0.0 0.0 0.015"/> + <volume_morph + name="L_UPPER_ARM" + scale="0.02 0.0 0.02" + pos="0.0 0.0 -0.02"/> + <volume_morph + name="L_LOWER_ARM" + scale="0.01 0.0 0.01" + pos="0.0 0.0 -0.01"/> + <volume_morph + name="R_CLAVICLE" + scale="0.0 0.0 0.015"/> + <volume_morph + name="R_UPPER_ARM" + scale="0.02 0.0 0.02" + pos="0.0 0.0 -0.02"/> + <volume_morph + name="R_LOWER_ARM" + scale="0.01 0.0 0.01" + pos="0.0 0.0 -0.01"/> + <volume_morph + name="NECK" + scale="0.015 0.01 0.0"/> + <volume_morph + name="HEAD" + scale="0.0 0.0 0.01" + pos="0 0 -0.01"/> + </param_morph> </param> <param - id="515" + id="507" group="0" - name="Foot_Size" - label="Foot Size" + sex="female" + name="Breast_Gravity" + label="Breast Buoyancy" wearable="shape" - edit_group="shape_legs" - edit_group_order="6" - label_min="Small" - label_max="Big" - value_min="-1" - value_max="3" - camera_angle="45" - camera_distance="1.1" - camera_elevation="-1"> + edit_group="shape_torso" + edit_group_order="7" + label_min="Less Gravity" + label_max="More Gravity" + value_default="0" + value_min="-1.5" + value_max="2" + camera_elevation=".3" + camera_distance=".8"> <param_morph> <volume_morph - name="L_FOOT" - scale="0.02 0.01 0.0" - pos="0.01 0 0"/> + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.004 0.0 -0.01"/> <volume_morph - name="R_FOOT" - scale="0.02 0.01 0.0" - pos="0.01 0 0"/> + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.004 0.0 -0.01"/> </param_morph> </param> - + <param - id="516" + id="628" group="1" - name="Displace_Loose_Lowerbody" - label="Pants Fit" - wearable="pants" + name="Displace_Loose_Upperbody" + label="Shirt Fit" + wearable="shirt" edit_group="driven" clothing_morph="true" value_min="0" @@ -4929,17 +6855,17 @@ </param> <param - id="625" + id="840" group="0" - name="Leg_Pantflair" - label="Cuff Flare" + name="Shirtsleeve_flair" + label="Sleeve Looseness" show_simple="true" - wearable="pants" - edit_group="pants" - edit_group_order="3" + wearable="shirt" + edit_group="shirt" + edit_group_order="6" clothing_morph="true" - label_min="Tight Cuffs" - label_max="Flared Cuffs" + label_min="Tight Sleeves" + label_max="Loose Sleeves" value_min="0" value_max="1.5" camera_distance="1.8" @@ -4949,2856 +6875,2906 @@ </param> <param - id="793" + id="855" group="1" - name="Leg_Longcuffs" - label="Longcuffs" - wearable="pants" + name="Love_Handles" + wearable="shape" edit_group="driven" - clothing_morph="true" - value_min="0" - value_max="3" - value_default="0"> - <param_morph /> + value_default="0" + value_min="-1" + value_max="2"> + <param_morph> + <volume_morph + name="BELLY" + scale="0.0 0.02 0.0"/> + <volume_morph + name="LOWER_BACK" + scale="0.0 0.02 0.0"/> + <volume_morph + name="LEFT_HANDLE" + pos="0.0 0.025 0.0"/> + <volume_morph + name="RIGHT_HANDLE" + pos="0.0 -0.025 0.0"/> + </param_morph> </param> <param - id="638" + id="684" group="0" - name="Low_Crotch" - label="Pants Crotch" - wearable="pants" - clothing_morph="true" - edit_group="pants" - edit_group_order="4" - label_min="High and Tight" - label_max="Low and Loose" - value_min="0" - value_max="1.3" - camera_distance="1.2" - camera_angle="-20" - camera_elevation="-.3"> - <param_morph /> - </param> - - <param - id="635" - group="1" - name="Fat_Legs" - label="Fat Torso" + sex="female" + name="Breast_Female_Cleavage" + label="Breast Cleavage" wearable="shape" - edit_group="shape_body" - label_min="skinny" - label_max="fat" - value_min="0" - value_max="1"> + edit_group="shape_torso" + edit_group_order="8" + label_min="Separate" + label_max="Join" + value_default="0" + value_min="-.3" + value_max="1.3" + camera_elevation=".3" + camera_distance=".8"> <param_morph> <volume_morph - name="PELVIS" - scale="0.03 0.06 0.0"/> - <volume_morph - name="R_UPPER_LEG" - scale="0.02 0.02 0.0" - pos="0.0 -0.02 0.0"/> + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 -0.026 0.0"/> <volume_morph - name="R_LOWER_LEG" - scale="0.01 0.01 0.0"/> + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.026 0.0"/> + </param_morph> + </param> + + <param + id="685" + group="0" + sex="male" + name="Chest_Male_No_Pecs" + label="Pectorals" + wearable="shape" + edit_group="shape_torso" + edit_group_order="5" + label_min="Big Pectorals" + label_max="Sunken Chest" + value_default="0" + value_min="-0.5" + value_max="1.1" + camera_elevation=".3" + camera_distance="1.2"> + <param_morph> <volume_morph - name="L_UPPER_LEG" - scale="0.02 0.02 0.0" - pos="0.0 0.02 0.0"/> + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="-0.03 -0.024 -0.01"/> <volume_morph - name="L_LOWER_LEG" - scale="0.01 0.01 0.0"/> + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="-0.03 0.024 -0.01"/> </param_morph> </param> + <!-- ############# # + other morphs (not user controlled) + ############# --> <param - id="854" + id="100" group="1" - name="Saddlebags" - wearable="shape" + name="Male_Torso" + wearable="shape" edit_group="driven" - value_min="-.5" - value_max="3"> + label_min="Male_Torso" + value_min="0" + value_max="1"> <param_morph> <volume_morph - name="PELVIS" - scale="0.0 0.025 0.0"/> + name="CHEST" + scale="0.03 0.04 0.02" + pos="-0.03 0 -0.01"/> + <volume_morph + name="BELLY" + scale="0.03 0.03 0.0" + pos="-0.03 0 0.02"/> + <volume_morph + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.008 -0.03 0.01"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.008 0.03 0.01"/> + <volume_morph + name="L_CLAVICLE" + scale="0.02 0.0 0.01" + pos="-0.02 0 0"/> + <volume_morph + name="L_UPPER_ARM" + scale="0.01 0.0 0.01" + pos="0.0 0.0 -0.01"/> + <volume_morph + name="L_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.0 0.0 -0.005"/> + <volume_morph + name="R_CLAVICLE" + scale="0.02 0.0 0.01" + pos="-0.02 0 0"/> + <volume_morph + name="R_UPPER_ARM" + scale="0.01 0.0 0.01" + pos="0.0 0.0 -0.01"/> + <volume_morph + name="R_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.0 0.0 -0.005"/> + <volume_morph + name="NECK" + scale="0.015 0.01 0.0"/> + <volume_morph + name="HEAD" + scale="0.0 0.0 0.01" + pos="0 0 -0.01"/> </param_morph> - </param> + <!-- + ############## + # animatable morphs + ############## + --> <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"> + id="101" + group="1" + name="Hands_Relaxed" + value_min="0" + value_max="1"> <param_morph /> </param> - <!-- - ############# - # other morphs (not user controlled) - ############# - --> <param - id="153" + id="102" group="1" - name="Male_Legs" - wearable="shape" - edit_group="driven" + name="Hands_Point" value_min="0" value_max="1"> <param_morph /> </param> - <!-- - ############# - # physics morphs (not user controlled) - ############# - --> <param - id="1202" + id="103" group="1" - name="Belly_Physics_Legs_UpDown_Driven" - wearable="physics" - cross_wearable="true" - edit_group="driven" - value_min="-1" + name="Hands_Fist" + value_min="0" value_max="1"> <param_morph /> </param> - <param - id="1205" + id="666" group="1" - name="Butt_Physics_UpDown_Driven" - wearable="physics" - cross_wearable="true" - edit_group="driven" - value_default="0" - value_min="-1" + name="Hands_Relaxed_L" + value_min="0" value_max="1"> - <param_morph> - <volume_morph - name="BUTT" - pos="0.0 0.0 0.05"/> - </param_morph> + <param_morph /> </param> <param - id="1206" + id="667" group="1" - name="Butt_Physics_LeftRight_Driven" - wearable="physics" - cross_wearable="true" - edit_group="driven" - value_default="0" - value_min="-1" + name="Hands_Point_L" + value_min="0" value_max="1"> - <param_morph> - <volume_morph - name="BUTT" - pos="0.0 0.05 0.0"/> - </param_morph> + <param_morph /> </param> - <!-- - #end morph targets - --> + <param + id="668" + group="1" + name="Hands_Fist_L" + value_min="0" + value_max="1"> + <param_morph /> + </param> - </mesh> + <param + id="669" + group="1" + name="Hands_Relaxed_R" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <mesh - type="lowerBodyMesh" - lod="1" - file_name="avatar_lower_body_1.llm" - min_pixel_width="160" - reference="avatar_lower_body.llm"> - </mesh> + <param + id="670" + group="1" + name="Hands_Point_R" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <mesh - type="lowerBodyMesh" - lod="2" - file_name="avatar_lower_body_2.llm" - min_pixel_width="80" - reference="avatar_lower_body.llm"> - </mesh> + <param + id="671" + group="1" + name="Hands_Fist_R" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <mesh - type="lowerBodyMesh" - lod="3" - file_name="avatar_lower_body_3.llm" - min_pixel_width="40" - reference="avatar_lower_body.llm"> - </mesh> - - <mesh - type="lowerBodyMesh" - lod="4" - file_name="avatar_lower_body_4.llm" - min_pixel_width="0" - reference="avatar_lower_body.llm"> - </mesh> - - <!-- - #lowerBodyMesh2 = - #lowerBodyMesh3 = - --> - <!-- - #eyeLidLeftMesh = - --> - <mesh - type="eyeBallLeftMesh" - lod="0" - file_name="avatar_eye.llm" - min_pixel_width="320"> - <!-- begin morph_params --> <param - id="679" + id="672" group="1" - name="Eyeball_Size" - label="Eyeball Size" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".10"> + name="Hands_Typing" + value_min="0" + value_max="1"> <param_morph /> </param> <param - id="687" + id="766" group="1" - name="Eyeball_Size" - label="Big Eyeball" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".25"> + name="Hands_Salute_R" + value_min="0" + value_max="1"> <param_morph /> </param> - </mesh> - <mesh - type="eyeBallLeftMesh" - lod="1" - file_name="avatar_eye_1.llm" - min_pixel_width="80"> - <!-- begin morph_params --> <param - id="694" + id="791" group="1" - name="Eyeball_Size" - label="Eyeball Size" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".10"> + name="Hands_Peace_R" + value_min="0" + value_max="1"> <param_morph /> </param> <param - id="695" + id="792" group="1" - name="Eyeball_Size" - label="Big Eyeball" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".25"> + name="Hands_Spread_R" + value_min="0" + value_max="1"> <param_morph /> </param> - </mesh> - <!-- - #eyeLidRightMesh = - --> - <mesh - type="eyeBallRightMesh" - lod="0" - file_name="avatar_eye.llm" - min_pixel_width="320"> - <!-- begin morph_params --> + <!-- + ############# + # physics morphs (not user controlled) + ############# + --> <param - id="680" + id="1200" group="1" - name="Eyeball_Size" - label="Eyeball Size" - wearable="shape" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".10"> - <param_morph /> + sex="female" + name="Breast_Physics_UpDown_Driven" + wearable="physics" + edit_group="driven" + value_default="0" + value_min="-3" + value_max="3"> + <param_morph> + <volume_morph + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.0 -0.01"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.0 -0.01"/> + </param_morph> </param> <param - id="688" + id="1201" group="1" - name="Eyeball_Size" - label="Big Eyeball" - wearable="shape" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".25"> - <param_morph /> + sex="female" + name="Breast_Physics_InOut_Driven" + wearable="physics" + edit_group="driven" + value_default="0" + value_min="-1.25" + value_max="1.25"> + <param_morph> + <volume_morph + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 -0.026 0.0"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.026 -0.0"/> + </param_morph> </param> - </mesh> - <mesh - type="eyeBallRightMesh" - lod="1" - file_name="avatar_eye_1.llm" - min_pixel_width="80"> - <!-- begin morph_params --> <param - id="681" + id="1204" group="1" - name="Eyeball_Size" - label="Eyeball Size" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".10"> - <param_morph /> + name="Belly_Physics_Torso_UpDown_Driven" + wearable="physics" + edit_group="driven" + value_default="0" + value_min="-1" + value_max="1"> + <param_morph> + <volume_morph + name="BELLY" + scale="0.0 0.0 0.0" + pos="0.0 0.0 0.05"/> + </param_morph> </param> <param - id="691" + id="1207" group="1" - name="Eyeball_Size" - label="Big Eyeball" - wearable="shape" - edit_group="shape_eyes" - label_min="small eye" - label_max="big eye" - value_min="-.25" - value_max=".25"> - <param_morph /> + name="Breast_Physics_LeftRight_Driven" + wearable="physics" + edit_group="driven" + value_default="0" + value_min="-2" + value_max="2"> + <param_morph> + <volume_morph + name="LEFT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.03 0.0"/> + <volume_morph + name="RIGHT_PEC" + scale="0.0 0.0 0.0" + pos="0.0 0.03 0.0"/> + </param_morph> </param> + + <!-- + #end morph targets + --> + </mesh> <mesh - type="skirtMesh" + type="upperBodyMesh" + lod="1" + file_name="avatar_upper_body_1.llm" + min_pixel_width="160" + reference="avatar_upper_body.llm"> + </mesh> + + <mesh + type="upperBodyMesh" + lod="2" + file_name="avatar_upper_body_2.llm" + min_pixel_width="80" + reference="avatar_upper_body.llm"> + </mesh> + + <mesh + type="upperBodyMesh" + lod="3" + file_name="avatar_upper_body_3.llm" + min_pixel_width="40" + reference="avatar_upper_body.llm"> + </mesh> + + <mesh + type="upperBodyMesh" + lod="4" + file_name="avatar_upper_body_4.llm" + min_pixel_width="0" + reference="avatar_upper_body.llm"> + </mesh> + + <!-- + #upperBodyMesh2 = + #upperBodyMesh3 = + --> + <mesh + type="lowerBodyMesh" lod="0" - file_name="avatar_skirt.llm" + file_name="avatar_lower_body.llm" min_pixel_width="320"> + <!-- + #begin morph targets + ############# + # tweakable morphs + ############# + --> <param - id="845" + id="156" group="1" - name="skirt_poofy" - label="poofy skirt" - clothing_morph="true" - wearable="skirt" - edit_group="skirt" - label_min="less poofy" - label_max="more poofy" + name="Big_Belly_Legs" + wearable="shape" + edit_group="driven" value_min="0" - value_max="1.5"> + value_max="1"> <param_morph /> </param> + <param - id="846" + id="151" group="1" - name="skirt_loose" - label="loose skirt" - clothing_morph="true" - wearable="skirt" - edit_group="skirt" - label_min="form fitting" - label_max="loose" + name="Big_Butt_Legs" + label="Butt Size" + wearable="shape" + edit_group="shape_legs" + label_min="Regular" + label_max="Large" value_min="0" value_max="1"> - <param_morph /> + <param_morph> + <volume_morph + name="PELVIS" + scale="0.03 0.0 0.02" + pos="-0.03 0 -0.025"/> + </param_morph> </param> <param - id="866" + id="794" group="1" - name="skirt_tight" - label="tight skirt" - clothing_morph="true" - wearable="skirt" - edit_group="skirt" - label_min="form fitting" - label_max="loose" + name="Small_Butt" + label="Butt Size" + wearable="shape" + edit_group="shape_legs" + label_min="Regular" + label_max="Small" value_min="0" value_max="1"> - <param_morph /> + <param_morph> + <volume_morph + name="PELVIS" + scale="-0.01 0.0 0.0" + pos="0.01 0 0.0"/> + <volume_morph + name="BUTT" + scale="0.0 0.0886 0.0" + pos="0.03 0 0.0"/> + </param_morph> </param> <param - id="867" + id="152" group="1" - name="skirt_smallbutt" - label="tight skirt" - clothing_morph="false" - wearable="skirt" - edit_group="skirt" - cross_wearable="true" - label_min="form fitting" - label_max="loose" + name="Muscular_Legs" + label="Leg Muscles" + show_simple="true" + wearable="shape" + edit_group="shape_legs" + label_min="Regular Muscles" + label_max="More Muscles" value_min="0" - value_max="1"> - <param_morph /> + value_max="1.5" + camera_distance="1.3" + camera_elevation="-.5"> + <param_morph> + <volume_morph + name="L_UPPER_LEG" + scale="0.015 0.015 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="L_LOWER_LEG" + scale="0.01 0.01 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="R_UPPER_LEG" + scale="0.015 0.015 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="R_LOWER_LEG" + scale="0.01 0.01 0.0" + pos="0.0 0 0.0"/> + </param_morph> </param> <param - id="848" - group="0" - name="skirt_bustle" - label="bustle skirt" - clothing_morph="true" - wearable="skirt" - edit_group_order="3" - edit_group="skirt" - label_min="no bustle" - label_max="more bustle" + id="651" + group="1" + name="Scrawny_Legs" + label="Scrawny Leg" + wearable="shape" + edit_group="shape_legs" + label_min="Regular Muscles" + label_max="Less Muscles" value_min="0" - value_max="2" - value_default=".2" - camera_angle="100" + value_max="1.5" camera_distance="1.3" camera_elevation="-.5"> - <param_morph /> + <param_morph> + <volume_morph + name="L_UPPER_LEG" + scale="-0.03 -0.03 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="L_LOWER_LEG" + scale="-0.015 -0.015 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="R_UPPER_LEG" + scale="-0.03 -0.03 0.0" + pos="0.0 0 0.0"/> + <volume_morph + name="R_LOWER_LEG" + scale="-0.015 -0.015 0.0" + pos="0.0 0 0.0"/> + </param_morph> </param> <param - id="847" + id="853" group="1" - name="skirt_bowlegs" - label="legs skirt" - wearable="skirt" - edit_group="driven" - cross_wearable="true" + name="Bowed_Legs" + label="Knee Angle" + wearable="shape" value_min="-1" - value_max="1" - value_default="0"> - <param_morph /> + value_max="1"> + <param_morph> + <volume_morph + name="L_UPPER_LEG" + pos="0.0 0.03 0.0"/> + <volume_morph + name="L_LOWER_LEG" + pos="0.0 0.03 0.0"/> + <volume_morph + name="R_UPPER_LEG" + pos="0.0 -0.03 0.0"/> + <volume_morph + name="R_LOWER_LEG" + pos="0.0 -0.03 0.0"/> + </param_morph> </param> <param - id="852" + id="500" group="1" - name="skirt_bigbutt" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - label="bigbutt skirt" - label_min="less" - label_max="more" + name="Shoe_Heel_Height" + label="Heel Height" + wearable="shoes" + edit_group="shoes" + label_min="Low Heels" + label_max="High Heels" value_min="0" - value_max="1"> + value_max="1" + camera_distance="1.5" + camera_elevation="-.5"> <param_morph /> </param> <param - id="849" + id="501" group="1" - name="skirt_belly" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - label="big belly skirt" + name="Shoe_Platform_Height" + label="Platform Height" + wearable="shoes" + edit_group="shoes" + label_min="Low Platforms" + label_max="High Platforms" value_min="0" - value_max="1"> + value_max="1" + camera_distance="1.5" + camera_elevation="-.5"> <param_morph /> </param> <param - id="850" - group="1" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - name="skirt_saddlebags" - value_min="-.5" - value_max="3"> + id="508" + group="0" + name="Shoe_Platform_Width" + label="Platform Width" + wearable="shoes" + edit_group="shoes" + edit_group_order="7" + label_min="Narrow" + label_max="Wide" + value_min="-1" + value_max="2" + camera_angle="15" + camera_distance="1.5" + camera_elevation="-1"> <param_morph /> </param> <param - id="851" + id="509" group="1" - name="skirt_chubby" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - label_min="less" - label_max="more" + name="Shoe_Heel_Point" + label="Heel Shape" + wearable="shoes" + edit_group="shoes" + label_min="Default Heels" + label_max="Pointy Heels" value_min="0" value_max="1" - value_default="0"> + camera_distance="1.3" + camera_elevation="-.5"> <param_morph /> </param> <param - id="856" + id="510" group="1" - name="skirt_lovehandles" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - label_min="less" - label_max="more" - value_min="-1" - value_max="2" - value_default="0"> + name="Shoe_Heel_Thick" + label="Heel Shape" + wearable="shoes" + edit_group="shoes" + label_min="default Heels" + label_max="Thick Heels" + value_min="0" + value_max="1" + camera_distance="1.3" + camera_elevation="-.5"> <param_morph /> </param> - <!-- - ############# - # other morphs (not user controlled) - ############# - --> <param - id="857" + id="511" group="1" - name="skirt_male" - wearable="skirt" - edit_group="driven" - cross_wearable="true" - value_min="0" - value_max="1"> + name="Shoe_Toe_Point" + label="Toe Shape" + wearable="shoes" + edit_group="shoes" + label_min="Default Toe" + label_max="Pointy Toe" + value_min="0" + value_max="1" + camera_distance="1.3" + camera_elevation="-.5"> <param_morph /> </param> - <!-- - ############# - # physics morphs (not user controlled) - ############# - --> <param - id="1203" + id="512" group="1" - name="Belly_Physics_Skirt_UpDown_Driven" - wearable="physics" - cross_wearable="true" - edit_group="driven" - value_default="0" - value_min="-1" - value_max="1"> + name="Shoe_Toe_Square" + label="Toe Shape" + wearable="shoes" + edit_group="shoes" + label_min="Default Toe" + label_max="Square Toe" + value_min="0" + value_max="1" + camera_distance="1.5" + camera_elevation="-.5"> <param_morph /> </param> - </mesh> - - <mesh - type="skirtMesh" - lod="1" - file_name="avatar_skirt_1.llm" - min_pixel_width="160" - reference="avatar_skirt.llm"> - </mesh> - - <mesh - type="skirtMesh" - lod="2" - file_name="avatar_skirt_2.llm" - min_pixel_width="80" - reference="avatar_skirt.llm"> - </mesh> - - <mesh - type="skirtMesh" - lod="3" - file_name="avatar_skirt_3.llm" - min_pixel_width="40" - reference="avatar_skirt.llm"> - </mesh> - - <mesh - type="skirtMesh" - lod="4" - file_name="avatar_skirt_4.llm" - min_pixel_width="0" - reference="avatar_skirt.llm"> - </mesh> - - <!-- =========================================================== --> - <global_color - name="skin_color"> <param - id="111" + id="654" group="0" - wearable="skin" - edit_group="skin_color" - edit_group_order="1" - name="Pigment" - show_simple="true" - label_min="Light" - label_max="Dark" + name="Shoe_Toe_Thick" + label="Toe Thickness" + wearable="shoes" + edit_group="shoes" + edit_group_order="5" + label_min="Flat Toe" + label_max="Thick Toe" value_min="0" - value_max="1" - value_default=".5"> - <param_color> - <value - color="252, 215, 200, 255" /> - - <value - color="240, 177, 112, 255" /> - - <value - color="90, 40, 16, 255" /> - - <value - color="29, 9, 6, 255" /> - </param_color> + value_max="2" + camera_angle="15" + camera_distance="1.5" + camera_elevation="-1"> + <param_morph /> </param> <param - id="110" + id="515" group="0" - wearable="skin" - edit_group="skin_color" - edit_group_order="2" - name="Red Skin" - label="Ruddiness" - label_min="Pale" - label_max="Ruddy" - value_min="0" - value_max="0.1"> - <param_color - operation="blend"> - <value - color="218, 41, 37, 255" /> - </param_color> + name="Foot_Size" + label="Foot Size" + wearable="shape" + edit_group="shape_legs" + edit_group_order="6" + label_min="Small" + label_max="Big" + value_min="-1" + value_max="3" + camera_angle="45" + camera_distance="1.1" + camera_elevation="-1"> + <param_morph> + <volume_morph + name="L_FOOT" + scale="0.02 0.01 0.0" + pos="0.01 0 0"/> + <volume_morph + name="R_FOOT" + scale="0.02 0.01 0.0" + pos="0.01 0 0"/> + </param_morph> </param> <param - id="108" - group="0" - wearable="skin" - edit_group="skin_color" - edit_group_order="3" - name="Rainbow Color" - show_simple="true" - label_min="None" - label_max="Wild" + id="516" + group="1" + name="Displace_Loose_Lowerbody" + label="Pants Fit" + wearable="pants" + edit_group="driven" + clothing_morph="true" value_min="0" value_max="1" - camera_elevation=".1" - camera_distance=".5"> - <param_color> - <value - color=" 0, 0, 0, 255" /> - - <value - color="255, 0, 255, 255" /> - - <value - color="255, 0, 0, 255" /> - - <value - color="255, 255, 0, 255" /> - - <value - color=" 0, 255, 0, 255" /> - - <value - color=" 0, 255, 255, 255" /> - - <value - color=" 0, 0, 255, 255" /> - - <value - color="255, 0, 255, 255" /> - </param_color> + value_default="0"> + <param_morph /> </param> - </global_color> - <!-- =========================================================== --> - <global_color - name="hair_color"> <param - id="114" + id="625" group="0" - wearable="hair" - edit_group="hair_color" - edit_group_order="3" - name="Blonde Hair" + name="Leg_Pantflair" + label="Cuff Flare" show_simple="true" - label_min="Black" - label_max="Blonde" + wearable="pants" + edit_group="pants" + edit_group_order="3" + clothing_morph="true" + label_min="Tight Cuffs" + label_max="Flared Cuffs" value_min="0" - value_max="1" - value_default=".5" - camera_elevation=".1" - camera_distance=".5"> - <param_color> - <value - color="0, 0, 0, 255" /> + value_max="1.5" + camera_distance="1.8" + camera_angle="30" + camera_elevation="-.3"> + <param_morph /> + </param> - <value - color="22, 6, 6, 255" /> - - <value - color="29, 9, 6, 255" /> - - <value - color="45, 21, 11, 255" /> - - <value - color="78, 39, 11, 255" /> - - <value - color="90, 53, 16, 255" /> - - <value - color="136, 92, 21, 255" /> - - <value - color="150, 106, 33, 255" /> - - <value - color="198, 156, 74, 255" /> - - <value - color="233, 192, 103, 255" /> - - <value - color="238, 205, 136, 255" /> - </param_color> + <param + id="793" + group="1" + name="Leg_Longcuffs" + label="Longcuffs" + wearable="pants" + edit_group="driven" + clothing_morph="true" + value_min="0" + value_max="3" + value_default="0"> + <param_morph /> </param> <param - id="113" + id="638" group="0" - wearable="hair" - edit_group="hair_color" + name="Low_Crotch" + label="Pants Crotch" + wearable="pants" + clothing_morph="true" + edit_group="pants" edit_group_order="4" - name="Red Hair" - show_simple="true" - label_min="No Red" - label_max="Very Red" + label_min="High and Tight" + label_max="Low and Loose" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="118, 47, 19, 255" /> - </param_color> + value_max="1.3" + camera_distance="1.2" + camera_angle="-20" + camera_elevation="-.3"> + <param_morph /> </param> <param - id="115" - group="0" - wearable="hair" - edit_group="hair_color" - edit_group_order="1" - name="White Hair" - show_simple="true" - label_min="No White" - label_max="All White" + id="635" + group="1" + name="Fat_Legs" + label="Fat Torso" + wearable="shape" + edit_group="shape_body" + label_min="skinny" + label_max="fat" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="255, 255, 255, 255" /> - </param_color> + value_max="1"> + <param_morph> + <volume_morph + name="PELVIS" + scale="0.03 0.06 0.0"/> + <volume_morph + name="R_UPPER_LEG" + scale="0.02 0.02 0.0" + pos="0.0 -0.02 0.0"/> + <volume_morph + name="R_LOWER_LEG" + scale="0.01 0.01 0.0"/> + <volume_morph + name="L_UPPER_LEG" + scale="0.02 0.02 0.0" + pos="0.0 0.02 0.0"/> + <volume_morph + name="L_LOWER_LEG" + scale="0.01 0.01 0.0"/> + </param_morph> </param> <param - id="112" - group="0" - wearable="hair" - edit_group="hair_color" - edit_group_order="2" - name="Rainbow Color" - show_simple="true" - label_min="None" - label_max="Wild" - value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".5"> - <param_color> - <value - color=" 0, 0, 0, 255" /> - - <value - color="255, 0, 255, 255" /> - - <value - color="255, 0, 0, 255" /> + id="854" + group="1" + name="Saddlebags" + wearable="shape" + edit_group="driven" + value_min="-.5" + value_max="3"> + <param_morph> + <volume_morph + name="PELVIS" + scale="0.0 0.025 0.0"/> + </param_morph> - <value - color="255, 255, 0, 255" /> + </param> - <value - color=" 0, 255, 0, 255" /> + <param + id="20879" + group="1" + sex="male" + name="Male_Package" + value_min="-.5" + value_max="2"> + <param_morph /> + </param> - <value - color=" 0, 255, 255, 255" /> + <!-- + ############# + # other morphs (not user controlled) + ############# + --> + <param + id="153" + group="1" + name="Male_Legs" + wearable="shape" + edit_group="driven" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <value - color=" 0, 0, 255, 255" /> + <!-- + ############# + # physics morphs (not user controlled) + ############# + --> + <param + id="1202" + group="1" + name="Belly_Physics_Legs_UpDown_Driven" + wearable="physics" + cross_wearable="true" + edit_group="driven" + value_min="-1" + value_max="1"> + <param_morph /> + </param> - <value - color="255, 0, 255, 255" /> - </param_color> + + <param + id="1205" + group="1" + name="Butt_Physics_UpDown_Driven" + wearable="physics" + cross_wearable="true" + edit_group="driven" + value_default="0" + value_min="-1" + value_max="1"> + <param_morph> + <volume_morph + name="BUTT" + pos="0.0 0.0 0.05"/> + </param_morph> </param> - </global_color> - <!-- =========================================================== --> - <global_color - name="eye_color"> <param - id="99" - group="0" - wearable="eyes" - edit_group="eyes" - edit_group_order="1" - name="Eye Color" - show_simple="true" - label_min="Natural" - label_max="Unnatural" - value_min="0" - value_max="1" + id="1206" + group="1" + name="Butt_Physics_LeftRight_Driven" + wearable="physics" + cross_wearable="true" + edit_group="driven" value_default="0" - camera_elevation=".1" - camera_distance=".3"> - <!-- default to natural brown eyes--> - <param_color> - <value - color="50, 25, 5, 255" /> + value_min="-1" + value_max="1"> + <param_morph> + <volume_morph + name="BUTT" + pos="0.0 0.05 0.0"/> + </param_morph> + </param> - <!-- natural dark brown eyes--> - <value - color="109, 55, 15, 255" /> - - <!-- natural brown eyes--> - <value - color="150, 93, 49, 255" /> + <!-- + #end morph targets + --> - <!-- natural light brown eyes--> - <value - color="152, 118, 25, 255" /> + </mesh> - <!--natural hazel eyes--> - <value - color="95, 179, 107, 255" /> + <mesh + type="lowerBodyMesh" + lod="1" + file_name="avatar_lower_body_1.llm" + min_pixel_width="160" + reference="avatar_lower_body.llm"> + </mesh> - <!--natural green eyes--> - <value - color="87, 192, 191, 255" /> + <mesh + type="lowerBodyMesh" + lod="2" + file_name="avatar_lower_body_2.llm" + min_pixel_width="80" + reference="avatar_lower_body.llm"> + </mesh> - <!--natural aqua eyes--> - <value - color="95, 172, 179, 255" /> + <mesh + type="lowerBodyMesh" + lod="3" + file_name="avatar_lower_body_3.llm" + min_pixel_width="40" + reference="avatar_lower_body.llm"> + </mesh> - <!--natural blue eyes--> - <value - color="128, 128, 128, 255" /> + <mesh + type="lowerBodyMesh" + lod="4" + file_name="avatar_lower_body_4.llm" + min_pixel_width="0" + reference="avatar_lower_body.llm"> + </mesh> - <!--natural grey eyes--> - <value - color="0, 0, 0, 255" /> + <!-- + #lowerBodyMesh2 = + #lowerBodyMesh3 = + --> + <!-- + #eyeLidLeftMesh = + --> + <mesh + type="eyeBallLeftMesh" + lod="0" + file_name="avatar_eye.llm" + min_pixel_width="320"> + <!-- begin morph_params --> + <param + id="679" + group="1" + name="Eyeball_Size" + label="Eyeball Size" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".10"> + <param_morph /> + </param> - <!--black eyes--> - <value - color="255, 255, 0, 255" /> + <param + id="687" + group="1" + name="Eyeball_Size" + label="Big Eyeball" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".25"> + <param_morph /> + </param> + </mesh> - <!--bright yellow eyes--> - <value - color=" 0, 255, 0, 255" /> + <mesh + type="eyeBallLeftMesh" + lod="1" + file_name="avatar_eye_1.llm" + min_pixel_width="80"> + <!-- begin morph_params --> + <param + id="694" + group="1" + name="Eyeball_Size" + label="Eyeball Size" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".10"> + <param_morph /> + </param> - <!-- bright green eyes--> - <value - color=" 0, 255, 255, 255" /> + <param + id="695" + group="1" + name="Eyeball_Size" + label="Big Eyeball" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".25"> + <param_morph /> + </param> + </mesh> - <!-- bright cyan eyes--> - <value - color=" 0, 0, 255, 255" /> + <!-- + #eyeLidRightMesh = + --> + <mesh + type="eyeBallRightMesh" + lod="0" + file_name="avatar_eye.llm" + min_pixel_width="320"> + <!-- begin morph_params --> + <param + id="680" + group="1" + name="Eyeball_Size" + label="Eyeball Size" + wearable="shape" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".10"> + <param_morph /> + </param> - <!--bright blue eyes--> - <value - color="255, 0, 255, 255" /> + <param + id="688" + group="1" + name="Eyeball_Size" + label="Big Eyeball" + wearable="shape" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".25"> + <param_morph /> + </param> + </mesh> - <!-- bright violet eyes--> - <value - color="255, 0, 0, 255" /> + <mesh + type="eyeBallRightMesh" + lod="1" + file_name="avatar_eye_1.llm" + min_pixel_width="80"> + <!-- begin morph_params --> + <param + id="681" + group="1" + name="Eyeball_Size" + label="Eyeball Size" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".10"> + <param_morph /> + </param> - <!--bright red eyes--> - </param_color> + <param + id="691" + group="1" + name="Eyeball_Size" + label="Big Eyeball" + wearable="shape" + edit_group="shape_eyes" + label_min="small eye" + label_max="big eye" + value_min="-.25" + value_max=".25"> + <param_morph /> </param> + </mesh> + <mesh + type="skirtMesh" + lod="0" + file_name="avatar_skirt.llm" + min_pixel_width="320"> <param - id="98" - group="0" - wearable="eyes" - edit_group="eyes" - edit_group_order="2" - name="Eye Lightness" - show_simple="true" - label_min="Darker" - label_max="Lighter" + id="845" + group="1" + name="skirt_poofy" + label="poofy skirt" + clothing_morph="true" + wearable="skirt" + edit_group="skirt" + label_min="less poofy" + label_max="more poofy" value_min="0" - value_max="1" - camera_elevation=".1" - camera_distance=".3"> - <param_color> - <value - color="0, 0, 0, 0" /> - - <value - color="255, 255, 255, 255" /> - </param_color> + value_max="1.5"> + <param_morph /> </param> - </global_color> - <!-- =========================================================== --> - <layer_set - body_region="hair" - width="512" - height="512" - clear_alpha="false"> - <layer - name="base" - global_color="hair_color" - write_all_channels="true"> - <texture - local_texture="hair_grain" /> - </layer> + <param + id="846" + group="1" + name="skirt_loose" + label="loose skirt" + clothing_morph="true" + wearable="skirt" + edit_group="skirt" + label_min="form fitting" + label_max="loose" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <layer - name="hair texture alpha layer" - visibility_mask="TRUE"> - <texture - local_texture="hair_grain" /> - </layer> + <param + id="866" + group="1" + name="skirt_tight" + label="tight skirt" + clothing_morph="true" + wearable="skirt" + edit_group="skirt" + label_min="form fitting" + label_max="loose" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <layer - name="hair alpha" - visibility_mask="TRUE"> - <texture - local_texture="hair_alpha" /> - </layer> + <param + id="867" + group="1" + name="skirt_smallbutt" + label="tight skirt" + clothing_morph="false" + wearable="skirt" + edit_group="skirt" + cross_wearable="true" + label_min="form fitting" + label_max="loose" + value_min="0" + value_max="1"> + <param_morph /> + </param> - </layer_set> - <!-- =========================================================== --> + <param + id="848" + group="0" + name="skirt_bustle" + label="bustle skirt" + clothing_morph="true" + wearable="skirt" + edit_group_order="3" + edit_group="skirt" + label_min="no bustle" + label_max="more bustle" + value_min="0" + value_max="2" + value_default=".2" + camera_angle="100" + camera_distance="1.3" + camera_elevation="-.5"> + <param_morph /> + </param> - <layer_set - body_region="head" - width="512" - height="512"> - <layer - name="head bump base" - fixed_color = "128,128,128,255" - render_pass="bump"> - </layer> + <param + id="847" + group="1" + name="skirt_bowlegs" + label="legs skirt" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + value_min="-1" + value_max="1" + value_default="0"> + <param_morph /> + </param> - <layer - name="head bump definition" - render_pass="bump"> - + <param + id="852" + group="1" + name="skirt_bigbutt" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + label="bigbutt skirt" + label_min="less" + label_max="more" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <texture - tga_file="bump_head_base.tga" - file_is_mask="FALSE"/> + <param + id="849" + group="1" + name="skirt_belly" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + label="big belly skirt" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <param - id="873" - group="1" - wearable="skin" - edit_group="driven" - edit_group_order="12" - name="Bump base" - value_min="0" - value_max="1"> - <param_alpha - domain="0" /> - </param> - </layer> + <param + id="850" + group="1" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + name="skirt_saddlebags" + value_min="-.5" + value_max="3"> + <param_morph /> + </param> - <layer - name="base" - global_color="skin_color"> - <texture - tga_file="head_skingrain.tga" /> - </layer> + <param + id="851" + group="1" + name="skirt_chubby" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + label_min="less" + label_max="more" + value_min="0" + value_max="1" + value_default="0"> + <param_morph /> + </param> - <layer - name="headcolor"> - <texture - tga_file="head_color.tga" /> - </layer> + <param + id="856" + group="1" + name="skirt_lovehandles" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + label_min="less" + label_max="more" + value_min="-1" + value_max="2" + value_default="0"> + <param_morph /> + </param> - <layer - name="shadow"> - <texture - tga_file="head_shading_alpha.tga" - file_is_mask="TRUE" /> + <!-- + ############# + # other morphs (not user controlled) + ############# + --> + <param + id="857" + group="1" + name="skirt_male" + wearable="skirt" + edit_group="driven" + cross_wearable="true" + value_min="0" + value_max="1"> + <param_morph /> + </param> - <param - id="158" - group="1" - wearable="skin" - name="Shading" - value_min="0" - value_max="1"> - <param_color> - <value - color="0, 0, 0, 0" /> + <!-- + ############# + # physics morphs (not user controlled) + ############# + --> + <param + id="1203" + group="1" + name="Belly_Physics_Skirt_UpDown_Driven" + wearable="physics" + cross_wearable="true" + edit_group="driven" + value_default="0" + value_min="-1" + value_max="1"> + <param_morph /> + </param> - <value - color="0, 0, 0, 128" /> - </param_color> - </param> - </layer> - - <layer - name="highlight"> - <texture - tga_file="head_highlights_alpha.tga" -file_is_mask="TRUE" /> + </mesh> + <mesh + type="skirtMesh" + lod="1" + file_name="avatar_skirt_1.llm" + min_pixel_width="160" + reference="avatar_skirt.llm"> + </mesh> - <param - id="159" - group="1" - name="Shading" - wearable="skin" - value_min="0" - value_max="1"> - <param_color> - <value -color="255, 255, 255, 0" /> + <mesh + type="skirtMesh" + lod="2" + file_name="avatar_skirt_2.llm" + min_pixel_width="80" + reference="avatar_skirt.llm"> + </mesh> + <mesh + type="skirtMesh" + lod="3" + file_name="avatar_skirt_3.llm" + min_pixel_width="40" + reference="avatar_skirt.llm"> + </mesh> - <value - color="255, 255, 255, 64" /> - </param_color> - </param> - </layer> - <layer - name="rosyface"> - <texture - tga_file="rosyface_alpha.tga" - file_is_mask="true" /> + <mesh + type="skirtMesh" + lod="4" + file_name="avatar_skirt_4.llm" + min_pixel_width="0" + reference="avatar_skirt.llm"> + </mesh> - <param - id="116" - group="0" - wearable="skin" - edit_group="skin_facedetail" - edit_group_order="4" - name="Rosy Complexion" - label_min="Less Rosy" - label_max="More Rosy" - value_min="0" - value_max="1" - camera_distance=".3" - camera_elevation=".07"> - <param_color> - <value - color="198, 71, 71, 0" /> + <!-- =========================================================== --> + <global_color + name="skin_color"> + <param + id="111" + group="0" + wearable="skin" + edit_group="skin_color" + edit_group_order="1" + name="Pigment" + show_simple="true" + label_min="Light" + label_max="Dark" + value_min="0" + value_max="1" + value_default=".5"> + <param_color> + <value + color="252, 215, 200, 255" /> - <value - color="198, 71, 71, 255" /> - </param_color> - </param> - </layer> + <value + color="240, 177, 112, 255" /> - <layer - name="lips"> - <texture - tga_file="lips_mask.tga" - file_is_mask="true" /> + <value + color="90, 40, 16, 255" /> - <param - id="117" - group="0" - wearable="skin" - edit_group="skin_facedetail" - edit_group_order="5" - name="Lip Pinkness" - label_min="Darker" - label_max="Pinker" - value_min="0" - value_max="1" - camera_distance=".25"> - <param_color> - <value - color="220, 115, 115, 0" /> + <value + color="29, 9, 6, 255" /> + </param_color> + </param> - <value - color="220, 115, 115, 128" /> - </param_color> - </param> - </layer> + <param + id="110" + group="0" + wearable="skin" + edit_group="skin_color" + edit_group_order="2" + name="Red Skin" + label="Ruddiness" + label_min="Pale" + label_max="Ruddy" + value_min="0" + value_max="0.1"> + <param_color + operation="blend"> + <value + color="218, 41, 37, 255" /> + </param_color> + </param> - <layer - name="wrinkles_shading" - render_pass="bump" - fixed_color="0,0,0,100"> - <param - id="118" - group="1" - wearable="skin" - name="Wrinkles" - value_min="0" - value_max="1"> - <param_alpha - tga_file="bump_face_wrinkles.tga" - skip_if_zero="true" - domain="0.3" /> - </param> - </layer> + <param + id="108" + group="0" + wearable="skin" + edit_group="skin_color" + edit_group_order="3" + name="Rainbow Color" + show_simple="true" + label_min="None" + label_max="Wild" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5"> + <param_color> + <value + color=" 0, 0, 0, 255" /> - <!--<layer - name="wrinkles_highlights" - fixed_color="255,255,255,64"> - <param - id="128" - group="1" - name="Wrinkles" - value_min="0" - value_max="1"> - <param_alpha - tga_file="head_wrinkles_highlights_alpha.tga" - skip_if_zero="true" - domain="0.3" /> - </param> - </layer>--> - <layer - name="freckles" - fixed_color="120,47,20,128"> - <param - id="165" - group="0" - wearable="skin" - edit_group="skin_facedetail" - edit_group_order="2" - name="Freckles" - label_min="Less" - label_max="More" - value_min="0" - value_max="1" - camera_distance=".3" -camera_elevation=".07"> - <param_alpha - tga_file="freckles_alpha.tga" - skip_if_zero="true" -domain="0.5" /> - </param> - </layer> - <layer -name="eyebrowsbump" -render_pass="bump"> - <texture - tga_file="head_hair.tga" - file_is_mask="false" /> + <value + color="255, 0, 255, 255" /> - <param - id="1000" - group="1" - wearable="hair" - edit_group="driven" - name="Eyebrow Size Bump" - value_min="0" - value_max="1"> - <param_alpha - tga_file="eyebrows_alpha.tga" - domain="0.1" /> - </param> + <value + color="255, 0, 0, 255" /> - <param - id="1002" - group="1" - wearable="hair" - edit_group="driven" - name="Eyebrow Density Bump" - value_min="0" - value_max="1"> - <param_color> - <value - color="255,255,255,0" /> + <value + color="255, 255, 0, 255" /> - <value - color="255,255,255,255" /> - </param_color> - </param> - </layer> + <value + color=" 0, 255, 0, 255" /> - <layer - name="eyebrows" - global_color="hair_color"> - <texture - tga_file="head_hair.tga" - file_is_mask="false" /> - - <param - id="1001" - group="1" - wearable="hair" - edit_group="hair_eyebrows" - name="Eyebrow Size" - show_simple="true" - value_min="0" - value_max="1" - value_default="0.5"> - <param_alpha - tga_file="eyebrows_alpha.tga" - domain="0.1" /> - </param> - - <param - id="1003" - group="1" - wearable="hair" - edit_group="driven" - name="Eyebrow Density" - value_min="0" - value_max="1"> - <param_color - operation="multiply"> - <value - color="255,255,255,0" /> + <value + color=" 0, 255, 255, 255" /> - <value - color="255,255,255,255" /> - </param_color> - </param> - </layer> + <value + color=" 0, 0, 255, 255" /> - <layer - name="lipstick"> - <param - id="700" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="2" - name="Lipstick Color" - label_min="Pink" - label_max="Black" - value_min="0" - value_max="1" - value_default=".25" - camera_distance=".25"> - <param_color> - <value - color="245,161,177,200" /> + <value + color="255, 0, 255, 255" /> + </param_color> + </param> + </global_color> - <value - color="216,37,67,200" /> + <!-- =========================================================== --> + <global_color + name="hair_color"> + <param + id="114" + group="0" + wearable="hair" + edit_group="hair_color" + edit_group_order="3" + name="Blonde Hair" + show_simple="true" + label_min="Black" + label_max="Blonde" + value_min="0" + value_max="1" + value_default=".5" + camera_elevation=".1" + camera_distance=".5"> + <param_color> + <value + color="0, 0, 0, 255" /> - <value - color="178,48,76,200" /> + <value + color="22, 6, 6, 255" /> - <value - color="68,0,11,200" /> + <value + color="29, 9, 6, 255" /> - <value - color="252,207,184,200" /> + <value + color="45, 21, 11, 255" /> - <value - color="241,136,106,200" /> + <value + color="78, 39, 11, 255" /> - <value - color="208,110,85,200" /> + <value + color="90, 53, 16, 255" /> - <value - color="106,28,18,200" /> + <value + color="136, 92, 21, 255" /> - <value - color="58,26,49,200" /> + <value + color="150, 106, 33, 255" /> - <value - color="14,14,14,200" /> - </param_color> - </param> + <value + color="198, 156, 74, 255" /> - <param - id="701" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="1" - name="Lipstick" - label_min="No Lipstick" - label_max="More Lipstick" - value_min="0" - value_max=".9" - value_default="0.0" - camera_distance=".25"> - <param_alpha - tga_file="lipstick_alpha.tga" - skip_if_zero="true" - domain="0.05" /> - </param> - </layer> + <value + color="233, 192, 103, 255" /> - <layer - name="lipgloss" - fixed_color="255,255,255,190"> - <param - id="702" - name="Lipgloss" - label_min="No Lipgloss" - label_max="Glossy" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="3" - group="0" - value_min="0" - value_max="1" - camera_distance=".25"> - <param_alpha - tga_file="lipgloss_alpha.tga" - skip_if_zero="true" - domain="0.2" /> - </param> - </layer> + <value + color="238, 205, 136, 255" /> + </param_color> + </param> - <layer - name="blush"> - <param - id="704" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="4" - name="Blush" - label_min="No Blush" - label_max="More Blush" - value_min="0" - value_max=".9" - value_default="0" - camera_distance=".3" - camera_elevation=".07" - camera_angle="20"> - <param_alpha - tga_file="blush_alpha.tga" - skip_if_zero="true" - domain="0.3" /> - </param> + <param + id="113" + group="0" + wearable="hair" + edit_group="hair_color" + edit_group_order="4" + name="Red Hair" + show_simple="true" + label_min="No Red" + label_max="Very Red" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5"> + <param_color> + <value + color="0, 0, 0, 255" /> - <param - id="705" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="5" - name="Blush Color" - label_min="Pink" - label_max="Orange" - value_min="0" - value_max="1" - value_default=".5" - camera_distance=".3" - camera_elevation=".07" - camera_angle="20"> - <param_color> - <value - color="253,162,193,200" /> + <value + color="118, 47, 19, 255" /> + </param_color> + </param> - <value - color="247,131,152,200" /> + <param + id="115" + group="0" + wearable="hair" + edit_group="hair_color" + edit_group_order="1" + name="White Hair" + show_simple="true" + label_min="No White" + label_max="All White" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5"> + <param_color> + <value + color="0, 0, 0, 255" /> - <value - color="213,122,140,200" /> + <value + color="255, 255, 255, 255" /> + </param_color> + </param> - <value - color="253,152,144,200" /> - - <value - color="236,138,103,200" /> - - <value - color="195,128,122,200" /> + <param + id="112" + group="0" + wearable="hair" + edit_group="hair_color" + edit_group_order="2" + name="Rainbow Color" + show_simple="true" + label_min="None" + label_max="Wild" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5"> + <param_color> + <value + color=" 0, 0, 0, 255" /> - <value - color="148,103,100,200" /> + <value + color="255, 0, 255, 255" /> - <value - color="168,95,62,200" /> - </param_color> - </param> + <value + color="255, 0, 0, 255" /> - <param - id="711" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="6" - name="Blush Opacity" - label_min="Clear" - label_max="Opaque" - value_min="0" - value_max="1" - value_default=".5" - camera_distance=".3" - camera_elevation=".07" - camera_angle="20"> - <param_color - operation="multiply"> - <value - color="255,255,255,0" /> + <value + color="255, 255, 0, 255" /> - <value - color="255,255,255,255" /> - </param_color> - </param> - </layer> + <value + color=" 0, 255, 0, 255" /> - <layer - name="Outer Eye Shadow"> - <param - id="708" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="11" - name="Out Shdw Color" - label_min="Light" - label_max="Dark" - value_min="0" - value_max="1" - camera_distance=".3" - camera_elevation=".14"> - <param_color> - <value - color="252,247,246,255" /> + <value + color=" 0, 255, 255, 255" /> - <value - color="255,206,206,255" /> + <value + color=" 0, 0, 255, 255" /> - <value - color="233,135,149,255" /> + <value + color="255, 0, 255, 255" /> + </param_color> + </param> + </global_color> - <value - color="220,168,192,255" /> + <!-- =========================================================== --> + <global_color + name="eye_color"> + <param + id="99" + group="0" + wearable="eyes" + edit_group="eyes" + edit_group_order="1" + name="Eye Color" + show_simple="true" + label_min="Natural" + label_max="Unnatural" + value_min="0" + value_max="1" + value_default="0" + camera_elevation=".1" + camera_distance=".3"> + <!-- default to natural brown eyes--> + <param_color> + <value + color="50, 25, 5, 255" /> - <value - color="228,203,232,255" /> + <!-- natural dark brown eyes--> + <value + color="109, 55, 15, 255" /> - <value - color="255,234,195,255" /> + <!-- natural brown eyes--> + <value + color="150, 93, 49, 255" /> - <value - color="230,157,101,255" /> + <!-- natural light brown eyes--> + <value + color="152, 118, 25, 255" /> - <value - color="255,147,86,255" /> + <!--natural hazel eyes--> + <value + color="95, 179, 107, 255" /> - <value - color="228,110,89,255" /> + <!--natural green eyes--> + <value + color="87, 192, 191, 255" /> - <value - color="228,150,120,255" /> + <!--natural aqua eyes--> + <value + color="95, 172, 179, 255" /> - <value - color="223,227,213,255" /> + <!--natural blue eyes--> + <value + color="128, 128, 128, 255" /> - <value - color="96,116,87,255" /> + <!--natural grey eyes--> + <value + color="0, 0, 0, 255" /> - <value - color="88,143,107,255" /> + <!--black eyes--> + <value + color="255, 255, 0, 255" /> - <value - color="194,231,223,255" /> + <!--bright yellow eyes--> + <value + color=" 0, 255, 0, 255" /> - <value - color="207,227,234,255" /> + <!-- bright green eyes--> + <value + color=" 0, 255, 255, 255" /> - <value - color="41,171,212,255" /> + <!-- bright cyan eyes--> + <value + color=" 0, 0, 255, 255" /> - <value - color="180,137,130,255" /> + <!--bright blue eyes--> + <value + color="255, 0, 255, 255" /> - <value - color="173,125,105,255" /> + <!-- bright violet eyes--> + <value + color="255, 0, 0, 255" /> - <value - color="144,95,98,255" /> + <!--bright red eyes--> + </param_color> + </param> - <value - color="115,70,77,255" /> + <param + id="98" + group="0" + wearable="eyes" + edit_group="eyes" + edit_group_order="2" + name="Eye Lightness" + show_simple="true" + label_min="Darker" + label_max="Lighter" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".3"> + <param_color> + <value + color="0, 0, 0, 0" /> - <value - color="155,78,47,255" /> + <value + color="255, 255, 255, 255" /> + </param_color> + </param> + </global_color> - <value - color="239,239,239,255" /> + <!-- =========================================================== --> + <layer_set + body_region="hair" + width="512" + height="512" + clear_alpha="false"> + <layer + name="base" + global_color="hair_color" + write_all_channels="true"> + <texture + local_texture="hair_grain" /> + </layer> - <value - color="194,194,194,255" /> + <layer + name="hair texture alpha layer" + visibility_mask="TRUE"> + <texture + local_texture="hair_grain" /> + </layer> - <value - color="120,120,120,255" /> + <layer + name="hair alpha" + visibility_mask="TRUE"> + <texture + local_texture="hair_alpha" /> + </layer> - <value - color="10,10,10,255" /> - </param_color> - </param> + </layer_set> + <!-- =========================================================== --> - <param - id="706" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="12" - name="Out Shdw Opacity" - label_min="Clear" - label_max="Opaque" - value_min=".2" - value_max="1" - value_default=".6" - camera_distance=".3" - camera_elevation=".14"> - <param_color - operation="multiply"> - <value - color="255,255,255,0" /> + <layer_set + body_region="head" + width="512" + height="512"> + <layer + name="head bump base" + fixed_color = "128,128,128,255" + render_pass="bump"> + </layer> - <value - color="255,255,255,255" /> - </param_color> - </param> + <layer + name="head bump definition" + render_pass="bump"> + + + <texture + tga_file="bump_head_base.tga" + file_is_mask="FALSE"/> <param - id="707" - group="0" + id="873" + group="1" wearable="skin" - edit_group="skin_makeup" - edit_group_order="10" - name="Outer Shadow" - label_min="No Eyeshadow" - label_max="More Eyeshadow" + edit_group="driven" + edit_group_order="12" + name="Bump base" value_min="0" - value_max=".7" - camera_distance=".3" - camera_elevation=".14"> + value_max="1"> <param_alpha - tga_file="eyeshadow_outer_alpha.tga" - skip_if_zero="true" - domain="0.05" /> + domain="0" /> </param> </layer> <layer - name="Inner Eye Shadow"> + name="base" + global_color="skin_color"> + <texture + tga_file="head_skingrain.tga" /> + </layer> + + <layer + name="headcolor"> + <texture + tga_file="head_color.tga" /> + </layer> + + <layer + name="shadow"> + <texture + tga_file="head_shading_alpha.tga" + file_is_mask="TRUE" /> + <param - id="712" - group="0" + id="158" + group="1" wearable="skin" - edit_group="skin_makeup" - edit_group_order="8" - name="In Shdw Color" - label_min="Light" - label_max="Dark" + name="Shading" value_min="0" - value_max="1" - camera_distance=".3" - camera_elevation=".14"> + value_max="1"> <param_color> <value - color="252,247,246,255" /> - - <value - color="255,206,206,255" /> - - <value - color="233,135,149,255" /> - - <value - color="220,168,192,255" /> - - <value - color="228,203,232,255" /> - - <value - color="255,234,195,255" /> - - <value - color="230,157,101,255" /> - - <value - color="255,147,86,255" /> - - <value - color="228,110,89,255" /> - - <value - color="228,150,120,255" /> - - <value - color="223,227,213,255" /> - - <value - color="96,116,87,255" /> - - <value - color="88,143,107,255" /> - - <value - color="194,231,223,255" /> - - <value - color="207,227,234,255" /> - - <value - color="41,171,212,255" /> - - <value - color="180,137,130,255" /> - - <value - color="173,125,105,255" /> - - <value - color="144,95,98,255" /> + color="0, 0, 0, 0" /> <value - color="115,70,77,255" /> + color="0, 0, 0, 128" /> + </param_color> + </param> + </layer> - <value - color="155,78,47,255" /> + <layer + name="highlight"> + <texture + tga_file="head_highlights_alpha.tga" +file_is_mask="TRUE" /> - <value - color="239,239,239,255" /> + <param + id="159" + group="1" + name="Shading" + wearable="skin" + value_min="0" + value_max="1"> + <param_color> <value - color="194,194,194,255" /> +color="255, 255, 255, 0" /> - <value - color="120,120,120,255" /> <value - color="10,10,10,255" /> + color="255, 255, 255, 64" /> </param_color> </param> + </layer> + <layer + name="rosyface"> + <texture + tga_file="rosyface_alpha.tga" + file_is_mask="true" /> <param - id="713" + id="116" group="0" wearable="skin" - edit_group="skin_makeup" - edit_group_order="9" - name="In Shdw Opacity" - label_min="Clear" - label_max="Opaque" - value_min=".2" + edit_group="skin_facedetail" + edit_group_order="4" + name="Rosy Complexion" + label_min="Less Rosy" + label_max="More Rosy" + value_min="0" value_max="1" - value_default=".7" camera_distance=".3" - camera_elevation=".14"> - <param_color - operation="multiply"> + camera_elevation=".07"> + <param_color> <value - color="255,255,255,0" /> + color="198, 71, 71, 0" /> <value - color="255,255,255,255" /> + color="198, 71, 71, 255" /> </param_color> </param> + </layer> + + <layer + name="lips"> + <texture + tga_file="lips_mask.tga" + file_is_mask="true" /> <param - id="709" + id="117" group="0" wearable="skin" - edit_group="skin_makeup" - edit_group_order="7" - name="Inner Shadow" - label_min="No Eyeshadow" - label_max="More Eyeshadow" + edit_group="skin_facedetail" + edit_group_order="5" + name="Lip Pinkness" + label_min="Darker" + label_max="Pinker" value_min="0" value_max="1" - value_default="0" - camera_distance=".3" - camera_elevation=".14"> - <param_alpha - tga_file="eyeshadow_inner_alpha.tga" - skip_if_zero="true" - domain="0.2" /> + camera_distance=".25"> + <param_color> + <value + color="220, 115, 115, 0" /> + + <value + color="220, 115, 115, 128" /> + </param_color> </param> </layer> <layer - name="eyeliner" - fixed_color="0,0,0,200"> + name="wrinkles_shading" + render_pass="bump" + fixed_color="0,0,0,100"> <param - id="703" - group="0" + id="118" + group="1" wearable="skin" - edit_group="skin_makeup" - edit_group_order="13" - name="Eyeliner" - label_min="No Eyeliner" - label_max="Full Eyeliner" + name="Wrinkles" value_min="0" - value_max="1" - value_default="0.0" - camera_distance=".3" - camera_elevation=".14"> + value_max="1"> <param_alpha - tga_file="eyeliner_alpha.tga" + tga_file="bump_face_wrinkles.tga" skip_if_zero="true" - domain="0.1" /> + domain="0.3" /> </param> + </layer> + <!--<layer + name="wrinkles_highlights" + fixed_color="255,255,255,64"> + <param + id="128" + group="1" + name="Wrinkles" + value_min="0" + value_max="1"> + <param_alpha + tga_file="head_wrinkles_highlights_alpha.tga" + skip_if_zero="true" + domain="0.3" /> + </param> + </layer>--> + <layer + name="freckles" + fixed_color="120,47,20,128"> <param - id="714" - group="0" - wearable="skin" - edit_group="skin_makeup" - edit_group_order="14" - name="Eyeliner Color" - label_min="Dark Green" - label_max="Black" - value_min="0" - value_max="1" - camera_distance=".3" - camera_elevation=".14"> - <param_color> - <value - color="24,98,40,250" /> - - <!-- dark green --> - <value - color="9,100,127,250" /> - - <!-- lt.aqua blue --> - <value - color="61,93,134,250" /> - - <!-- aqua --> - <value - color="70,29,27,250" /> - - <!-- dark brown --> - <value - color="115,75,65,250" /> - - <!-- lt. brown blue --> - <value - color="100,100,100,250" /> - - <!-- grey --> - <value - color="91,80,74,250" /> - - <!-- grey/brown --> - <value - color="112,42,76,250" /> - - <!-- plum --> - <value - color="14,14,14,250" /> - - <!-- black --> - </param_color> + id="165" + group="0" + wearable="skin" + edit_group="skin_facedetail" + edit_group_order="2" + name="Freckles" + label_min="Less" + label_max="More" + value_min="0" + value_max="1" + camera_distance=".3" +camera_elevation=".07"> + <param_alpha + tga_file="freckles_alpha.tga" + skip_if_zero="true" +domain="0.5" /> </param> </layer> - <layer - name="facialhair bump" - render_pass="bump"> +name="eyebrowsbump" +render_pass="bump"> <texture tga_file="head_hair.tga" file_is_mask="false" /> <param - id="1004" - sex="male" - group="1" - wearable="hair" - edit_group="driven" - name="Sideburns bump" - value_min="0" - value_max="1"> - <param_alpha - tga_file="facehair_sideburns_alpha.tga" - skip_if_zero="true" - domain="0.05" /> - </param> - - <param - id="1006" - sex="male" - group="1" - wearable="hair" - edit_group="driven" - name="Moustache bump" - value_min="0" - value_max="1"> - <param_alpha - tga_file="facehair_moustache_alpha.tga" - skip_if_zero="true" - domain="0.05" /> - </param> - - <param - id="1008" - sex="male" + id="1000" group="1" wearable="hair" edit_group="driven" - name="Soulpatch bump" + name="Eyebrow Size Bump" value_min="0" value_max="1"> <param_alpha - tga_file="facehair_soulpatch_alpha.tga" - skip_if_zero="true" + tga_file="eyebrows_alpha.tga" domain="0.1" /> </param> <param - id="1010" - sex="male" - group="1" - edit_group="driven" - wearable="hair" - name="Chin Curtains bump" - value_min="0" - value_max="1"> - <param_alpha - tga_file="facehair_chincurtains_alpha.tga" - skip_if_zero="true" - domain="0.03" /> - </param> - - <param - id="1012" + id="1002" group="1" - sex="male" wearable="hair" edit_group="driven" - name="5 O'Clock Shadow bump" + name="Eyebrow Density Bump" value_min="0" value_max="1"> <param_color> <value - color="255,255,255,255" /> + color="255,255,255,0" /> <value - color="255,255,255,0" /> + color="255,255,255,255" /> </param_color> </param> </layer> <layer - name="facialhair" + name="eyebrows" global_color="hair_color"> - <texture tga_file="head_hair.tga" file_is_mask="false" /> <param - id="1005" - sex="male" - group="1" - wearable="hair" - edit_group="driven" - name="Sideburns" - value_min="0" - value_max="1"> - <param_alpha - tga_file="facehair_sideburns_alpha.tga" - skip_if_zero="true" - domain="0.05" /> - </param> - - <param - id="1007" - sex="male" - group="1" - wearable="hair" - edit_group="driven" - name="Moustache" - value_min="0" - value_max="1"> - <param_alpha - tga_file="facehair_moustache_alpha.tga" - skip_if_zero="true" - domain="0.05" /> - </param> - - <param - id="1009" - sex="male" + id="1001" group="1" wearable="hair" - edit_group="driven" - name="Soulpatch" + edit_group="hair_eyebrows" + name="Eyebrow Size" + show_simple="true" value_min="0" - value_max="1"> + value_max="1" + value_default="0.5"> <param_alpha - tga_file="facehair_soulpatch_alpha.tga" - skip_if_zero="true" + tga_file="eyebrows_alpha.tga" domain="0.1" /> </param> <param - id="1011" - sex="male" + id="1003" group="1" wearable="hair" edit_group="driven" - name="Chin Curtains" + name="Eyebrow Density" value_min="0" value_max="1"> - <param_alpha - tga_file="facehair_chincurtains_alpha.tga" - skip_if_zero="true" - domain="0.03" /> - </param> - - <param - id="751" - group="1" - wearable="hair" - sex="male" - edit_group="hair_facial" - name="5 O'Clock Shadow" - label_min="Dense hair" - label_max="Shadow hair" - value_min="0" - value_max="1" - value_default="0.7" - camera_elevation=".1" - camera_distance=".3"> <param_color operation="multiply"> <value - color="255,255,255,255" /> + color="255,255,255,0" /> <value - color="255,255,255,30" /> + color="255,255,255,255" /> </param_color> </param> </layer> <layer - name="head_bodypaint"> - <texture - local_texture="head_bodypaint" /> - </layer> - <layer - name="eyelash alpha" - visibility_mask="TRUE"> - <texture - tga_file="head_alpha.tga" - file_is_mask="TRUE" /> - </layer> - <layer - name="head alpha" - visibility_mask="TRUE"> - <texture - local_texture="head_alpha" /> - </layer> - <layer - name="head_tattoo"> - <texture - local_texture="head_tattoo" /> + name="lipstick"> <param - id="1062" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_head_red" + id="700" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="2" + name="Lipstick Color" + label_min="Pink" + label_max="Black" value_min="0" value_max="1" - value_default="1"> + value_default=".25" + camera_distance=".25"> <param_color> <value - color="0, 0, 0, 255" /> + color="245,161,177,200" /> <value - color="255, 0, 0, 255" /> - </param_color> - </param> + color="216,37,67,200" /> - <param - id="1063" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_head_green" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="178,48,76,200" /> <value - color="0, 255, 0, 255" /> - </param_color> - </param> + color="68,0,11,200" /> - <param - id="1064" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_head_blue" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="252,207,184,200" /> <value - color="0, 0, 255, 255" /> - </param_color> - </param> - - </layer> + color="241,136,106,200" /> + <value + color="208,110,85,200" /> - </layer_set> + <value + color="106,28,18,200" /> - <!-- =========================================================== --> - <layer_set - body_region="upper_body" - width="512" - height="512"> - <layer - name="base_upperbody bump" - render_pass="bump" - fixed_color="128,128,128,255"> - </layer> - <layer - name="upperbody bump definition" - render_pass="bump"> - <texture - tga_file="bump_upperbody_base.tga" - file_is_mask="FALSE"/> + <value + color="58,26,49,200" /> - <param - id="874" - group="1" - wearable="skin" - edit_group="driven" - edit_group_order="20" - name="Bump upperdef" - value_min="0" - value_max="1"> - <param_alpha - domain="0" /> + <value + color="14,14,14,200" /> + </param_color> </param> - </layer> - - <layer - name="base" - global_color="skin_color"> - <texture - tga_file="body_skingrain.tga" /> - </layer> - - <layer - name="nipples"> - <texture - tga_file="upperbody_color.tga" /> - </layer> - - <layer - name="shadow"> - <texture - tga_file="upperbody_shading_alpha.tga" - file_is_mask="TRUE" /> <param - id="125" - group="1" - name="Shading" + id="701" + group="0" wearable="skin" + edit_group="skin_makeup" + edit_group_order="1" + name="Lipstick" + label_min="No Lipstick" + label_max="More Lipstick" value_min="0" - value_max="1"> - <param_color> - <value - color="0, 0, 0, 0" /> - - <value - color="0, 0, 0, 128" /> - </param_color> + value_max=".9" + value_default="0.0" + camera_distance=".25"> + <param_alpha + tga_file="lipstick_alpha.tga" + skip_if_zero="true" + domain="0.05" /> </param> </layer> <layer - name="highlight"> - <texture - tga_file="upperbody_highlights_alpha.tga" - file_is_mask="TRUE" /> - + name="lipgloss" + fixed_color="255,255,255,190"> <param - id="126" - group="1" + id="702" + name="Lipgloss" + label_min="No Lipgloss" + label_max="Glossy" wearable="skin" - name="Shading" + edit_group="skin_makeup" + edit_group_order="3" + group="0" value_min="0" - value_max="1"> - <param_color> - <value - color="255, 255, 255, 0" /> - - <value - color="255, 255, 255, 64" /> - </param_color> + value_max="1" + camera_distance=".25"> + <param_alpha + tga_file="lipgloss_alpha.tga" + skip_if_zero="true" + domain="0.2" /> </param> </layer> <layer - name="upper_bodypaint"> - <texture - local_texture="upper_bodypaint" /> - </layer> - - <layer - name="freckles upper" - fixed_color="120,47,20,128"> + name="blush"> <param - id="776" - group="1" - name="freckles upper" + id="704" + group="0" wearable="skin" + edit_group="skin_makeup" + edit_group_order="4" + name="Blush" + label_min="No Blush" + label_max="More Blush" value_min="0" - value_max="1"> + value_max=".9" + value_default="0" + camera_distance=".3" + camera_elevation=".07" + camera_angle="20"> <param_alpha - tga_file="upperbodyfreckles_alpha.tga" + tga_file="blush_alpha.tga" skip_if_zero="true" - domain="0.6" /> + domain="0.3" /> </param> - </layer> - - <layer - name="upper_tattoo"> - <texture - local_texture="upper_tattoo" /> <param - id="1065" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_upper_red" + id="705" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="5" + name="Blush Color" + label_min="Pink" + label_max="Orange" value_min="0" value_max="1" - value_default="1"> + value_default=".5" + camera_distance=".3" + camera_elevation=".07" + camera_angle="20"> <param_color> <value - color="0, 0, 0, 255" /> + color="253,162,193,200" /> <value - color="255, 0, 0, 255" /> - </param_color> - </param> + color="247,131,152,200" /> - <param - id="1066" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_upper_green" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="213,122,140,200" /> <value - color="0, 255, 0, 255" /> + color="253,152,144,200" /> + + <value + color="236,138,103,200" /> + + <value + color="195,128,122,200" /> + + <value + color="148,103,100,200" /> + + <value + color="168,95,62,200" /> </param_color> </param> <param - id="1067" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_upper_blue" + id="711" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="6" + name="Blush Opacity" + label_min="Clear" + label_max="Opaque" value_min="0" value_max="1" - value_default="1"> - <param_color> + value_default=".5" + camera_distance=".3" + camera_elevation=".07" + camera_angle="20"> + <param_color + operation="multiply"> <value - color="0, 0, 0, 255" /> + color="255,255,255,0" /> <value - color="0, 0, 255, 255" /> + color="255,255,255,255" /> </param_color> </param> - </layer> - <layer - name="upper_undershirt bump" - render_pass="bump" - fixed_color="128,128,128,255"> - <texture - local_texture="upper_undershirt" - local_texture_alpha_only="true" /> - - <param - id="1043" - group="1" - wearable="undershirt" - edit_group="driven" - name="Sleeve Length bump" - value_min=".01" - value_max="1" - value_default=".4"> - <param_alpha - tga_file="shirt_sleeve_alpha.tga" - multiply_blend="false" - domain="0.01" /> - </param> - + name="Outer Eye Shadow"> <param - id="1045" - group="1" - wearable="undershirt" - edit_group="undershirt" - edit_group_order="2" - name="Bottom bump" + id="708" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="11" + name="Out Shdw Color" + label_min="Light" + label_max="Dark" value_min="0" value_max="1" - value_default=".8"> - <param_alpha - tga_file="shirt_bottom_alpha.tga" - multiply_blend="true" - domain="0.05" /> + camera_distance=".3" + camera_elevation=".14"> + <param_color> + <value + color="252,247,246,255" /> + + <value + color="255,206,206,255" /> + + <value + color="233,135,149,255" /> + + <value + color="220,168,192,255" /> + + <value + color="228,203,232,255" /> + + <value + color="255,234,195,255" /> + + <value + color="230,157,101,255" /> + + <value + color="255,147,86,255" /> + + <value + color="228,110,89,255" /> + + <value + color="228,150,120,255" /> + + <value + color="223,227,213,255" /> + + <value + color="96,116,87,255" /> + + <value + color="88,143,107,255" /> + + <value + color="194,231,223,255" /> + + <value + color="207,227,234,255" /> + + <value + color="41,171,212,255" /> + + <value + color="180,137,130,255" /> + + <value + color="173,125,105,255" /> + + <value + color="144,95,98,255" /> + + <value + color="115,70,77,255" /> + + <value + color="155,78,47,255" /> + + <value + color="239,239,239,255" /> + + <value + color="194,194,194,255" /> + + <value + color="120,120,120,255" /> + + <value + color="10,10,10,255" /> + </param_color> </param> <param - id="1047" - group="1" - wearable="undershirt" - edit_group="driven" - name="Collar Front bump" - value_min="0" + id="706" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="12" + name="Out Shdw Opacity" + label_min="Clear" + label_max="Opaque" + value_min=".2" value_max="1" - value_default=".8"> - <param_alpha - tga_file="shirt_collar_alpha.tga" - multiply_blend="true" - domain="0.05" /> + value_default=".6" + camera_distance=".3" + camera_elevation=".14"> + <param_color + operation="multiply"> + <value + color="255,255,255,0" /> + + <value + color="255,255,255,255" /> + </param_color> </param> <param - id="1049" - group="1" - wearable="undershirt" - edit_group="driven" - name="Collar Back bump" + id="707" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="10" + name="Outer Shadow" + label_min="No Eyeshadow" + label_max="More Eyeshadow" value_min="0" - value_max="1" - value_default=".8"> + value_max=".7" + camera_distance=".3" + camera_elevation=".14"> <param_alpha - tga_file="shirt_collar_back_alpha.tga" - multiply_blend="true" + tga_file="eyeshadow_outer_alpha.tga" + skip_if_zero="true" domain="0.05" /> </param> </layer> <layer - name="upper_undershirt"> - <texture - local_texture="upper_undershirt" /> - + name="Inner Eye Shadow"> <param - id="821" + id="712" group="0" - wearable="undershirt" - edit_group="colorpicker" - name="undershirt_red" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="8" + name="In Shdw Color" + label_min="Light" + label_max="Dark" value_min="0" value_max="1" - value_default="1"> + camera_distance=".3" + camera_elevation=".14"> <param_color> <value - color="0, 0, 0, 255" /> + color="252,247,246,255" /> <value - color="255, 0, 0, 255" /> - </param_color> - </param> + color="255,206,206,255" /> - <param - id="822" - group="0" - wearable="undershirt" - edit_group="colorpicker" - name="undershirt_green" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="233,135,149,255" /> <value - color="0, 255, 0, 255" /> - </param_color> - </param> + color="220,168,192,255" /> - <param - id="823" - group="0" - wearable="undershirt" - edit_group="colorpicker" - name="undershirt_blue" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="228,203,232,255" /> <value - color="0, 0, 255, 255" /> - </param_color> - </param> + color="255,234,195,255" /> - <param - id="1042" - group="1" - wearable="undershirt" - edit_group="driven" - name="Sleeve Length" - value_min=".01" - value_max="1" - value_default=".4"> - <param_alpha - tga_file="shirt_sleeve_alpha.tga" - multiply_blend="false" - domain="0.01" /> - </param> + <value + color="230,157,101,255" /> - <param - id="1044" - group="1" - wearable="undershirt" - edit_group="driven" - name="Bottom" - value_min="0" - value_max="1" - value_default=".8"> - <param_alpha - tga_file="shirt_bottom_alpha.tga" - multiply_blend="true" - domain="0.05" /> + <value + color="255,147,86,255" /> + + <value + color="228,110,89,255" /> + + <value + color="228,150,120,255" /> + + <value + color="223,227,213,255" /> + + <value + color="96,116,87,255" /> + + <value + color="88,143,107,255" /> + + <value + color="194,231,223,255" /> + + <value + color="207,227,234,255" /> + + <value + color="41,171,212,255" /> + + <value + color="180,137,130,255" /> + + <value + color="173,125,105,255" /> + + <value + color="144,95,98,255" /> + + <value + color="115,70,77,255" /> + + <value + color="155,78,47,255" /> + + <value + color="239,239,239,255" /> + + <value + color="194,194,194,255" /> + + <value + color="120,120,120,255" /> + + <value + color="10,10,10,255" /> + </param_color> </param> <param - id="1046" - group="1" - wearable="undershirt" - edit_group="driven" - name="Collar Front" - value_min="0" + id="713" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="9" + name="In Shdw Opacity" + label_min="Clear" + label_max="Opaque" + value_min=".2" value_max="1" - value_default=".8"> - <param_alpha - tga_file="shirt_collar_alpha.tga" - multiply_blend="true" - domain="0.05" /> + value_default=".7" + camera_distance=".3" + camera_elevation=".14"> + <param_color + operation="multiply"> + <value + color="255,255,255,0" /> + + <value + color="255,255,255,255" /> + </param_color> </param> <param - id="1048" - group="1" - wearable="undershirt" - edit_group="driven" - name="Collar Back" - label_min="Low" - label_max="High" + id="709" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="7" + name="Inner Shadow" + label_min="No Eyeshadow" + label_max="More Eyeshadow" value_min="0" value_max="1" - value_default=".8"> + value_default="0" + camera_distance=".3" + camera_elevation=".14"> <param_alpha - tga_file="shirt_collar_back_alpha.tga" - multiply_blend="true" - domain="0.05" /> + tga_file="eyeshadow_inner_alpha.tga" + skip_if_zero="true" + domain="0.2" /> </param> </layer> <layer - name="Nail Polish"> + name="eyeliner" + fixed_color="0,0,0,200"> <param - id="710" + id="703" group="0" wearable="skin" edit_group="skin_makeup" - edit_group_order="15" - name="Nail Polish" - label_min="No Polish" - label_max="Painted Nails" + edit_group_order="13" + name="Eyeliner" + label_min="No Eyeliner" + label_max="Full Eyeliner" value_min="0" value_max="1" value_default="0.0" - camera_distance="1.6" - camera_elevation="-.4" - camera_angle="70"> + camera_distance=".3" + camera_elevation=".14"> <param_alpha - tga_file="nailpolish_alpha.tga" + tga_file="eyeliner_alpha.tga" skip_if_zero="true" domain="0.1" /> </param> <param - id="715" + id="714" group="0" wearable="skin" edit_group="skin_makeup" - edit_group_order="16" - name="Nail Polish Color" - label_min="Pink" + edit_group_order="14" + name="Eyeliner Color" + label_min="Dark Green" label_max="Black" value_min="0" value_max="1" - camera_distance="1.6" - camera_elevation="-.4" - camera_angle="70"> + camera_distance=".3" + camera_elevation=".14"> <param_color> <value - color="255,187,200,255" /> + color="24,98,40,250" /> + <!-- dark green --> <value - color="194,102,127,255" /> + color="9,100,127,250" /> + <!-- lt.aqua blue --> <value - color="227,34,99,255" /> + color="61,93,134,250" /> + <!-- aqua --> <value - color="168,41,60,255" /> + color="70,29,27,250" /> + <!-- dark brown --> <value - color="97,28,59,255" /> + color="115,75,65,250" /> + <!-- lt. brown blue --> <value - color="234,115,93,255" /> + color="100,100,100,250" /> + <!-- grey --> <value - color="142,58,47,255" /> + color="91,80,74,250" /> + <!-- grey/brown --> <value - color="114,30,46,255" /> + color="112,42,76,250" /> + <!-- plum --> <value - color="14,14,14,255" /> + color="14,14,14,250" /> + + <!-- black --> </param_color> </param> </layer> <layer - name="upper_gloves bump" - render_pass="bump" - fixed_color="128,128,128,255"> + name="facialhair bump" + render_pass="bump"> <texture - local_texture="upper_gloves" - local_texture_alpha_only="true" /> + tga_file="head_hair.tga" + file_is_mask="false" /> <param - id="1059" + id="1004" + sex="male" group="1" - wearable="gloves" + wearable="hair" edit_group="driven" - name="Glove Length bump" - value_min=".01" - value_max="1" - value_default=".8"> + name="Sideburns bump" + value_min="0" + value_max="1"> <param_alpha - tga_file="glove_length_alpha.tga" - domain="0.01" /> + tga_file="facehair_sideburns_alpha.tga" + skip_if_zero="true" + domain="0.05" /> </param> <param - id="1061" + id="1006" + sex="male" group="1" - wearable="gloves" + wearable="hair" edit_group="driven" - name="Glove Fingers bump" - value_min=".01" - value_max="1" - value_default="1"> + name="Moustache bump" + value_min="0" + value_max="1"> <param_alpha - tga_file="gloves_fingers_alpha.tga" - multiply_blend="true" - domain="0.01" /> + tga_file="facehair_moustache_alpha.tga" + skip_if_zero="true" + domain="0.05" /> </param> - </layer> - - <layer - name="upper_gloves"> - <texture - local_texture="upper_gloves" /> <param - id="827" - group="0" - wearable="gloves" - edit_group="colorpicker" - name="gloves_red" - value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="255, 0, 0, 255" /> - </param_color> - </param> - - <param - id="829" - group="0" - wearable="gloves" - edit_group="colorpicker" - name="gloves_green" - value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 255, 0, 255" /> - </param_color> - </param> - - <param - id="830" - group="0" - wearable="gloves" - edit_group="colorpicker" - name="gloves_blue" - value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 0, 255, 255" /> - </param_color> - </param> - - <param - id="1058" + id="1008" + sex="male" group="1" - wearable="gloves" + wearable="hair" edit_group="driven" - name="Glove Length" - value_min=".01" - value_max="1" - value_default=".8"> + name="Soulpatch bump" + value_min="0" + value_max="1"> <param_alpha - tga_file="glove_length_alpha.tga" - domain="0.01" /> + tga_file="facehair_soulpatch_alpha.tga" + skip_if_zero="true" + domain="0.1" /> </param> <param - id="1060" + id="1010" + sex="male" group="1" - wearable="gloves" edit_group="driven" - name="Glove Fingers" - value_min=".01" - value_max="1" - value_default="1"> + wearable="hair" + name="Chin Curtains bump" + value_min="0" + value_max="1"> <param_alpha - tga_file="gloves_fingers_alpha.tga" - multiply_blend="true" - domain="0.01" /> + tga_file="facehair_chincurtains_alpha.tga" + skip_if_zero="true" + domain="0.03" /> </param> - </layer> - - <layer - name="upper_clothes_shadow"> - <texture - local_texture="upper_shirt" /> <param - id="899" + id="1012" group="1" + sex="male" + wearable="hair" edit_group="driven" - wearable="shirt" - name="Upper Clothes Shading" + name="5 O'Clock Shadow bump" value_min="0" - value_max="1" - value_default="0"> + value_max="1"> <param_color> <value - color="0, 0, 0, 0" /> + color="255,255,255,255" /> <value - color="0, 0, 0, 80" /> + color="255,255,255,0" /> </param_color> </param> + </layer> + + <layer + name="facialhair" + global_color="hair_color"> + + <texture + tga_file="head_hair.tga" + file_is_mask="false" /> <param - id="900" + id="1005" + sex="male" group="1" - wearable="shirt" + wearable="hair" edit_group="driven" - name="Sleeve Length Shadow" - value_min="0.02" - value_max=".87" - value_default="0.02"> + name="Sideburns" + value_min="0" + value_max="1"> <param_alpha - multiply_blend="false" - tga_file="shirt_sleeve_alpha.tga" + tga_file="facehair_sideburns_alpha.tga" skip_if_zero="true" - domain="0.03" /> + domain="0.05" /> </param> <param - id="901" + id="1007" + sex="male" group="1" - wearable="shirt" + wearable="hair" edit_group="driven" - name="Shirt Shadow Bottom" - value_min="0.02" + name="Moustache" + value_min="0" value_max="1"> <param_alpha - multiply_blend="true" - tga_file="shirt_bottom_alpha.tga" + tga_file="facehair_moustache_alpha.tga" skip_if_zero="true" domain="0.05" /> </param> <param - id="902" + id="1009" + sex="male" group="1" - wearable="shirt" + wearable="hair" edit_group="driven" - name="Collar Front Shadow Height" - value_min="0.02" + name="Soulpatch" + value_min="0" value_max="1"> <param_alpha - multiply_blend="true" - tga_file="shirt_collar_alpha.tga" + tga_file="facehair_soulpatch_alpha.tga" skip_if_zero="true" - domain="0.02" /> + domain="0.1" /> </param> <param - id="903" + id="1011" + sex="male" group="1" - wearable="shirt" + wearable="hair" edit_group="driven" - name="Collar Back Shadow Height" - value_min="0.02" + name="Chin Curtains" + value_min="0" value_max="1"> <param_alpha - multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" + tga_file="facehair_chincurtains_alpha.tga" skip_if_zero="true" - domain="0.02" /> + domain="0.03" /> </param> - </layer> - - <layer - name="upper_shirt base bump" - render_pass="bump" - fixed_color="128,128,128,255"> - <texture - local_texture="upper_shirt" - local_texture_alpha_only="true" /> <param - id="1029" + id="751" group="1" - wearable="shirt" - edit_group="driven" - name="Sleeve Length Cloth" + wearable="hair" + sex="male" + edit_group="hair_facial" + name="5 O'Clock Shadow" + label_min="Dense hair" + label_max="Shadow hair" value_min="0" - value_max="0.85"> - <param_alpha - multiply_blend="false" - tga_file="shirt_sleeve_alpha.tga" - domain="0.01" /> + value_max="1" + value_default="0.7" + camera_elevation=".1" + camera_distance=".3"> + <param_color + operation="multiply"> + <value + color="255,255,255,255" /> + + <value + color="255,255,255,30" /> + </param_color> </param> + </layer> + <layer + name="head_bodypaint"> + <texture + local_texture="head_bodypaint" /> + </layer> + <layer + name="eyelash alpha" + visibility_mask="TRUE"> + <texture + tga_file="head_alpha.tga" + file_is_mask="TRUE" /> + </layer> + <layer + name="head alpha" + visibility_mask="TRUE"> + <texture + local_texture="head_alpha" /> + </layer> + <layer + name="head_tattoo"> + <texture + local_texture="head_tattoo" /> <param - id="1030" + id="1062" group="1" - wearable="shirt" - edit_group="driven" - name="Shirt Bottom Cloth" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_head_red" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_bottom_alpha.tga" - domain="0.05" /> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> </param> <param - id="1031" + id="1063" group="1" - wearable="shirt" - edit_group="driven" - name="Collar Front Height Cloth" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_head_green" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_collar_alpha.tga" - domain="0.05" /> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> </param> <param - id="1032" + id="1064" group="1" - wearable="shirt" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_head_blue" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> + </param> + + </layer> + + + </layer_set> + + <!-- =========================================================== --> + <layer_set + body_region="upper_body" + width="512" + height="512"> + <layer + name="base_upperbody bump" + render_pass="bump" + fixed_color="128,128,128,255"> + </layer> + <layer + name="upperbody bump definition" + render_pass="bump"> + <texture + tga_file="bump_upperbody_base.tga" + file_is_mask="FALSE"/> + + <param + id="874" + group="1" + wearable="skin" edit_group="driven" - name="Collar Back Height Cloth" + edit_group_order="20" + name="Bump upperdef" value_min="0" value_max="1"> <param_alpha - multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" - domain="0.05" /> + domain="0" /> </param> </layer> <layer - name="upper_clothes bump" - render_pass="bump"> + name="base" + global_color="skin_color"> <texture - tga_file="bump_shirt_wrinkles.tga" /> + tga_file="body_skingrain.tga" /> + </layer> + <layer + name="nipples"> <texture - local_texture="upper_shirt" - local_texture_alpha_only="true" /> + tga_file="upperbody_color.tga" /> + </layer> + + <layer + name="shadow"> + <texture + tga_file="upperbody_shading_alpha.tga" + file_is_mask="TRUE" /> <param - id="868" - group="3" - wearable="shirt" - edit_group="shirt" - edit_group_order="8" - name="Shirt Wrinkles" + id="125" + group="1" + name="Shading" + wearable="skin" value_min="0" - value_max="1" - value_default="0"> + value_max="1"> <param_color> <value - color="255, 255, 255, 0" /> + color="0, 0, 0, 0" /> <value - color="255, 255, 255, 255" /> + color="0, 0, 0, 128" /> </param_color> </param> + </layer> - <param - id="1013" - group="1" - wearable="shirt" - edit_group="driven" - name="Sleeve Length Cloth" - value_min="0" - value_max="0.85"> - <param_alpha - multiply_blend="false" - tga_file="shirt_sleeve_alpha.tga" - domain="0.01" /> - </param> + <layer + name="highlight"> + <texture + tga_file="upperbody_highlights_alpha.tga" + file_is_mask="TRUE" /> <param - id="1014" + id="126" group="1" - wearable="shirt" - edit_group="driven" - name="Shirt Bottom Cloth" + wearable="skin" + name="Shading" value_min="0" value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_bottom_alpha.tga" - domain="0.05" /> - </param> + <param_color> + <value + color="255, 255, 255, 0" /> - <param - id="1015" - group="1" - wearable="shirt" - edit_group="driven" - name="Collar Front Height Cloth" - value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_collar_alpha.tga" - domain="0.05" /> + <value + color="255, 255, 255, 64" /> + </param_color> </param> + </layer> + + <layer + name="upper_bodypaint"> + <texture + local_texture="upper_bodypaint" /> + </layer> + <layer + name="freckles upper" + fixed_color="120,47,20,128"> <param - id="1016" + id="776" group="1" - wearable="shirt" - edit_group="driven" - name="Collar Back Height Cloth" + name="freckles upper" + wearable="skin" value_min="0" value_max="1"> <param_alpha - multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" - domain="0.05" /> + tga_file="upperbodyfreckles_alpha.tga" + skip_if_zero="true" + domain="0.6" /> </param> </layer> <layer - name="upper_clothes"> + name="upper_tattoo"> <texture - local_texture="upper_shirt" /> + local_texture="upper_tattoo" /> <param - id="803" - group="0" - wearable="shirt" - edit_group="colorpicker" - name="shirt_red" + id="1065" + group="1" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_upper_red" value_min="0" value_max="1" value_default="1"> @@ -7812,11 +9788,11 @@ render_pass="bump"> </param> <param - id="804" - group="0" - wearable="shirt" - edit_group="colorpicker" - name="shirt_green" + id="1066" + group="1" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_upper_green" value_min="0" value_max="1" value_default="1"> @@ -7830,11 +9806,11 @@ render_pass="bump"> </param> <param - id="805" - group="0" - wearable="shirt" - edit_group="colorpicker" - name="shirt_blue" + id="1067" + group="1" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_upper_blue" value_min="0" value_max="1" value_default="1"> @@ -7847,623 +9823,643 @@ render_pass="bump"> </param_color> </param> + </layer> + + + <layer + name="upper_undershirt bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="upper_undershirt" + local_texture_alpha_only="true" /> + <param - id="600" + id="1043" group="1" - wearable="shirt" + wearable="undershirt" edit_group="driven" - name="Sleeve Length Cloth" - value_min="0" - value_max="0.85" - value_default=".7"> + name="Sleeve Length bump" + value_min=".01" + value_max="1" + value_default=".4"> <param_alpha - multiply_blend="false" tga_file="shirt_sleeve_alpha.tga" + multiply_blend="false" domain="0.01" /> </param> <param - id="601" + id="1045" group="1" - wearable="shirt" - edit_group="driven" - name="Shirt Bottom Cloth" + wearable="undershirt" + edit_group="undershirt" + edit_group_order="2" + name="Bottom bump" value_min="0" value_max="1" value_default=".8"> <param_alpha - multiply_blend="true" tga_file="shirt_bottom_alpha.tga" + multiply_blend="true" domain="0.05" /> </param> <param - id="602" + id="1047" group="1" - wearable="shirt" + wearable="undershirt" edit_group="driven" - name="Collar Front Height Cloth" + name="Collar Front bump" value_min="0" value_max="1" value_default=".8"> <param_alpha - multiply_blend="true" tga_file="shirt_collar_alpha.tga" + multiply_blend="true" domain="0.05" /> </param> <param - id="778" + id="1049" group="1" - wearable="shirt" + wearable="undershirt" edit_group="driven" - name="Collar Back Height Cloth" + name="Collar Back bump" value_min="0" value_max="1" value_default=".8"> <param_alpha - multiply_blend="true" tga_file="shirt_collar_back_alpha.tga" + multiply_blend="true" domain="0.05" /> </param> </layer> <layer - name="upper_jacket base bump" - render_pass="bump" - fixed_color="128,128,128,255"> + name="upper_undershirt"> <texture - local_texture="upper_jacket" - local_texture_alpha_only="true" /> + local_texture="upper_undershirt" /> <param - id="1039" - group="1" - wearable="jacket" - edit_group="driven" - edit_group_order="1" - name="Jacket Sleeve Length bump" + id="821" + group="0" + wearable="undershirt" + edit_group="colorpicker" + name="undershirt_red" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="false" - tga_file="shirt_sleeve_alpha.tga" - domain="0.01" /> - </param> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> - <param - id="1040" - group="1" - wearable="jacket" - edit_group="driven" - name="Jacket Collar Front bump" - value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_collar_alpha.tga" - domain="0.05" /> + <value + color="255, 0, 0, 255" /> + </param_color> </param> <param - id="1041" - group="1" - wearable="jacket" - edit_group="driven" - edit_group_order="3.5" - name="Jacket Collar Back bump" + id="822" + group="0" + wearable="undershirt" + edit_group="colorpicker" + name="undershirt_green" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" - domain="0.05" /> - </param> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> - <param - id="1037" - group="1" - wearable="jacket" - edit_group="driven" - name="jacket bottom length upper bump" - value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="jacket_length_upper_alpha.tga" - domain="0.01" /> + <value + color="0, 255, 0, 255" /> + </param_color> </param> <param - id="1038" - group="1" - wearable="jacket" - edit_group="driven" - name="jacket open upper bump" + id="823" + group="0" + wearable="undershirt" + edit_group="colorpicker" + name="undershirt_blue" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="jacket_open_upper_alpha.tga" - domain="0.01" /> - </param> - </layer> - - <layer - name="upper_jacket bump" - render_pass="bump"> - <texture - tga_file="bump_shirt_wrinkles.tga" /> - - <texture - local_texture="upper_jacket" - local_texture_alpha_only="true" /> - - - <param - id="875" - group="1" - wearable="jacket" - name="jacket upper Wrinkles" - value_min="0" - value_max="1" - value_default="0"> + value_max="1" + value_default="1"> <param_color> <value - color="255, 255, 255, 0" /> + color="0, 0, 0, 255" /> <value - color="255, 255, 255, 255" /> + color="0, 0, 255, 255" /> </param_color> </param> <param - id="1019" + id="1042" group="1" - wearable="jacket" + wearable="undershirt" edit_group="driven" - edit_group_order="1" - name="Jacket Sleeve Length bump" - value_min="0" - value_max="1"> + name="Sleeve Length" + value_min=".01" + value_max="1" + value_default=".4"> <param_alpha - multiply_blend="false" tga_file="shirt_sleeve_alpha.tga" + multiply_blend="false" domain="0.01" /> </param> <param - id="1021" + id="1044" group="1" - wearable="jacket" + wearable="undershirt" edit_group="driven" - name="Jacket Collar Front bump" + name="Bottom" value_min="0" - value_max="1"> + value_max="1" + value_default=".8"> <param_alpha + tga_file="shirt_bottom_alpha.tga" multiply_blend="true" - tga_file="shirt_collar_alpha.tga" domain="0.05" /> </param> <param - id="1023" + id="1046" group="1" - wearable="jacket" + wearable="undershirt" edit_group="driven" - edit_group_order="3.5" - name="Jacket Collar Back bump" + name="Collar Front" value_min="0" - value_max="1"> + value_max="1" + value_default=".8"> <param_alpha + tga_file="shirt_collar_alpha.tga" multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" domain="0.05" /> </param> <param - id="1025" + id="1048" group="1" - wearable="jacket" + wearable="undershirt" edit_group="driven" - name="jacket bottom length upper bump" + name="Collar Back" + label_min="Low" + label_max="High" value_min="0" - value_max="1"> + value_max="1" + value_default=".8"> <param_alpha + tga_file="shirt_collar_back_alpha.tga" multiply_blend="true" - tga_file="jacket_length_upper_alpha.tga" - domain="0.01" /> + domain="0.05" /> </param> + </layer> + <layer + name="Nail Polish"> <param - id="1026" - group="1" - wearable="jacket" - edit_group="driven" - name="jacket open upper bump" + id="710" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="15" + name="Nail Polish" + label_min="No Polish" + label_max="Painted Nails" value_min="0" - value_max="1"> + value_max="1" + value_default="0.0" + camera_distance="1.6" + camera_elevation="-.4" + camera_angle="70"> <param_alpha - multiply_blend="true" - tga_file="jacket_open_upper_alpha.tga" - domain="0.01" /> + tga_file="nailpolish_alpha.tga" + skip_if_zero="true" + domain="0.1" /> </param> - </layer> - - <layer - name="upper_jacket"> - <texture - local_texture="upper_jacket" /> <param - id="831" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="upper_jacket_red" + id="715" + group="0" + wearable="skin" + edit_group="skin_makeup" + edit_group_order="16" + name="Nail Polish Color" + label_min="Pink" + label_max="Black" value_min="0" value_max="1" - value_default="1"> + camera_distance="1.6" + camera_elevation="-.4" + camera_angle="70"> <param_color> <value - color="0, 0, 0, 255" /> + color="255,187,200,255" /> <value - color="255, 0, 0, 255" /> - </param_color> - </param> + color="194,102,127,255" /> - <param - id="832" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="upper_jacket_green" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="227,34,99,255" /> <value - color="0, 255, 0, 255" /> - </param_color> - </param> + color="168,41,60,255" /> - <param - id="833" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="upper_jacket_blue" - value_min="0" - value_max="1" - value_default="1"> - <param_color> <value - color="0, 0, 0, 255" /> + color="97,28,59,255" /> <value - color="0, 0, 255, 255" /> + color="234,115,93,255" /> + + <value + color="142,58,47,255" /> + + <value + color="114,30,46,255" /> + + <value + color="14,14,14,255" /> </param_color> </param> + </layer> + + <layer + name="upper_gloves bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="upper_gloves" + local_texture_alpha_only="true" /> <param - id="1020" + id="1059" group="1" - edit_group="driven" - wearable="jacket" - name="jacket Sleeve Length" value_min="0" - value_max="1"> + wearable="gloves" + edit_group="driven" + name="Glove Length bump" + value_min=".01" + value_max="1" + value_default=".8"> <param_alpha - multiply_blend="false" - tga_file="shirt_sleeve_alpha.tga" + tga_file="glove_length_alpha.tga" domain="0.01" /> </param> <param - id="1022" + id="1061" group="1" - wearable="jacket" + wearable="gloves" edit_group="driven" - name="jacket Collar Front" - value_min="0" - value_max="1"> + name="Glove Fingers bump" + value_min=".01" + value_max="1" + value_default="1"> <param_alpha + tga_file="gloves_fingers_alpha.tga" multiply_blend="true" - tga_file="shirt_collar_alpha.tga" - domain="0.05" /> + domain="0.01" /> </param> + </layer> + + <layer + name="upper_gloves"> + <texture + local_texture="upper_gloves" /> <param - id="1024" - group="1" - wearable="jacket" - edit_group="driven" - edit_group_order="3.5" - name="jacket Collar Back" + id="827" + group="0" + wearable="gloves" + edit_group="colorpicker" + name="gloves_red" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="shirt_collar_back_alpha.tga" - domain="0.05" /> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> </param> <param - id="620" - group="1" - wearable="jacket" - edit_group="jacket" - name="bottom length upper" - label_min="hi cut" - label_max="low cut" + id="829" + group="0" + wearable="gloves" + edit_group="colorpicker" + name="gloves_green" value_min="0" value_max="1" - value_default=".8" - camera_distance="1.2" - camera_angle="30" - camera_elevation=".2"> - <param_alpha - multiply_blend="true" - tga_file="jacket_length_upper_alpha.tga" - domain="0.01" /> + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> </param> <param - id="622" - group="1" - wearable="jacket" - edit_group="jacket" - name="open upper" - label_min="closed" - label_max="open" + id="830" + group="0" + wearable="gloves" + edit_group="colorpicker" + name="gloves_blue" value_min="0" value_max="1" - value_default=".8" - camera_distance="1.2" - camera_angle="30" - camera_elevation=".2"> + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> + </param> + + <param + id="1058" + group="1" + wearable="gloves" + edit_group="driven" + name="Glove Length" + value_min=".01" + value_max="1" + value_default=".8"> <param_alpha - multiply_blend="true" - tga_file="jacket_open_upper_alpha.tga" + tga_file="glove_length_alpha.tga" domain="0.01" /> </param> - </layer> - - <layer - name="upper alpha" - visibility_mask="TRUE"> - <texture - local_texture="upper_alpha" /> - </layer> - - </layer_set> - - <!-- =========================================================== --> - <layer_set - body_region="lower_body" - width="512" - height="512"> - <layer - name="lower body bump base" - fixed_color = "128,128,128,255" - render_pass="bump"> - </layer> - <layer - name="base_lowerbody bump" - render_pass="bump"> - <texture - tga_file="bump_lowerbody_base.tga" - file_is_mask="FALSE" /> <param - id="878" + id="1060" group="1" - wearable="skin" + wearable="gloves" edit_group="driven" - edit_group_order="20" - name="Bump upperdef" - value_min="0" - value_max="1"> + name="Glove Fingers" + value_min=".01" + value_max="1" + value_default="1"> <param_alpha - domain="0" /> + tga_file="gloves_fingers_alpha.tga" + multiply_blend="true" + domain="0.01" /> </param> </layer> <layer - name="base" - global_color="skin_color"> - <texture - tga_file="body_skingrain.tga" /> - </layer> - - <layer - name="shadow"> + name="upper_clothes_shadow"> <texture - tga_file="lowerbody_shading_alpha.tga" - file_is_mask="TRUE" /> + local_texture="upper_shirt" /> <param - id="160" + id="899" group="1" - name="Shading" - wearable="pants" - cross_wearable="true" + edit_group="driven" + wearable="shirt" + name="Upper Clothes Shading" value_min="0" - value_max="1"> + value_max="1" + value_default="0"> <param_color> <value color="0, 0, 0, 0" /> <value - color="0, 0, 0, 128" /> + color="0, 0, 0, 80" /> </param_color> </param> - </layer> - <layer - name="highlight"> - <texture - tga_file="lowerbody_highlights_alpha.tga" - file_is_mask="TRUE" /> + <param + id="900" + group="1" + wearable="shirt" + edit_group="driven" + name="Sleeve Length Shadow" + value_min="0.02" + value_max=".87" + value_default="0.02"> + <param_alpha + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" + skip_if_zero="true" + domain="0.03" /> + </param> <param - id="161" + id="901" group="1" - name="Shading" - wearable="skin" - value_min="0" + wearable="shirt" + edit_group="driven" + name="Shirt Shadow Bottom" + value_min="0.02" value_max="1"> - <param_color> - <value - color="255, 255, 255, 0" /> + <param_alpha + multiply_blend="true" + tga_file="shirt_bottom_alpha.tga" + skip_if_zero="true" + domain="0.05" /> + </param> - <value - color="255, 255, 255, 64" /> - </param_color> + <param + id="902" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Front Shadow Height" + value_min="0.02" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + skip_if_zero="true" + domain="0.02" /> </param> - </layer> - <layer - name="toenails"> - <texture - tga_file="lowerbody_color.tga" /> + <param + id="903" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Back Shadow Height" + value_min="0.02" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + skip_if_zero="true" + domain="0.02" /> + </param> </layer> <layer - name="lower_bodypaint"> + name="upper_shirt base bump" + render_pass="bump" + fixed_color="128,128,128,255"> <texture - local_texture="lower_bodypaint" /> - </layer> + local_texture="upper_shirt" + local_texture_alpha_only="true" /> - <layer - name="freckles lower" - fixed_color="120,47,20,128"> <param - id="777" + id="1029" group="1" - name="freckles lower" - wearable="skin" + wearable="shirt" + edit_group="driven" + name="Sleeve Length Cloth" + value_min="0" + value_max="0.85"> + <param_alpha + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" + domain="0.01" /> + </param> + + <param + id="1030" + group="1" + wearable="shirt" + edit_group="driven" + name="Shirt Bottom Cloth" value_min="0" value_max="1"> <param_alpha - tga_file="bodyfreckles_alpha.tga" - skip_if_zero="true" - domain="0.6" /> + multiply_blend="true" + tga_file="shirt_bottom_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1031" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Front Height Cloth" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1032" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Back Height Cloth" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> </param> </layer> <layer - name="lower_tattoo"> + name="upper_clothes bump" + render_pass="bump"> <texture - local_texture="lower_tattoo" /> + tga_file="bump_shirt_wrinkles.tga" /> + + <texture + local_texture="upper_shirt" + local_texture_alpha_only="true" /> <param - id="1068" - group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_lower_red" + id="868" + group="3" + wearable="shirt" + edit_group="shirt" + edit_group_order="8" + name="Shirt Wrinkles" value_min="0" value_max="1" - value_default="1"> + value_default="0"> <param_color> <value - color="0, 0, 0, 255" /> + color="255, 255, 255, 0" /> <value - color="255, 0, 0, 255" /> + color="255, 255, 255, 255" /> </param_color> </param> <param - id="1069" + id="1013" group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_lower_green" + wearable="shirt" + edit_group="driven" + name="Sleeve Length Cloth" value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 255, 0, 255" /> - </param_color> + value_max="0.85"> + <param_alpha + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" + domain="0.01" /> </param> <param - id="1070" + id="1014" group="1" - edit_group="colorpicker_driven" - wearable="tattoo" - name="tattoo_lower_blue" + wearable="shirt" + edit_group="driven" + name="Shirt Bottom Cloth" value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 0, 255, 255" /> - </param_color> + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_bottom_alpha.tga" + domain="0.05" /> </param> - </layer> - - <layer - name="lower_underpants bump" - render_pass="bump" - fixed_color="128,128,128,255"> - <texture - local_texture="lower_underpants" - local_texture_alpha_only="true" /> - <param - id="1055" + id="1015" group="1" - wearable="underpants" - edit_group="underpants" - name="Pants Length" + wearable="shirt" + edit_group="driven" + name="Collar Front Height Cloth" value_min="0" - value_max="1" - value_default=".3"> + value_max="1"> <param_alpha - tga_file="pants_length_alpha.tga" - domain="0.01" /> + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> </param> <param - id="1057" + id="1016" group="1" - wearable="underpants" - edit_group="underpants" - name="Pants Waist" + wearable="shirt" + edit_group="driven" + name="Collar Back Height Cloth" value_min="0" - value_max="1" - value_default=".8"> + value_max="1"> <param_alpha - tga_file="pants_waist_alpha.tga" + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" domain="0.05" /> </param> </layer> <layer - name="lower_underpants"> + name="upper_clothes"> <texture - local_texture="lower_underpants" /> + local_texture="upper_shirt" /> <param - id="824" + id="803" group="0" - wearable="underpants" + wearable="shirt" edit_group="colorpicker" - name="underpants_red" + name="shirt_red" value_min="0" value_max="1" value_default="1"> @@ -8477,11 +10473,11 @@ render_pass="bump"> </param> <param - id="825" + id="804" group="0" - wearable="underpants" + wearable="shirt" edit_group="colorpicker" - name="underpants_green" + name="shirt_green" value_min="0" value_max="1" value_default="1"> @@ -8495,11 +10491,11 @@ render_pass="bump"> </param> <param - id="826" + id="805" group="0" - wearable="underpants" + wearable="shirt" edit_group="colorpicker" - name="underpants_blue" + name="shirt_blue" value_min="0" value_max="1" value_default="1"> @@ -8513,168 +10509,259 @@ render_pass="bump"> </param> <param - id="1054" + id="600" group="1" - wearable="underpants" + wearable="shirt" edit_group="driven" - name="Pants Length" + name="Sleeve Length Cloth" value_min="0" - value_max="1" - value_default=".3" - camera_distance="1.2" - camera_angle="30" - camera_elevation="-.3"> + value_max="0.85" + value_default=".7"> <param_alpha - tga_file="pants_length_alpha.tga" + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" domain="0.01" /> </param> <param - id="1056" + id="601" group="1" - wearable="underpants" + wearable="shirt" edit_group="driven" - name="Pants Waist" + name="Shirt Bottom Cloth" value_min="0" value_max="1" value_default=".8"> <param_alpha - tga_file="pants_waist_alpha.tga" + multiply_blend="true" + tga_file="shirt_bottom_alpha.tga" + domain="0.05" /> + </param> + + <param + id="602" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Front Height Cloth" + value_min="0" + value_max="1" + value_default=".8"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + </param> + + <param + id="778" + group="1" + wearable="shirt" + edit_group="driven" + name="Collar Back Height Cloth" + value_min="0" + value_max="1" + value_default=".8"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" domain="0.05" /> </param> </layer> <layer - name="lower_socks bump" + name="upper_jacket base bump" render_pass="bump" fixed_color="128,128,128,255"> <texture - local_texture="lower_socks" + local_texture="upper_jacket" local_texture_alpha_only="true" /> <param - id="1051" + id="1039" group="1" - wearable="socks" + wearable="jacket" edit_group="driven" - name="Socks Length bump" + edit_group_order="1" + name="Jacket Sleeve Length bump" value_min="0" - value_max="1" - value_default="0.35"> + value_max="1"> <param_alpha - tga_file="shoe_height_alpha.tga" + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" + domain="0.01" /> + </param> + + <param + id="1040" + group="1" + wearable="jacket" + edit_group="driven" + name="Jacket Collar Front bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1041" + group="1" + wearable="jacket" + edit_group="driven" + edit_group_order="3.5" + name="Jacket Collar Back bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1037" + group="1" + wearable="jacket" + edit_group="driven" + name="jacket bottom length upper bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="jacket_length_upper_alpha.tga" + domain="0.01" /> + </param> + + <param + id="1038" + group="1" + wearable="jacket" + edit_group="driven" + name="jacket open upper bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="jacket_open_upper_alpha.tga" domain="0.01" /> </param> </layer> <layer - name="lower_socks"> + name="upper_jacket bump" + render_pass="bump"> <texture - local_texture="lower_socks" /> + tga_file="bump_shirt_wrinkles.tga" /> + + <texture + local_texture="upper_jacket" + local_texture_alpha_only="true" /> + <param - id="818" - group="0" - wearable="socks" - edit_group="colorpicker" - name="socks_red" - value_min="0" - value_max="1" - value_default="1"> + id="875" + group="1" + wearable="jacket" + name="jacket upper Wrinkles" + value_min="0" + value_max="1" + value_default="0"> <param_color> <value - color="0, 0, 0, 255" /> + color="255, 255, 255, 0" /> <value - color="255, 0, 0, 255" /> + color="255, 255, 255, 255" /> </param_color> </param> <param - id="819" - group="0" - wearable="socks" - edit_group="colorpicker" - name="socks_green" + id="1019" + group="1" + wearable="jacket" + edit_group="driven" + edit_group_order="1" + name="Jacket Sleeve Length bump" value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 255, 0, 255" /> - </param_color> + value_max="1"> + <param_alpha + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" + domain="0.01" /> </param> <param - id="820" - group="0" - wearable="socks" - edit_group="colorpicker" - name="socks_blue" + id="1021" + group="1" + wearable="jacket" + edit_group="driven" + name="Jacket Collar Front bump" value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + </param> - <value - color="0, 0, 255, 255" /> - </param_color> + <param + id="1023" + group="1" + wearable="jacket" + edit_group="driven" + edit_group_order="3.5" + name="Jacket Collar Back bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> </param> <param - id="1050" + id="1025" group="1" - wearable="socks" + wearable="jacket" edit_group="driven" - name="Socks Length bump" + name="jacket bottom length upper bump" value_min="0" - value_max="1" - value_default="0.35"> + value_max="1"> <param_alpha - tga_file="shoe_height_alpha.tga" + multiply_blend="true" + tga_file="jacket_length_upper_alpha.tga" domain="0.01" /> </param> - </layer> - - <layer - name="lower_shoes bump" - render_pass="bump" - fixed_color="128,128,128,255"> - <texture - local_texture="lower_shoes" - local_texture_alpha_only="true" /> <param - id="1053" + id="1026" group="1" - wearable="shoes" + wearable="jacket" edit_group="driven" - name="Shoe Height bump" + name="jacket open upper bump" value_min="0" - value_max="1" - value_default="0.1"> + value_max="1"> <param_alpha - tga_file="shoe_height_alpha.tga" + multiply_blend="true" + tga_file="jacket_open_upper_alpha.tga" domain="0.01" /> </param> </layer> <layer - name="lower_shoes"> + name="upper_jacket"> <texture - local_texture="lower_shoes" /> + local_texture="upper_jacket" /> <param - id="812" - group="0" - wearable="shoes" - edit_group="colorpicker" - name="shoes_red" + id="831" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="upper_jacket_red" value_min="0" value_max="1" value_default="1"> @@ -8688,11 +10775,11 @@ render_pass="bump"> </param> <param - id="813" - group="0" - wearable="shoes" - edit_group="colorpicker" - name="shoes_green" + id="832" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="upper_jacket_green" value_min="0" value_max="1" value_default="1"> @@ -8706,11 +10793,11 @@ render_pass="bump"> </param> <param - id="817" - group="0" - wearable="shoes" - edit_group="colorpicker" - name="shoes_blue" + id="833" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="upper_jacket_blue" value_min="0" value_max="1" value_default="1"> @@ -8724,357 +10811,320 @@ render_pass="bump"> </param> <param - id="1052" + id="1020" group="1" - wearable="shoes" - edit_group="driven" - name="Shoe Height" - value_min="0" - value_max="1" - value_default="0.1"> + edit_group="driven" + wearable="jacket" + name="jacket Sleeve Length" value_min="0" + value_max="1"> <param_alpha - tga_file="shoe_height_alpha.tga" + multiply_blend="false" + tga_file="shirt_sleeve_alpha.tga" domain="0.01" /> </param> - </layer> - - <layer - name="lower_clothes_shadow"> - <texture - local_texture="lower_pants" /> <param - id="913" + id="1022" group="1" + wearable="jacket" edit_group="driven" - wearable="pants" - name="Lower Clothes Shading" + name="jacket Collar Front" value_min="0" - value_max="1" - value_default="0"> - <param_color> - <value - color="0, 0, 0, 0" /> - - <value - color="0, 0, 0, 80" /> - </param_color> - </param> - - <param - id="914" - group="1" - edit_group="driven" - wearable="pants" - name="Waist Height Shadow" - value_min="0.02" value_max="1"> <param_alpha - tga_file="pants_waist_alpha.tga" - skip_if_zero="true" - domain="0.04" /> + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> </param> <param - id="915" + id="1024" group="1" + wearable="jacket" edit_group="driven" - wearable="pants" - name="Pants Length Shadow" - value_min="0.02" + edit_group_order="3.5" + name="jacket Collar Back" + value_min="0" value_max="1"> <param_alpha - tga_file="pants_length_alpha.tga" - skip_if_zero="true" - domain="0.03" /> + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> </param> - </layer> - - <layer - name="lower_pants base bump" - render_pass="bump" - fixed_color="128,128,128,255"> - <texture - local_texture="lower_pants" - local_texture_alpha_only="true" /> <param - id="1035" + id="620" group="1" - edit_group="driven" - wearable="pants" - name="Waist Height Cloth" + wearable="jacket" + edit_group="jacket" + name="bottom length upper" + label_min="hi cut" + label_max="low cut" value_min="0" - value_max="1"> + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> <param_alpha - tga_file="pants_waist_alpha.tga" - domain="0.05" /> + multiply_blend="true" + tga_file="jacket_length_upper_alpha.tga" + domain="0.01" /> </param> <param - id="1036" + id="622" group="1" - edit_group="driven" - wearable="pants" - name="Pants Length Cloth" + wearable="jacket" + edit_group="jacket" + name="open upper" + label_min="closed" + label_max="open" value_min="0" - value_max="1"> + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> <param_alpha - tga_file="pants_length_alpha.tga" + multiply_blend="true" + tga_file="jacket_open_upper_alpha.tga" domain="0.01" /> </param> </layer> <layer - name="lower_pants bump" - render_pass="bump"> - <texture - tga_file="bump_pants_wrinkles.tga" /> - + name="upper alpha" + visibility_mask="TRUE"> <texture - local_texture="lower_pants" - local_texture_alpha_only="true" /> + local_texture="upper_alpha" /> + </layer> - <param - id="869" - group="3" - wearable="pants" - edit_group="pants" - edit_group_order="6" - name="Pants Wrinkles" - value_min="0" - value_max="1" - value_default="0"> - <param_color> - <value - color="255, 255, 255, 0" /> + </layer_set> - <value - color="255, 255, 255, 255" /> - </param_color> - </param> + <!-- =========================================================== --> + <layer_set + body_region="lower_body" + width="512" + height="512"> + <layer + name="lower body bump base" + fixed_color = "128,128,128,255" + render_pass="bump"> + </layer> + <layer + name="base_lowerbody bump" + render_pass="bump"> + <texture + tga_file="bump_lowerbody_base.tga" + file_is_mask="FALSE" /> <param - id="1017" + id="878" group="1" + wearable="skin" edit_group="driven" - wearable="pants" - name="Waist Height Cloth" + edit_group_order="20" + name="Bump upperdef" value_min="0" value_max="1"> <param_alpha - tga_file="pants_waist_alpha.tga" - domain="0.05" /> + domain="0" /> </param> + </layer> - <param - id="1018" - group="1" - edit_group="driven" - wearable="pants" - name="Pants Length Cloth" - value_min="0" - value_max="1"> - <param_alpha - tga_file="pants_length_alpha.tga" - domain="0.01" /> - </param> + <layer + name="base" + global_color="skin_color"> + <texture + tga_file="body_skingrain.tga" /> </layer> <layer - name="lower_pants"> + name="shadow"> <texture - local_texture="lower_pants" /> + tga_file="lowerbody_shading_alpha.tga" + file_is_mask="TRUE" /> <param - id="806" - group="0" + id="160" + group="1" + name="Shading" wearable="pants" - edit_group="colorpicker" - name="pants_red" + cross_wearable="true" value_min="0" - value_max="1" - value_default="1"> + value_max="1"> <param_color> <value - color="0, 0, 0, 255" /> + color="0, 0, 0, 0" /> <value - color="255, 0, 0, 255" /> + color="0, 0, 0, 128" /> </param_color> </param> + </layer> + + <layer + name="highlight"> + <texture + tga_file="lowerbody_highlights_alpha.tga" + file_is_mask="TRUE" /> <param - id="807" - group="0" - wearable="pants" - edit_group="colorpicker" - name="pants_green" + id="161" + group="1" + name="Shading" + wearable="skin" value_min="0" - value_max="1" - value_default="1"> + value_max="1"> <param_color> <value - color="0, 0, 0, 255" /> + color="255, 255, 255, 0" /> <value - color="0, 255, 0, 255" /> + color="255, 255, 255, 64" /> </param_color> </param> + </layer> - <param - id="808" - group="0" - wearable="pants" - edit_group="colorpicker" - name="pants_blue" - value_min="0" - value_max="1" - value_default="1"> - <param_color> - <value - color="0, 0, 0, 255" /> - - <value - color="0, 0, 255, 255" /> - </param_color> - </param> + <layer + name="toenails"> + <texture + tga_file="lowerbody_color.tga" /> + </layer> - <param - id="614" - group="1" - edit_group="driven" - wearable="pants" - name="Waist Height Cloth" - value_min="0" - value_max="1" - value_default=".8"> - <param_alpha - tga_file="pants_waist_alpha.tga" - domain="0.05" /> - </param> + <layer + name="lower_bodypaint"> + <texture + local_texture="lower_bodypaint" /> + </layer> + <layer + name="freckles lower" + fixed_color="120,47,20,128"> <param - id="615" + id="777" group="1" - edit_group="driven" - wearable="pants" - name="Pants Length Cloth" + name="freckles lower" + wearable="skin" value_min="0" - value_max="1" - value_default=".8"> + value_max="1"> <param_alpha - tga_file="pants_length_alpha.tga" - domain="0.01" /> + tga_file="bodyfreckles_alpha.tga" + skip_if_zero="true" + domain="0.6" /> </param> </layer> <layer - name="lower_jacket base bump" - render_pass="bump" - fixed_color="128,128,128,255"> + name="lower_tattoo"> <texture - local_texture="lower_jacket" - local_texture_alpha_only="true" /> + local_texture="lower_tattoo" /> <param - id="1033" + id="1068" group="1" - wearable="jacket" - edit_group="driven" - cross_wearable="true" - name="jacket bottom length lower bump" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_lower_red" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="false" - tga_file="jacket_length_lower_alpha.tga" - domain="0.01" /> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> </param> <param - id="1034" + id="1069" group="1" - wearable="jacket" - edit_group="driven" - name="jacket open lower bump" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_lower_green" value_min="0" - value_max="1"> - <param_alpha - multiply_blend="true" - tga_file="jacket_open_lower_alpha.tga" - domain="0.01" /> - </param> - </layer> - - <layer - name="lower_jacket bump" - render_pass="bump"> - <texture - tga_file="bump_pants_wrinkles.tga" /> + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> - <texture - local_texture="lower_jacket" - local_texture_alpha_only="true" /> - + <value + color="0, 255, 0, 255" /> + </param_color> + </param> <param - id="876" + id="1070" group="1" - wearable="jacket" - name="jacket upper Wrinkles" + edit_group="colorpicker_driven" + wearable="tattoo" + name="tattoo_lower_blue" value_min="0" value_max="1" - value_default="0"> + value_default="1"> <param_color> <value - color="255, 255, 255, 0" /> + color="0, 0, 0, 255" /> <value - color="255, 255, 255, 255" /> + color="0, 0, 255, 255" /> </param_color> </param> + </layer> + + <layer + name="lower_underpants bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="lower_underpants" + local_texture_alpha_only="true" /> + <param - id="1027" + id="1055" group="1" - wearable="jacket" - edit_group="driven" - name="jacket bottom length lower bump" + wearable="underpants" + edit_group="underpants" + name="Pants Length" value_min="0" - value_max="1"> + value_max="1" + value_default=".3"> <param_alpha - multiply_blend="false" - tga_file="jacket_length_lower_alpha.tga" + tga_file="pants_length_alpha.tga" domain="0.01" /> </param> <param - id="1028" + id="1057" group="1" - wearable="jacket" - edit_group="driven" - name="jacket open lower bump" + wearable="underpants" + edit_group="underpants" + name="Pants Waist" value_min="0" - value_max="1"> + value_max="1" + value_default=".8"> <param_alpha - multiply_blend="true" - tga_file="jacket_open_lower_alpha.tga" - domain="0.01" /> + tga_file="pants_waist_alpha.tga" + domain="0.05" /> </param> </layer> <layer - name="lower_jacket"> + name="lower_underpants"> <texture - local_texture="lower_jacket" /> + local_texture="lower_underpants" /> <param - id="809" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="lower_jacket_red" + id="824" + group="0" + wearable="underpants" + edit_group="colorpicker" + name="underpants_red" value_min="0" value_max="1" value_default="1"> @@ -9088,11 +11138,11 @@ render_pass="bump"> </param> <param - id="810" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="lower_jacket_green" + id="825" + group="0" + wearable="underpants" + edit_group="colorpicker" + name="underpants_green" value_min="0" value_max="1" value_default="1"> @@ -9106,11 +11156,11 @@ render_pass="bump"> </param> <param - id="811" - group="1" - edit_group="colorpicker_driven" - wearable="jacket" - name="lower_jacket_blue" + id="826" + group="0" + wearable="underpants" + edit_group="colorpicker" + name="underpants_blue" value_min="0" value_max="1" value_default="1"> @@ -9124,100 +11174,71 @@ render_pass="bump"> </param> <param - id="621" + id="1054" group="1" - wearable="jacket" - edit_group="jacket" - name="bottom length lower" - label_min="hi cut" - label_max="low cut" + wearable="underpants" + edit_group="driven" + name="Pants Length" value_min="0" value_max="1" - value_default=".8" + value_default=".3" camera_distance="1.2" camera_angle="30" - camera_elevation=".2"> + camera_elevation="-.3"> <param_alpha - multiply_blend="false" - tga_file="jacket_length_lower_alpha.tga" + tga_file="pants_length_alpha.tga" domain="0.01" /> </param> <param - id="623" + id="1056" group="1" - wearable="jacket" - edit_group="jacket" - name="open lower" - label_min="open" - label_max="closed" + wearable="underpants" + edit_group="driven" + name="Pants Waist" value_min="0" value_max="1" - value_default=".8" - camera_distance="1.2" - camera_angle="30" - camera_elevation=".2"> + value_default=".8"> <param_alpha - multiply_blend="true" - tga_file="jacket_open_lower_alpha.tga" - domain="0.01" /> + tga_file="pants_waist_alpha.tga" + domain="0.05" /> </param> </layer> <layer - name="lower alpha" - visibility_mask="TRUE"> + name="lower_socks bump" + render_pass="bump" + fixed_color="128,128,128,255"> <texture - local_texture="lower_alpha" /> - </layer> - - </layer_set> + local_texture="lower_socks" + local_texture_alpha_only="true" /> - <!-- =========================================================== --> - <layer_set - body_region="eyes" - width="128" - height="128"> - <layer - name="whites"> - <texture - tga_file="eyewhite.tga" /> - </layer> - - <layer - name="iris" - global_color="eye_color"> - <texture - local_texture="eyes_iris" /> - </layer> - - <layer - name="eyes alpha" - visibility_mask="TRUE"> - <texture - local_texture="eyes_alpha" /> + <param + id="1051" + group="1" + wearable="socks" + edit_group="driven" + name="Socks Length bump" + value_min="0" + value_max="1" + value_default="0.35"> + <param_alpha + tga_file="shoe_height_alpha.tga" + domain="0.01" /> + </param> </layer> - </layer_set> - - <!-- =========================================================== --> - <layer_set - body_region="skirt" - width="512" - height="512" - clear_alpha="false"> <layer - name="skirt_fabric" - write_all_channels="true"> + name="lower_socks"> <texture - local_texture="skirt" /> + local_texture="lower_socks" /> <param - id="921" + id="818" group="0" - wearable="skirt" + wearable="socks" edit_group="colorpicker" - name="skirt_red" + name="socks_red" value_min="0" value_max="1" value_default="1"> @@ -9231,11 +11252,11 @@ render_pass="bump"> </param> <param - id="922" + id="819" group="0" - wearable="skirt" + wearable="socks" edit_group="colorpicker" - name="skirt_green" + name="socks_green" value_min="0" value_max="1" value_default="1"> @@ -9249,11 +11270,11 @@ render_pass="bump"> </param> <param - id="923" + id="820" group="0" - wearable="skirt" + wearable="socks" edit_group="colorpicker" - name="skirt_blue" + name="socks_blue" value_min="0" value_max="1" value_default="1"> @@ -9265,123 +11286,1582 @@ render_pass="bump"> color="0, 0, 255, 255" /> </param_color> </param> + + <param + id="1050" + group="1" + wearable="socks" + edit_group="driven" + name="Socks Length bump" + value_min="0" + value_max="1" + value_default="0.35"> + <param_alpha + tga_file="shoe_height_alpha.tga" + domain="0.01" /> + </param> </layer> <layer - name="skirt_fabric_alpha"> + name="lower_shoes bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="lower_shoes" + local_texture_alpha_only="true" /> + <param - id="858" - group="0" - wearable="skirt" - edit_group="skirt" - edit_group_order="1" - name="Skirt Length" - show_simple="true" - label_min="Short" - label_max="Long" - value_min=".01" + id="1053" + group="1" + wearable="shoes" + edit_group="driven" + name="Shoe Height bump" + value_min="0" value_max="1" - value_default=".4" - simple_percent_min="40" - simple_percent_max="100" - camera_distance="1.3" - camera_elevation="-.5" - camera_angle="30"> + value_default="0.1"> <param_alpha - tga_file="skirt_length_alpha.tga" - domain="0" - multiply_blend="true" /> + tga_file="shoe_height_alpha.tga" + domain="0.01" /> </param> + </layer> + + <layer + name="lower_shoes"> + <texture + local_texture="lower_shoes" /> <param - id="859" + id="812" group="0" - wearable="skirt" - edit_group="skirt" - edit_group_order="4" - name="Slit Front" - label_min="Open Front" - label_max="Closed Front" + wearable="shoes" + edit_group="colorpicker" + name="shoes_red" value_min="0" value_max="1" - value_default="1" - camera_distance="1.3" - camera_elevation="-.5" - camera_angle="30"> - <param_alpha - tga_file="skirt_slit_front_alpha.tga" - multiply_blend="true" - domain="0" /> + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> </param> <param - id="860" + id="813" group="0" - wearable="skirt" - edit_group="skirt" - edit_group_order="5" - name="Slit Back" - label_min="Open Back" - label_max="Closed Back" + wearable="shoes" + edit_group="colorpicker" + name="shoes_green" value_min="0" value_max="1" - value_default="1" - camera_distance="1.3" - camera_elevation="-.5" - camera_angle="160"> - <param_alpha - tga_file="skirt_slit_back_alpha.tga" - multiply_blend="true" - domain="0" /> + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> </param> <param - id="861" + id="817" group="0" - wearable="skirt" - edit_group="skirt" - edit_group_order="6" - name="Slit Left" - label_min="Open Left" - label_max="Closed Left" + wearable="shoes" + edit_group="colorpicker" + name="shoes_blue" value_min="0" value_max="1" - value_default="1" - camera_distance="1.3" - camera_elevation="-.5" - camera_angle="30"> - <param_alpha - tga_file="skirt_slit_left_alpha.tga" - multiply_blend="true" - domain="0" /> + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> </param> <param - id="862" - group="0" - wearable="skirt" - edit_group="skirt" - edit_group_order="7" - name="Slit Right" - label_min="Open Right" - label_max="Closed Right" + id="1052" + group="1" + wearable="shoes" + edit_group="driven" + name="Shoe Height" value_min="0" value_max="1" - value_default="1" - camera_distance="1.3" - camera_elevation="-.5" - camera_angle="-30"> + value_default="0.1"> <param_alpha - tga_file="skirt_slit_right_alpha.tga" - multiply_blend="true" - domain="0" /> + tga_file="shoe_height_alpha.tga" + domain="0.01" /> </param> </layer> - </layer_set> + <layer + name="lower_clothes_shadow"> + <texture + local_texture="lower_pants" /> + + <param + id="913" + group="1" + edit_group="driven" + wearable="pants" + name="Lower Clothes Shading" + value_min="0" + value_max="1" + value_default="0"> + <param_color> + <value + color="0, 0, 0, 0" /> + + <value + color="0, 0, 0, 80" /> + </param_color> + </param> + + <param + id="914" + group="1" + edit_group="driven" + wearable="pants" + name="Waist Height Shadow" + value_min="0.02" + value_max="1"> + <param_alpha + tga_file="pants_waist_alpha.tga" + skip_if_zero="true" + domain="0.04" /> + </param> + + <param + id="915" + group="1" + edit_group="driven" + wearable="pants" + name="Pants Length Shadow" + value_min="0.02" + value_max="1"> + <param_alpha + tga_file="pants_length_alpha.tga" + skip_if_zero="true" + domain="0.03" /> + </param> + </layer> + + <layer + name="lower_pants base bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="lower_pants" + local_texture_alpha_only="true" /> + + <param + id="1035" + group="1" + edit_group="driven" + wearable="pants" + name="Waist Height Cloth" + value_min="0" + value_max="1"> + <param_alpha + tga_file="pants_waist_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1036" + group="1" + edit_group="driven" + wearable="pants" + name="Pants Length Cloth" + value_min="0" + value_max="1"> + <param_alpha + tga_file="pants_length_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower_pants bump" + render_pass="bump"> + <texture + tga_file="bump_pants_wrinkles.tga" /> + + <texture + local_texture="lower_pants" + local_texture_alpha_only="true" /> + + <param + id="869" + group="3" + wearable="pants" + edit_group="pants" + edit_group_order="6" + name="Pants Wrinkles" + value_min="0" + value_max="1" + value_default="0"> + <param_color> + <value + color="255, 255, 255, 0" /> + + <value + color="255, 255, 255, 255" /> + </param_color> + </param> + + <param + id="1017" + group="1" + edit_group="driven" + wearable="pants" + name="Waist Height Cloth" + value_min="0" + value_max="1"> + <param_alpha + tga_file="pants_waist_alpha.tga" + domain="0.05" /> + </param> + + <param + id="1018" + group="1" + edit_group="driven" + wearable="pants" + name="Pants Length Cloth" + value_min="0" + value_max="1"> + <param_alpha + tga_file="pants_length_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower_pants"> + <texture + local_texture="lower_pants" /> + + <param + id="806" + group="0" + wearable="pants" + edit_group="colorpicker" + name="pants_red" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> + </param> + + <param + id="807" + group="0" + wearable="pants" + edit_group="colorpicker" + name="pants_green" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> + </param> + + <param + id="808" + group="0" + wearable="pants" + edit_group="colorpicker" + name="pants_blue" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> + </param> + + <param + id="614" + group="1" + edit_group="driven" + wearable="pants" + name="Waist Height Cloth" + value_min="0" + value_max="1" + value_default=".8"> + <param_alpha + tga_file="pants_waist_alpha.tga" + domain="0.05" /> + </param> + + <param + id="615" + group="1" + edit_group="driven" + wearable="pants" + name="Pants Length Cloth" + value_min="0" + value_max="1" + value_default=".8"> + <param_alpha + tga_file="pants_length_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower_jacket base bump" + render_pass="bump" + fixed_color="128,128,128,255"> + <texture + local_texture="lower_jacket" + local_texture_alpha_only="true" /> + + <param + id="1033" + group="1" + wearable="jacket" + edit_group="driven" + cross_wearable="true" + name="jacket bottom length lower bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="false" + tga_file="jacket_length_lower_alpha.tga" + domain="0.01" /> + </param> + + <param + id="1034" + group="1" + wearable="jacket" + edit_group="driven" + name="jacket open lower bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="jacket_open_lower_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower_jacket bump" + render_pass="bump"> + <texture + tga_file="bump_pants_wrinkles.tga" /> + + <texture + local_texture="lower_jacket" + local_texture_alpha_only="true" /> + + + <param + id="876" + group="1" + wearable="jacket" + name="jacket upper Wrinkles" + value_min="0" + value_max="1" + value_default="0"> + <param_color> + <value + color="255, 255, 255, 0" /> + + <value + color="255, 255, 255, 255" /> + </param_color> + </param> + + <param + id="1027" + group="1" + wearable="jacket" + edit_group="driven" + name="jacket bottom length lower bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="false" + tga_file="jacket_length_lower_alpha.tga" + domain="0.01" /> + </param> + + <param + id="1028" + group="1" + wearable="jacket" + edit_group="driven" + name="jacket open lower bump" + value_min="0" + value_max="1"> + <param_alpha + multiply_blend="true" + tga_file="jacket_open_lower_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower_jacket"> + <texture + local_texture="lower_jacket" /> + + <param + id="809" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="lower_jacket_red" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> + </param> + + <param + id="810" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="lower_jacket_green" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> + </param> + + <param + id="811" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="lower_jacket_blue" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> + </param> + + <param + id="621" + group="1" + wearable="jacket" + edit_group="jacket" + name="bottom length lower" + label_min="hi cut" + label_max="low cut" + value_min="0" + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> + <param_alpha + multiply_blend="false" + tga_file="jacket_length_lower_alpha.tga" + domain="0.01" /> + </param> + + <param + id="623" + group="1" + wearable="jacket" + edit_group="jacket" + name="open lower" + label_min="open" + label_max="closed" + value_min="0" + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> + <param_alpha + multiply_blend="true" + tga_file="jacket_open_lower_alpha.tga" + domain="0.01" /> + </param> + </layer> + + <layer + name="lower alpha" + visibility_mask="TRUE"> + <texture + local_texture="lower_alpha" /> + </layer> + + </layer_set> + + <!-- =========================================================== --> + <layer_set + body_region="eyes" + width="128" + height="128"> + <layer + name="whites"> + <texture + tga_file="eyewhite.tga" /> + </layer> + + <layer + name="iris" + global_color="eye_color"> + <texture + local_texture="eyes_iris" /> + </layer> + + <layer + name="eyes alpha" + visibility_mask="TRUE"> + <texture + local_texture="eyes_alpha" /> + </layer> + + </layer_set> + + <!-- =========================================================== --> + <layer_set + body_region="skirt" + width="512" + height="512" + clear_alpha="false"> + <layer + name="skirt_fabric" + write_all_channels="true"> + <texture + local_texture="skirt" /> + + <param + id="921" + group="0" + wearable="skirt" + edit_group="colorpicker" + name="skirt_red" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="255, 0, 0, 255" /> + </param_color> + </param> + + <param + id="922" + group="0" + wearable="skirt" + edit_group="colorpicker" + name="skirt_green" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 255, 0, 255" /> + </param_color> + </param> + + <param + id="923" + group="0" + wearable="skirt" + edit_group="colorpicker" + name="skirt_blue" + value_min="0" + value_max="1" + value_default="1"> + <param_color> + <value + color="0, 0, 0, 255" /> + + <value + color="0, 0, 255, 255" /> + </param_color> + </param> + </layer> + + <layer + name="skirt_fabric_alpha"> + <param + id="858" + group="0" + wearable="skirt" + edit_group="skirt" + edit_group_order="1" + name="Skirt Length" + show_simple="true" + label_min="Short" + label_max="Long" + value_min=".01" + value_max="1" + value_default=".4" + simple_percent_min="40" + simple_percent_max="100" + camera_distance="1.3" + camera_elevation="-.5" + camera_angle="30"> + <param_alpha + tga_file="skirt_length_alpha.tga" + domain="0" + multiply_blend="true" /> + </param> + + <param + id="859" + group="0" + wearable="skirt" + edit_group="skirt" + edit_group_order="4" + name="Slit Front" + label_min="Open Front" + label_max="Closed Front" + value_min="0" + value_max="1" + value_default="1" + camera_distance="1.3" + camera_elevation="-.5" + camera_angle="30"> + <param_alpha + tga_file="skirt_slit_front_alpha.tga" + multiply_blend="true" + domain="0" /> + </param> + + <param + id="860" + group="0" + wearable="skirt" + edit_group="skirt" + edit_group_order="5" + name="Slit Back" + label_min="Open Back" + label_max="Closed Back" + value_min="0" + value_max="1" + value_default="1" + camera_distance="1.3" + camera_elevation="-.5" + camera_angle="160"> + <param_alpha + tga_file="skirt_slit_back_alpha.tga" + multiply_blend="true" + domain="0" /> + </param> + + <param + id="861" + group="0" + wearable="skirt" + edit_group="skirt" + edit_group_order="6" + name="Slit Left" + label_min="Open Left" + label_max="Closed Left" + value_min="0" + value_max="1" + value_default="1" + camera_distance="1.3" + camera_elevation="-.5" + camera_angle="30"> + <param_alpha + tga_file="skirt_slit_left_alpha.tga" + multiply_blend="true" + domain="0" /> + </param> + + <param + id="862" + group="0" + wearable="skirt" + edit_group="skirt" + edit_group_order="7" + name="Slit Right" + label_min="Open Right" + label_max="Closed Right" + value_min="0" + value_max="1" + value_default="1" + camera_distance="1.3" + camera_elevation="-.5" + camera_angle="-30"> + <param_alpha + tga_file="skirt_slit_right_alpha.tga" + multiply_blend="true" + domain="0" /> + </param> + </layer> + + </layer_set> + + <!-- =========================================================== --> + <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> + - <!-- =========================================================== --> - <driver_parameters> + <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" @@ -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" @@ -10758,8 +14313,23 @@ render_pass="bump"> min1=".5" 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> @@ -11168,6 +14738,31 @@ render_pass="bump"> </param_driver> </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" diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml index 6b07bbc1d3d5fcbac2a50b2eb834f867d81de75d..350ba7b841e9458197d1315c9820ab834d4efcd2 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 d933537d2e63d5dd57c4c7bf35168bfb292bbb8b..b00c9608229b06a859014f787a35147d03af99a7 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 fa16f02c16cc154e0c0214871b9b1bda4c204dad..e335eabd1af7bf29e8d2aa217228e6affc5f2386 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 b6d02ea2f8111335803441c59497c605f88dc83d..5287f98827b9ebd688fd3f397cb95c2be6765ee4 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 4c16c542d6a947ef25a9dca4777fde1f2cfa4903..843cd9b249741bf3cfbf98cd66e10b5cb49f305f 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 e5df417ca9f89d5d8174c6e61d9be7fd3c4f33a4..d33a138e943e04dcd8c5d60e0ebf355cbed4f5e8 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 b81cc6e3a51649cbdadeeeef78ad9db0e8bcef88..20d15d96033b35bf4d5c0e383c4a5d74dcd08253 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -109,7 +109,9 @@ class LLFloaterBvhPreview : public LLFloaterNameDesc 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 ffeebfd25613a51c94479e3d30c64cc6d64b236e..0f0fafcce6b5a1b42cde77ccb973ebbc6c352aa9 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; @@ -3367,19 +3396,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 //----------------------------------------------------------------------------- @@ -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 a73ca502608fb89cd35384252229278c53a06b04..217ac35888702cbb5d215bdbbb948a2d8e5fbb10 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -260,6 +260,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex 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 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex 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 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex bool mLoading; U32 mLoadState; bool mResetJoints; - bool mRigParityWithScene; bool mModelNoErrors; std::map<std::string, bool> mViewOption; @@ -410,7 +406,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex bool mLastJointUpdate; - JointSet mJointsFromNode; + JointNameSet mJointsFromNode; JointTransformMap mJointTransformMap; LLPointer<LLVOAvatar> mPreviewAvatar; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36bdcf4d897e89472aad099de8f94e58749df189..8429be2f498dc29067114e9affc6dbdc47770feb 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 fa0c09e97a7c901723c132d47bb3205b9ae52a8b..fd45129c725baaa40d16307af3b79fa586986953 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -117,6 +117,8 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, 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 35ac0537a3d01758397f939b3d13eb509d471ad4..fb40af1302dcc79419052d8da6e2724a1e6b131d 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 0000000000000000000000000000000000000000..732afdfa9a46e8993d6970805a4f82578f6668b5 --- /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 0000000000000000000000000000000000000000..9a28100dc3bfdf144c535376e8ade710cfdc540f --- /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 b0eb4137a735634a160a7af5fb9cf1bbf9cf01bc..0fd36766b3c9c68943a619dd9dcf9d7006333973 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 @@ class LLOctreeRenderNonOccluded : public OctreeTraveler 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 88fbd233b8cf9bee012ebb3f04dd4c4703501895..79b5130bd3dafd2a39c4770166c65d5cd448b3f4 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 fd950864aa9c9fb340b09b0ad3bb134dc91e7634..01d799dcd50d62415c521a23ab9532cf81ccfbf2 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 16f40fb747393d55ff6f6c0f177040f065062470..f2680ce25dbdd2dedc30a8d73edfbb1c1858c2cb 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 e46299f9d2d54ae2cf90c2aff73944100d9ceaa6..b7bd131246a4ec3e647e229c3c494d6e8417c6ab 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 fd262b6e804793cfdc602545bd83dbd668ff2cd9..abe11bbf5c47a14dccfcea7c5ff0283539417b5b 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 888decd3bedebbed0717c70bec84bb8723814eb8..66e392ac424075f3ac3e3cb3d89705333073fef5 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 bf7cf08c6364221e94b1f31ae5db841a2ee0e2d5..43a81ada4952ce35fb83e8fb4f757ee7a47fba33 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 99a9ed1d75a2d7fbd93be5fa0f443167d6de1246..0b0d12c5b87101903e2f2ae00a942cc947173a99 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 b7bdf0015775bb61bfd4814f0019267c462ef3f1..8ce3c697871a64ef63312053b53359c0ecdea662 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 dafe2cafec02676632892c7871201e6be3f52432..3e0cec0f0999e7fb19b05ae4141f28bd03789070 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 0f73515b5d8331909708758fa9a2baa8b14425b0..8d482b2e34eb4b2f820c18bcc29bea056311e9f0 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -70,7 +70,7 @@ class LLOverrideBakedTextureUpdate }; // 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 b9dd43f0617aa7b0345362b8d25e5fc2684b0d95..0728509bcddfe9cfbf83eed5b4eb8babee4dbfa0 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,10 +5338,48 @@ 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 //----------------------------------------------------------------------------- @@ -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) @@ -5190,6 +5466,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 //----------------------------------------------------------------------------- @@ -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 418cca519d68697664ce31830df290a91e2bceb4..32a30c3aa8ead300f059c74bc91b3aeb51b5b0d9 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 @@ class LLVOAvatar : 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 @@ class LLVOAvatar : 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 @@ class LLVOAvatar : 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 @@ class LLVOAvatar : ** 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 5f48898cb165319a53b9594cfe3d247a8b501b9a..b6655dd078d78c67813bdad46cd0f5015169cd84 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 a9c4ab26a9ac0762f1131ebefd092f2ba3dd1e9d..f9f90bb323a6e99978810cc2320d09334c7424dd 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -103,17 +103,6 @@ class LLVOAvatarSelf : // 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 8f0b233f01544b91e90845204f38c1fbef2a1736..465f8fe0d6b6d4c0bd37a9f7923924be14faf0b2 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 638a4e2da88ceca6d7278498fce3392d5a23561a..9a9101e0da1f71e9f54012634d8a457562c4fe25 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 9e520b2d31b22c39e03acd5bf4986f2fc6a06047..8771660bcfa5ab2636d865a517af3c7fd03ad734 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -39,6 +39,15 @@ <menu_item_call.on_click 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" 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 c6ae844d676dc6385f8181134975fd69f924cce0..ced0dd37b161bce848af23c46839cd3a7e881543 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 fadacbf3cb79122f42ec226343fab8bd2b8d7f68..f89c0eadf817306174f4801fef468291dca226e8 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_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 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 d3b0b07f700f461fc7c55619de2443b61a9bcfb9..924e8b8454575e6233ab40f274a770c2f2ba17f9 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 0a492fb37b25538eb33bb3a88e58d38230dd8b97..ad7aca641b12ff646c3892250225fc87620be7e8 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3527,6 +3527,16 @@ function="Advanced.ToggleInfoDisplay" 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"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 492d96365358902da40464e8613e75b43d654134..4daff340ac23609dd4e48ffa2416d8756d16d395 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1414,6 +1414,13 @@ Note: This will clear the cache. Port settings take effect after you restart [APP_NAME]. </notification> + <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" @@ -10353,6 +10360,14 @@ Not enough script resources available to attach object! Cannot attach object because it is already being removed. </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" diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml index 94c468e1bb0d06e189cc7d6cfeeee4ae94a13f8d..756b8f81026e2147b25f18929f2c4393970ce305 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 a9b8e197bc4c6780f0541ad404b3ee611c6abf06..9e99916ca080d81095b5c30f119619083a5fac0b 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 323da2be38be875d17dc5f9634754ca5f01ddf3d..284688d4d15b4026bcb2ff9ca62e82acbdb3d681 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 615abbaa895c6bbfe42f17451ac966a67feeeeb3..53b74fa645693372f9b6f979e559d020ec2c21aa 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 ae63546082f9975c55c39e8ada14968f575cc96c..72a6f09f92f65e4c27f0c7774b05829717a2473d 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 0000000000000000000000000000000000000000..0cb1e1022e9193fd0f5d33fc423ffd24403d7e22 --- /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 0000000000000000000000000000000000000000..823f69cb854d1123cf1cb4a17c755e47ed78e3f6 --- /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 0000000000000000000000000000000000000000..5d4ea0e059da9bcb532581a591c675127c22a4eb --- /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) +