Bento hell and back, and back to hell, and back.

This commit is contained in:
Shyotl
2017-01-11 03:55:36 -06:00
parent 9dbdf75c14
commit 98516a2a22
54 changed files with 8482 additions and 2423 deletions

View File

@@ -44,6 +44,8 @@
#include "llstl.h"
#include "lltexglobalcolor.h"
#include "llwearabledata.h"
#include "boost/bind.hpp"
#include "boost/tokenizer.hpp"
#if LL_MSVC
@@ -87,8 +89,11 @@ public:
private:
std::string mName;
std::string mSupport;
std::string mAliases;
BOOL mIsJoint;
LLVector3 mPos;
LLVector3 mEnd;
LLVector3 mRot;
LLVector3 mScale;
LLVector3 mPivot;
@@ -118,6 +123,7 @@ public:
private:
S32 mNumBones;
S32 mNumCollisionVolumes;
LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
bone_info_list_t mBoneInfoList;
};
@@ -180,7 +186,9 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mPelvisToFoot(0.f),
mHeadOffset(),
mRoot(NULL),
mWearableData(wearable_data)
mWearableData(wearable_data),
mNumBones(0),
mIsBuilt(FALSE)
{
llassert_always(mWearableData);
mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
@@ -193,8 +201,6 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mBakedTextureDatas[i].mMaskTexName = 0;
mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
}
mIsBuilt = FALSE;
}
// virtual
@@ -327,36 +333,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;
@@ -369,16 +388,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);
@@ -441,11 +463,56 @@ void LLAvatarAppearance::cleanupClass()
using namespace LLAvatarAppearanceDefines;
void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state,
joint_state_map_t& curr_state)
{
if (!last_state.empty() && (last_state != curr_state))
{
S32 diff_count = 0;
joint_state_map_t::iterator it;
for (it=last_state.begin(); it != last_state.end(); ++it)
{
const std::string& key = it->first;
if (last_state[key] != curr_state[key])
{
LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL;
diff_count++;
}
}
if (diff_count > 0)
{
LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL;
}
}
}
//------------------------------------------------------------------------
// The viewer can only suggest a good size for the agent,
// the simulator will keep it inside a reasonable range.
void LLAvatarAppearance::computeBodySize()
{
mLastBodySizeState = mCurrBodySizeState;
mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale();
mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition();
mCurrBodySizeState["mSkull scale"] = mSkullp->getScale();
mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition();
mCurrBodySizeState["mNeck scale"] = mNeckp->getScale();
mCurrBodySizeState["mChest pos"] = mChestp->getPosition();
mCurrBodySizeState["mChest scale"] = mChestp->getScale();
mCurrBodySizeState["mHead pos"] = mHeadp->getPosition();
mCurrBodySizeState["mHead scale"] = mHeadp->getScale();
mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition();
mCurrBodySizeState["mTorso scale"] = mTorsop->getScale();
mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition();
mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale();
mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition();
mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale();
mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition();
mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
LLVector3 pelvis_scale = mPelvisp->getScale();
// some of the joints have not been cached
@@ -505,7 +572,8 @@ void LLAvatarAppearance::computeBodySize()
if (new_body_size != mBodySize || old_offset != mAvatarOffset)
{
mBodySize = new_body_size;
bodySizeChanged();
compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
}
}
@@ -541,7 +609,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;
@@ -557,6 +625,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);
@@ -571,7 +645,7 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
{
if (volume_num >= (S32)mCollisionVolumes.size())
{
LL_WARNS() << "Too many bones" << LL_ENDL;
LL_WARNS() << "Too many collision volumes" << LL_ENDL;
return FALSE;
}
joint = (mCollisionVolumes[volume_num]);
@@ -579,26 +653,34 @@ 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->setDefaultScale(info->mScale);
joint->setSupport(info->mSupport);
joint->setEnd(info->mEnd);
if (info->mIsJoint)
{
joint->setSkinOffset( info->mPivot );
joint->setJointNum(joint_num);
joint_num++;
}
else // collision volume
{
joint->setJointNum(mNumBones+volume_num);
volume_num++;
}
// setup children
LLAvatarBoneInfo::child_list_t::const_iterator iter;
for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
@@ -618,18 +700,12 @@ 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.empty() || !mSkeleton[0])
{
return FALSE;
}
if (mSkeleton.size() != num)
{
clearSkeleton();
mSkeleton = avatar_joint_list_t(num,NULL);
mNumBones = num;
}
return TRUE;
}
@@ -642,6 +718,8 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
{
if (!info)
return FALSE;
LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
//-------------------------------------------------------------------------
// allocate joints
//-------------------------------------------------------------------------
@@ -668,8 +746,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;
@@ -1128,6 +1206,7 @@ BOOL LLAvatarAppearance::loadMeshNodes()
{
// This should never happen
LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
return FALSE;
}
}
else
@@ -1264,6 +1343,10 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
{
return NULL;
}
if (!mSkeleton[num])
{
mSkeleton[num] = createAvatarJoint();
}
return mSkeleton[num];
}
@@ -1563,21 +1646,24 @@ LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_in
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
{
delete_and_clear(mCollisionVolumes);
mCollisionVolumes.reserve(num);
LLAvatarJointCollisionVolume* cv;
for (U32 i = 0; i < num; ++i)
if(num != mCollisionVolumes.size() )
{
cv = new LLAvatarJointCollisionVolume();
if (cv)
delete_and_clear(mCollisionVolumes);
mCollisionVolumes.reserve(num);
LLAvatarJointCollisionVolume* cv;
for (U32 i = 0; i < num; ++i)
{
mCollisionVolumes.push_back(cv);
}
else
{
delete_and_clear(mCollisionVolumes);
return false;
cv = new LLAvatarJointCollisionVolume();
if (cv)
{
mCollisionVolumes.push_back(cv);
}
else
{
delete_and_clear(mCollisionVolumes);
return false;
}
}
}
return TRUE;
@@ -1597,6 +1683,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"))
{
@@ -1634,6 +1723,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");
@@ -1689,6 +1792,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
@@ -1719,7 +1870,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "Unknown param type." << LL_ENDL;
}
continue;
return FALSE;
}
LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
@@ -1744,7 +1895,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No name supplied for attachment point." << LL_ENDL;
delete info;
continue;
return FALSE;
}
static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
@@ -1752,7 +1903,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL;
delete info;
continue;
return FALSE;
}
static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
@@ -1778,7 +1929,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL;
delete info;
continue;
return FALSE;
}
static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
@@ -1864,7 +2015,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
{
LL_WARNS() << "Unknown param type." << LL_ENDL;
}
continue;
return FALSE;
}
LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
@@ -2025,7 +2176,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No name supplied for morph mask." << LL_ENDL;
delete info;
continue;
return FALSE;
}
static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
@@ -2033,7 +2184,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No region supplied for morph mask." << LL_ENDL;
delete info;
continue;
return FALSE;
}
static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
@@ -2041,7 +2192,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL;
delete info;
continue;
return FALSE;
}
// optional parameter. don't throw a warning if not present.

View File

@@ -66,6 +66,7 @@ public:
LLAvatarAppearance(LLWearableData* wearable_data);
virtual ~LLAvatarAppearance();
static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members
static void initClass(); // initializes static members
static void cleanupClass(); // Cleanup data that's only init'd once per class.
virtual void initInstance(); // Called after construction to initialize the instance.
@@ -132,6 +133,7 @@ protected:
virtual LLAvatarJoint* createAvatarJoint() = 0;
virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0;
virtual LLAvatarJointMesh* createAvatarJointMesh() = 0;
void makeJointAliases(LLAvatarBoneInfo *bone_info);
public:
F32 getPelvisToFoot() const { return mPelvisToFoot; }
/*virtual*/ LLJoint* getRootJoint() { return mRoot; }
@@ -139,17 +141,27 @@ public:
LLVector3 mHeadOffset; // current head position
LLAvatarJoint *mRoot;
typedef std::map<std::string, LLJoint*> joint_map_t;
typedef std::vector<std::pair<char[64], LLJoint*>> joint_map_t;
joint_map_t mJointMap;
typedef std::map<std::string, LLVector3> joint_state_map_t;
joint_state_map_t mLastBodySizeState;
joint_state_map_t mCurrBodySizeState;
void compareJointStateMaps(joint_state_map_t& last_state,
joint_state_map_t& curr_state);
void computeBodySize();
public:
typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
typedef std::map<std::string, std::string> joint_alias_map_t;
const joint_alias_map_t& getJointAliases();
protected:
static BOOL parseSkeletonFile(const std::string& filename);
virtual void buildCharacter();
virtual BOOL loadAvatar();
virtual void bodySizeChanged() = 0;
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
BOOL allocateCharacterJoints(U32 num);
@@ -157,9 +169,10 @@ protected:
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;
LLVector3OverrideMap mPelvisFixups;
joint_alias_map_t mJointAliasMap;
//--------------------------------------------------------------------
// Pelvis height adjustment members.
@@ -343,6 +356,7 @@ protected:
// Collision volumes
//--------------------------------------------------------------------
public:
S32 mNumBones;
std::vector<LLAvatarJointCollisionVolume*> mCollisionVolumes;
protected:
BOOL allocateCollisionVolumes(U32 num);

View File

@@ -53,19 +53,18 @@ LLAvatarJoint::LLAvatarJoint() :
init();
}
LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
LLJoint(joint_num)
{
init();
}
LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
LLJoint(name, parent)
{
init();
}
LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
LLJoint(joint_num)
{
init();
}
void LLAvatarJoint::init()
{
mValid = FALSE;

View File

@@ -57,6 +57,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()
//-----------------------------------------------------------------------------
LLJoint *getBaseSkeletonAncestor(LLJoint* 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 ancestor;
}
//-----------------------------------------------------------------------------
// totalSkinOffset()
//-----------------------------------------------------------------------------
LLVector3 totalSkinOffset(LLJoint *joint)
{
LLVector3 totalOffset;
while (joint)
{
if (joint->getSupport() == LLJoint::SUPPORT_BASE)
{
totalOffset += joint->getSkinOffset();
}
joint = joint->getParent();
}
return totalOffset;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::LLSkinJoint
@@ -83,29 +118,24 @@ LLSkinJoint::~LLSkinJoint()
//-----------------------------------------------------------------------------
// LLSkinJoint::setupSkinJoint()
//-----------------------------------------------------------------------------
void LLSkinJoint::setupSkinJoint( LLJoint *joint)
BOOL LLSkinJoint::setupSkinJoint( LLJoint *joint)
{
// find the named joint
if (!(mJoint = joint))
if (!(mJoint = dynamic_cast<LLAvatarJoint*>(joint)))
{
LL_INFOS() << "Can't find joint" << LL_ENDL;
return;
return FALSE;
}
// compute the inverse root skin matrix
mRootToJointSkinOffset.clearVec();
mRootToParentJointSkinOffset.clearVec();
mRootToJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint);
mRootToJointSkinOffset = -mRootToJointSkinOffset;
do
{
mRootToJointSkinOffset -= joint->getSkinOffset();
} while (joint = joint->getParent());
//mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor((LLAvatarJoint*)joint));
mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
mRootToParentJointSkinOffset = mRootToJointSkinOffset;
mRootToParentJointSkinOffset += mJoint->getSkinOffset();
return;
return TRUE;
}
@@ -314,9 +344,9 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
if (!mMesh->isLOD())
{
setupJoint(getRoot());
LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
LL_DEBUGS() << "joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
//-----------------------------------------------------------------------------
@@ -324,10 +354,8 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::setupJoint(LLJoint* current_joint)
{
// LL_INFOS() << "Mesh: " << getName() << LL_ENDL;
// S32 joint_count = 0;
U32 sj;
for (sj=0; sj<mNumSkinJoints; sj++)
{
LLSkinJoint &js = mSkinJoints[sj];
@@ -338,25 +366,30 @@ void LLAvatarJointMesh::setupJoint(LLJoint* current_joint)
}
// we've found a skinjoint for this joint..
LL_DEBUGS("Avatar") << "Mesh: " << getName() << " joint " << current_joint->getName() << " matches skinjoint " << sj << LL_ENDL;
// is the last joint in the array our parent?
if(mMesh->mJointRenderData.size() && mMesh->mJointRenderData[mMesh->mJointRenderData.size() - 1]->mWorldMatrix == &current_joint->getParent()->getWorldMatrix())
std::vector<LLJointRenderData*> &jrd = mMesh->mJointRenderData;
// SL-287 - need to update this so the results are the same if
// additional extended-skeleton joints lie between this joint
// and the original parent.
LLJoint *ancestor = getBaseSkeletonAncestor(current_joint);
if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix())
{
// ...then just add ourselves
LLJoint* jointp = js.mJoint;
mMesh->mJointRenderData.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
// LL_INFOS() << "joint " << joint_count << js.mJoint->getName() << LL_ENDL;
// joint_count++;
jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
}
// otherwise add our parent and ourselves
// otherwise add our ancestor and ourselves
else
{
mMesh->mJointRenderData.push_back(new LLJointRenderData(&current_joint->getParent()->getWorldMatrix(), NULL));
// LL_INFOS() << "joint " << joint_count << current_joint->getParent()->getName() << LL_ENDL;
// joint_count++;
mMesh->mJointRenderData.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
// LL_INFOS() << "joint " << joint_count << current_joint->getName() << LL_ENDL;
// joint_count++;
jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL));
LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL;
jrd.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL;
}
}

View File

@@ -49,7 +49,7 @@ class LLSkinJoint
public:
LLSkinJoint();
~LLSkinJoint();
void setupSkinJoint( LLJoint *joint);
BOOL setupSkinJoint( LLJoint *joint);
LLJoint* mJoint;
LLVector3 mRootToJointSkinOffset;
@@ -124,6 +124,9 @@ public:
// Sets up joint matrix data for rendering
void setupJoint(LLJoint* current_joint);
// Render time method to upload batches of joint matrices
void uploadJointMatrices();
// Sets ID for picking
void setMeshID( S32 id ) {mMeshID = id;}

View File

@@ -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())
{

View File

@@ -130,6 +130,10 @@ public:
S32 getDrivenParamsCount() const;
const LLViewerVisualParam* getDrivenParam(S32 index) const;
typedef std::vector<LLDrivenEntry> entry_list_t;
entry_list_t& getDrivenList() { return mDriven; }
void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
protected:
LLDriverParam(const LLDriverParam& pOther);
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
@@ -137,7 +141,6 @@ protected:
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
typedef std::vector<LLDrivenEntry> entry_list_t;
entry_list_t mDriven;
LLViewerVisualParam* mCurrentDistortionParam;
// Backlink only; don't make this an LLPointer.

View File

@@ -680,8 +680,8 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
if (!mMorphData)
{
const std::string driven_tag = "_Driven";
size_t pos = morph_param_name.find(driven_tag);
if (pos != std::string::npos)
U32 pos = morph_param_name.find(driven_tag);
if (pos > 0)
{
morph_param_name = morph_param_name.substr(0,pos);
mMorphData = mMesh->getMorphData(morph_param_name);
@@ -1027,6 +1027,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()

View File

@@ -186,6 +186,7 @@ public:
void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);
void addPendingMorphMask() { mNumMorphMasksPending++; }
void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
void* operator new(size_t size)
{

View File

@@ -155,7 +155,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
if (!joint)
{
LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL;
continue;
return FALSE;
}
if (mJointScales.find(joint) != mJointScales.end())
@@ -205,10 +205,10 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
LLJoint* joint;
joint_vec_map_t::iterator iter;
LLJoint* joint;
joint_vec_map_t::iterator iter;
for (iter = mJointScales.begin();
iter != mJointScales.end();
@@ -216,9 +216,18 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
joint = iter->first;
LLVector3 newScale = joint->getScale();
LLVector3 scaleDelta = iter->second;
newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
joint->setScale(newScale);
LLVector3 scaleDelta = iter->second;
LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta;
newScale = newScale + offset;
//An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
// needed?
// joint->storeScaleForReset( newScale );
// BENTO for detailed stack tracing of params.
// std::stringstream ostr;
// ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset;
joint->setScale(newScale, true);
}
for (iter = mJointOffsets.begin();
@@ -229,14 +238,16 @@ 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
bool allow_attachment_pos_overrides = true;
joint->setPosition(newPosition, allow_attachment_pos_overrides);
}
if (mLastWeight != mCurWeight && !mIsAnimating)
if (mLastWeight != effective_weight && !mIsAnimating)
{
mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
}
mLastWeight = mCurWeight;
mLastWeight = effective_weight;
}

View File

@@ -279,7 +279,9 @@ LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController* controller) : AIM
mName = "eye_rot";
mLeftEyeState = new LLJointState;
mAltLeftEyeState = new LLJointState;
mRightEyeState = new LLJointState;
mAltRightEyeState = new LLJointState;
}
@@ -312,32 +314,135 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character)
return STATUS_FAILURE;
}
mAltLeftEyeState->setJoint( character->getJoint("mFaceEyeAltLeft") );
if ( ! mAltLeftEyeState->getJoint() )
{
LL_INFOS() << getName() << ": Can't get alt left eyeball joint." << LL_ENDL;
return STATUS_FAILURE;
}
mRightEyeState->setJoint( character->getJoint("mEyeRight") );
if ( ! mRightEyeState->getJoint() )
{
LL_INFOS() << getName() << ": Can't get Right eyeball joint." << LL_ENDL;
LL_INFOS() << getName() << ": Can't get right eyeball joint." << LL_ENDL;
return STATUS_FAILURE;
}
mAltRightEyeState->setJoint( character->getJoint("mFaceEyeAltRight") );
if ( ! mAltRightEyeState->getJoint() )
{
LL_INFOS() << getName() << ": Can't get alt right eyeball joint." << LL_ENDL;
return STATUS_FAILURE;
}
mLeftEyeState->setUsage(LLJointState::ROT);
mAltLeftEyeState->setUsage(LLJointState::ROT);
mRightEyeState->setUsage(LLJointState::ROT);
mAltRightEyeState->setUsage(LLJointState::ROT);
addJointState( mLeftEyeState );
addJointState( mAltLeftEyeState );
addJointState( mRightEyeState );
addJointState( mAltRightEyeState );
return STATUS_SUCCESS;
}
//-----------------------------------------------------------------------------
// LLEyeMotion::adjustEyeTarget()
//-----------------------------------------------------------------------------
void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state)
{
// Compute eye rotation.
BOOL has_eye_target = FALSE;
LLQuaternion target_eye_rot;
LLVector3 eye_look_at;
F32 vergence;
if (targetPos)
{
LLVector3 skyward(0.f, 0.f, 1.f);
LLVector3 left;
LLVector3 up;
eye_look_at = *targetPos;
has_eye_target = TRUE;
F32 lookAtDistance = eye_look_at.normVec();
left.setVec(skyward % eye_look_at);
up.setVec(eye_look_at % left);
target_eye_rot = LLQuaternion(eye_look_at, left, up);
// convert target rotation to head-local coordinates
target_eye_rot *= ~mHeadJoint->getWorldRotation();
// eliminate any Euler roll - we're lucky that roll is applied last.
F32 roll, pitch, yaw;
target_eye_rot.getEulerAngles(&roll, &pitch, &yaw);
target_eye_rot.setQuat(0.0f, pitch, yaw);
// constrain target orientation to be in front of avatar's face
target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE);
// calculate vergence
F32 interocular_dist = (left_eye_state.getJoint()->getWorldPosition() - right_eye_state.getJoint()->getWorldPosition()).magVec();
vergence = -atan2((interocular_dist / 2.f), lookAtDistance);
llclamp(vergence, -F_PI_BY_TWO, 0.f);
}
else
{
target_eye_rot = LLQuaternion::DEFAULT;
vergence = 0.f;
}
//RN: subtract 4 degrees to account for foveal angular offset relative to pupil
vergence += 4.f * DEG_TO_RAD;
// calculate eye jitter
LLQuaternion eye_jitter_rot;
// vergence not too high...
if (vergence > -0.05f)
{
//...go ahead and jitter
eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw);
}
else
{
//...or don't
eye_jitter_rot.loadIdentity();
}
// calculate vergence of eyes as an object gets closer to the avatar's head
LLQuaternion vergence_quat;
if (has_eye_target)
{
vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f));
}
else
{
vergence_quat.loadIdentity();
}
// calculate eye rotations
LLQuaternion left_eye_rot = target_eye_rot;
left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot;
LLQuaternion right_eye_rot = target_eye_rot;
vergence_quat.transQuat();
right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot;
left_eye_state.setRotation( left_eye_rot );
right_eye_state.setRotation( right_eye_rot );
}
//-----------------------------------------------------------------------------
// LLEyeMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
{
// Compute eye rotation.
LLQuaternion target_eye_rot;
LLVector3 eye_look_at;
F32 vergence;
//calculate jitter
if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
{
@@ -410,83 +515,10 @@ BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
}
}
BOOL has_eye_target = FALSE;
LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
if (targetPos)
{
LLVector3 skyward(0.f, 0.f, 1.f);
LLVector3 left;
LLVector3 up;
eye_look_at = *targetPos;
has_eye_target = TRUE;
F32 lookAtDistance = eye_look_at.normVec();
left.setVec(skyward % eye_look_at);
up.setVec(eye_look_at % left);
target_eye_rot = LLQuaternion(eye_look_at, left, up);
// convert target rotation to head-local coordinates
target_eye_rot *= ~mHeadJoint->getWorldRotation();
// eliminate any Euler roll - we're lucky that roll is applied last.
F32 roll, pitch, yaw;
target_eye_rot.getEulerAngles(&roll, &pitch, &yaw);
target_eye_rot.setQuat(0.0f, pitch, yaw);
// constrain target orientation to be in front of avatar's face
target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE);
// calculate vergence
F32 interocular_dist = (mLeftEyeState->getJoint()->getWorldPosition() - mRightEyeState->getJoint()->getWorldPosition()).magVec();
vergence = -atan2((interocular_dist / 2.f), lookAtDistance);
llclamp(vergence, -F_PI_BY_TWO, 0.f);
}
else
{
target_eye_rot = LLQuaternion::DEFAULT;
vergence = 0.f;
}
//RN: subtract 4 degrees to account for foveal angular offset relative to pupil
vergence += 4.f * DEG_TO_RAD;
// calculate eye jitter
LLQuaternion eye_jitter_rot;
// vergence not too high...
if (vergence > -0.05f)
{
//...go ahead and jitter
eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw);
}
else
{
//...or don't
eye_jitter_rot.loadIdentity();
}
// calculate vergence of eyes as an object gets closer to the avatar's head
LLQuaternion vergence_quat;
if (has_eye_target)
{
vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f));
}
else
{
vergence_quat.loadIdentity();
}
// calculate eye rotations
LLQuaternion left_eye_rot = target_eye_rot;
left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot;
LLQuaternion right_eye_rot = target_eye_rot;
vergence_quat.transQuat();
right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot;
mLeftEyeState->setRotation( left_eye_rot );
mRightEyeState->setRotation( right_eye_rot );
adjustEyeTarget(targetPos, *mLeftEyeState, *mRightEyeState);
adjustEyeTarget(targetPos, *mAltLeftEyeState, *mAltRightEyeState);
return TRUE;
}
@@ -503,12 +535,24 @@ void LLEyeMotion::onDeactivate()
joint->setRotation(LLQuaternion::DEFAULT);
}
joint = mAltLeftEyeState->getJoint();
if (joint)
{
joint->setRotation(LLQuaternion::DEFAULT);
}
joint = mRightEyeState->getJoint();
if (joint)
{
joint->setRotation(LLQuaternion::DEFAULT);
}
joint = mAltRightEyeState->getJoint();
if (joint)
{
joint->setRotation(LLQuaternion::DEFAULT);
}
AIMaskedMotion::onDeactivate();
}

View File

@@ -169,6 +169,9 @@ public:
// must return true to indicate success and be available for activation
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
void adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state);
// called per time step
// must return TRUE while it is active, and
// must return FALSE when the motion is completed.
@@ -186,6 +189,8 @@ public:
LLJoint *mHeadJoint;
LLPointer<LLJointState> mLeftEyeState;
LLPointer<LLJointState> mRightEyeState;
LLPointer<LLJointState> mAltLeftEyeState;
LLPointer<LLJointState> mAltRightEyeState;
LLFrameTimer mEyeJitterTimer;
F32 mEyeJitterTime;

View File

@@ -32,6 +32,7 @@
#include "lljoint.h"
#include "llmath.h"
#include <boost/algorithm/string.hpp>
S32 LLJoint::sNumUpdates = 0;
S32 LLJoint::sNumTouches = 0;
@@ -42,7 +43,7 @@ bool attachment_map_iter_compare_key(const T& a, const T& b)
return a.first < b.first;
}
bool LLPosOverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const
bool LLVector3OverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const
{
pos = LLVector3(0,0,0);
mesh_id = LLUUID();
@@ -60,7 +61,7 @@ bool LLPosOverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const
return found;
}
void LLPosOverrideMap::showJointPosOverrides( std::ostringstream& os ) const
void LLVector3OverrideMap::showJointVector3Overrides( std::ostringstream& os ) const
{
map_type::const_iterator max_it = std::max_element(m_map.begin(),
m_map.end(),
@@ -73,23 +74,23 @@ void LLPosOverrideMap::showJointPosOverrides( std::ostringstream& os ) const
}
}
U32 LLPosOverrideMap::count() const
U32 LLVector3OverrideMap::count() const
{
return m_map.size();
}
void LLPosOverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos)
void LLVector3OverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos)
{
m_map[mesh_id] = pos;
}
bool LLPosOverrideMap::remove(const LLUUID& mesh_id)
bool LLVector3OverrideMap::remove(const LLUUID& mesh_id)
{
U32 remove_count = m_map.erase(mesh_id);
return (remove_count > 0);
}
void LLPosOverrideMap::clear()
void LLVector3OverrideMap::clear()
{
m_map.clear();
}
@@ -107,6 +108,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() :
@@ -129,7 +132,7 @@ LLJoint::LLJoint(S32 joint_num) :
// 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()
//-----------------------------------------------------------------------------
@@ -239,6 +275,7 @@ void LLJoint::addChild(LLJoint* joint)
joint->mParent->removeChild(joint);
mChildren.push_back(joint);
//LL_INFOS() << getName() << " +child " << joint->getName() << LL_ENDL;
joint->mXform.setParent(&mXform);
joint->mParent = this;
joint->touch();
@@ -254,7 +291,7 @@ void LLJoint::removeChild(LLJoint* joint)
if (iter != mChildren.end())
{
mChildren.erase(iter);
//LL_INFOS() << getName() << " -child " << joint->getName() << LL_ENDL;
joint->mXform.setParent(NULL);
joint->mParent = NULL;
joint->touch();
@@ -273,6 +310,7 @@ void LLJoint::removeAllChildren()
child_list_t::iterator curiter = iter++;
LLJoint* joint = *curiter;
mChildren.erase(curiter);
//LL_INFOS() << getName() << " -child " << joint->getName() << LL_ENDL;
joint->mXform.setParent(NULL);
joint->mParent = NULL;
joint->touch();
@@ -290,43 +328,113 @@ 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 )
void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides )
{
if (pos != getPosition())
LLVector3 pos(requested_pos);
LLVector3 active_override;
LLUUID mesh_id;
if (apply_attachment_overrides && m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override))
{
if (pos != active_override && do_debug_joint(getName()))
{
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;
}
LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
}
mXform.setPosition(pos);
touch(MATRIX_DIRTY | POSITION_DIRTY);
if (pos != getPosition())
{
mXform.setPosition(pos);
touch(MATRIX_DIRTY | POSITION_DIRTY);
}
}
void LLJoint::setDefaultPosition( const LLVector3& pos )
{
mDefaultPosition = pos;
}
const LLVector3& LLJoint::getDefaultPosition() const
{
return mDefaultPosition;
}
void LLJoint::setDefaultScale( const LLVector3& scale )
{
mDefaultScale = scale;
}
const LLVector3& LLJoint::getDefaultScale() const
{
return mDefaultScale;
}
void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info )
{
std::ostringstream os;
os << joint.m_posBeforeOverrides;
joint.m_attachmentOverrides.showJointPosOverrides(os);
joint.m_attachmentPosOverrides.showJointVector3Overrides(os);
LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL;
}
void showJointScaleOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info )
{
std::ostringstream os;
os << joint.m_scaleBeforeOverrides;
joint.m_attachmentScaleOverrides.showJointVector3Overrides(os);
LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL;
}
bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const
{
LLVector3 diff = pos - getDefaultPosition();
const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm
return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset;
}
bool LLJoint::aboveJointScaleThreshold(const LLVector3& scale) const
{
LLVector3 diff = scale - getDefaultScale();
const F32 max_joint_scale_offset = 0.0001f; // 0.1 mm
return diff.lengthSquared() > max_joint_scale_offset * max_joint_scale_offset;
}
//--------------------------------------------------------------------
// addAttachmentPosOverride()
//--------------------------------------------------------------------
void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info )
void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed )
{
active_override_changed = false;
if (mesh_id.isNull())
{
return;
}
if (!m_attachmentOverrides.count())
// BENTO
// Not clear pelvis overrides are meaningful/useful.
//if (mName == "mPelvis")
//{
// return;
//}
LLVector3 before_pos;
LLUUID before_mesh_id;
bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id );
if (!m_attachmentPosOverrides.count())
{
if (do_debug_joint(getName()))
{
@@ -334,32 +442,50 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh
}
m_posBeforeOverrides = getPosition();
}
m_attachmentOverrides.add(mesh_id,pos);
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL;
}
updatePos(av_info);
m_attachmentPosOverrides.add(mesh_id,pos);
LLVector3 after_pos;
LLUUID after_mesh_id;
hasAttachmentPosOverride(after_pos, after_mesh_id);
if (!has_active_override_before || (after_pos != before_pos))
{
active_override_changed = true;
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL;
}
updatePos(av_info);
}
}
//--------------------------------------------------------------------
// removeAttachmentPosOverride()
//--------------------------------------------------------------------
void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info )
void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed )
{
active_override_changed = false;
if (mesh_id.isNull())
{
return;
}
if (m_attachmentOverrides.remove(mesh_id))
LLVector3 before_pos;
LLUUID before_mesh_id;
hasAttachmentPosOverride( before_pos, before_mesh_id );
if (m_attachmentPosOverrides.remove(mesh_id))
{
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
<< " removeAttachmentPosOverride for " << mesh_id << LL_ENDL;
showJointPosOverrides(*this, "remove", av_info);
}
updatePos(av_info);
LLVector3 after_pos;
LLUUID after_mesh_id;
bool has_active_override_after = hasAttachmentPosOverride(after_pos, after_mesh_id);
if (!has_active_override_after || (after_pos != before_pos))
{
active_override_changed = true;
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
<< " removeAttachmentPosOverride for " << mesh_id << LL_ENDL;
showJointPosOverrides(*this, "remove", av_info);
}
updatePos(av_info);
}
}
}
@@ -368,7 +494,7 @@ void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::str
//--------------------------------------------------------------------
bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const
{
return m_attachmentOverrides.findActiveOverride(mesh_id,pos);
return m_attachmentPosOverrides.findActiveOverride(mesh_id,pos);
}
//--------------------------------------------------------------------
@@ -376,11 +502,81 @@ bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const
//--------------------------------------------------------------------
void LLJoint::clearAttachmentPosOverrides()
{
if (m_attachmentOverrides.count())
if (m_attachmentPosOverrides.count())
{
m_attachmentOverrides.clear();
m_attachmentPosOverrides.clear();
setPosition(m_posBeforeOverrides);
setId( LLUUID::null );
}
}
//--------------------------------------------------------------------
// getAllAttachmentPosOverrides()
//--------------------------------------------------------------------
void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides,
std::set<LLVector3>& distinct_pos_overrides)
{
num_pos_overrides = m_attachmentPosOverrides.count();
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin();
for (; it != m_attachmentPosOverrides.getMap().end(); ++it)
{
distinct_pos_overrides.insert(it->second);
}
}
//--------------------------------------------------------------------
// getAllAttachmentScaleOverrides()
//--------------------------------------------------------------------
void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides,
std::set<LLVector3>& distinct_scale_overrides)
{
num_scale_overrides = m_attachmentScaleOverrides.count();
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin();
for (; it != m_attachmentScaleOverrides.getMap().end(); ++it)
{
distinct_scale_overrides.insert(it->second);
}
}
//--------------------------------------------------------------------
// showAttachmentPosOverrides()
//--------------------------------------------------------------------
void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const
{
LLVector3 active_override;
bool has_active_override;
LLUUID mesh_id;
has_active_override = m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override);
U32 count = m_attachmentPosOverrides.count();
if (count==1)
{
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.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;
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin();
for (; it != m_attachmentPosOverrides.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;
}
}
}
@@ -391,19 +587,177 @@ void LLJoint::updatePos(const std::string& av_info)
{
LLVector3 pos, found_pos;
LLUUID mesh_id;
if (m_attachmentOverrides.findActiveOverride(mesh_id,found_pos))
if (m_attachmentPosOverrides.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_attachmentPosOverrides.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);
}
//--------------------------------------------------------------------
// updateScale()
//--------------------------------------------------------------------
void LLJoint::updateScale(const std::string& av_info)
{
LLVector3 scale, found_scale;
LLUUID mesh_id;
if (m_attachmentScaleOverrides.findActiveOverride(mesh_id,found_scale))
{
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner of " << m_attachmentScaleOverrides.count() << " is mesh " << mesh_id << " scale " << found_scale << LL_ENDL;
}
scale = found_scale;
}
else
{
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner is scaleBeforeOverrides " << m_scaleBeforeOverrides << LL_ENDL;
}
scale = m_scaleBeforeOverrides;
}
setScale(scale);
}
//--------------------------------------------------------------------
// addAttachmentScaleOverride()
//--------------------------------------------------------------------
void LLJoint::addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info )
{
if (mesh_id.isNull())
{
return;
}
if (!m_attachmentScaleOverrides.count())
{
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_scaleBeforeOverrides " << getScale() << LL_ENDL;
}
m_scaleBeforeOverrides = getScale();
}
m_attachmentScaleOverrides.add(mesh_id,scale);
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentScaleOverride for mesh " << mesh_id << " scale " << scale << LL_ENDL;
}
updateScale(av_info);
}
//--------------------------------------------------------------------
// removeAttachmentScaleOverride()
//--------------------------------------------------------------------
void LLJoint::removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info )
{
if (mesh_id.isNull())
{
return;
}
if (m_attachmentScaleOverrides.remove(mesh_id))
{
if (do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
<< " removeAttachmentScaleOverride for " << mesh_id << LL_ENDL;
showJointScaleOverrides(*this, "remove", av_info);
}
updateScale(av_info);
}
}
//--------------------------------------------------------------------
// hasAttachmentScaleOverride()
//--------------------------------------------------------------------
bool LLJoint::hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const
{
return m_attachmentScaleOverrides.findActiveOverride(mesh_id,scale);
}
//--------------------------------------------------------------------
// clearAttachmentScaleOverrides()
//--------------------------------------------------------------------
void LLJoint::clearAttachmentScaleOverrides()
{
if (m_attachmentScaleOverrides.count())
{
m_attachmentScaleOverrides.clear();
setScale(m_scaleBeforeOverrides);
}
}
//--------------------------------------------------------------------
// showAttachmentScaleOverrides()
//--------------------------------------------------------------------
void LLJoint::showAttachmentScaleOverrides(const std::string& av_info) const
{
LLVector3 active_override;
bool has_active_override;
LLUUID mesh_id;
has_active_override = m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override);
U32 count = m_attachmentScaleOverrides.count();
if (count==1)
{
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin();
std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : "";
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
<< " has single attachment scale override " << highlight << "" << it->second << " default " << mDefaultScale << LL_ENDL;
}
else if (count>1)
{
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment scale overrides" << LL_ENDL;
std::set<LLVector3> distinct_offsets;
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin();
for (; it != m_attachmentScaleOverrides.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 " << mDefaultScale << LL_ENDL;
}
}
}
// 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()
//--------------------------------------------------------------------
@@ -527,13 +881,22 @@ const LLVector3& LLJoint::getScale()
//--------------------------------------------------------------------
// setScale()
//--------------------------------------------------------------------
void LLJoint::setScale( const LLVector3& scale )
void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_overrides )
{
// if (mXform.getScale() != scale)
{
mXform.setScale(scale);
touch();
}
LLVector3 scale(requested_scale);
LLUUID mesh_id;
LLVector3 active_override;
if (apply_attachment_overrides && m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override))
{
if (scale != active_override && do_debug_joint(getName()))
{
LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale
<< " overriden by attachment " << active_override << LL_ENDL;
}
scale = active_override;
}
mXform.setScale(scale);
touch();
}

View File

@@ -40,24 +40,33 @@
#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;
// Need to set this to count of animate-able joints,
// currently = #bones + #collision_volumes + #attachments + 2,
// rounded to next multiple of 4.
const U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 216; // 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;
class LLPosOverrideMap
class LLVector3OverrideMap
{
public:
LLPosOverrideMap() {}
LLVector3OverrideMap() {}
bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const;
void showJointPosOverrides(std::ostringstream& os) const;
void showJointVector3Overrides(std::ostringstream& os) const;
U32 count() const;
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;
};
//-----------------------------------------------------------------------------
@@ -85,17 +94,26 @@ public:
POSITION_DIRTY = 0x1 << 2,
ALL_DIRTY = 0x7
};
public:
enum SupportCategory
{
SUPPORT_BASE,
SUPPORT_EXTENDED
};
protected:
std::string mName;
SupportCategory mSupport;
// parent joint
LLJoint *mParent;
// explicit transformation members
LLXformMatrix mXform;
LLUUID mId;
LLVector3 mDefaultPosition;
LLVector3 mDefaultScale;
public:
U32 mDirtyFlags;
BOOL mUpdateXform;
@@ -103,6 +121,10 @@ public:
// describes the skin binding pose
LLVector3 mSkinOffset;
// Endpoint of the bone, if applicable. This is only relevant for
// external programs like Blender, and for diagnostic display.
LLVector3 mEnd;
S32 mJointNum;
// child joints
@@ -112,11 +134,21 @@ public:
// debug statics
static S32 sNumTouches;
static S32 sNumUpdates;
typedef std::set<std::string> debug_joint_name_t;
static debug_joint_name_t s_debugJointNames;
static void setDebugJointNames(const debug_joint_name_t& names);
static void setDebugJointNames(const std::string& names_string);
LLPosOverrideMap m_attachmentOverrides;
// Position overrides
LLVector3OverrideMap m_attachmentPosOverrides;
LLVector3 m_posBeforeOverrides;
// Scale overrides
LLVector3OverrideMap m_attachmentScaleOverrides;
LLVector3 m_scaleBeforeOverrides;
void updatePos(const std::string& av_info);
void updateScale(const std::string& av_info);
public:
LLJoint();
@@ -138,6 +170,19 @@ public:
const std::string& getName() const { return mName; }
void setName( const std::string &name ) { mName = name; }
// joint num
S32 getJointNum() const { return mJointNum; }
void setJointNum(S32 joint_num);
// get/set support
SupportCategory getSupport() const { return mSupport; }
void setSupport( const SupportCategory& support) { mSupport = support; }
void setSupport( const std::string& support_string);
// get/set end point
void setEnd( const LLVector3& end) { mEnd = end; }
const LLVector3& getEnd() const { return mEnd; }
// getParent
LLJoint *getParent() { return mParent; }
@@ -154,10 +199,16 @@ public:
// get/set local position
const LLVector3& getPosition();
void setPosition( const LLVector3& pos );
void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false );
// Tracks the default position defined by the skeleton
void setDefaultPosition( const LLVector3& pos );
const LLVector3& getDefaultPosition() const;
// Tracks the default scale defined by the skeleton
void setDefaultScale( const LLVector3& scale );
const LLVector3& getDefaultScale() const;
// get/set world position
LLVector3 getWorldPosition();
LLVector3 getLastWorldPosition();
@@ -174,7 +225,7 @@ public:
// get/set local scale
const LLVector3& getScale();
void setScale( const LLVector3& scale );
void setScale( const LLVector3& scale, bool apply_attachment_overrides = false );
// get/set world matrix
const LLMatrix4a &getWorldMatrix();
@@ -197,21 +248,28 @@ public:
virtual BOOL isAnimatable() const { return TRUE; }
S32 getJointNum() const { return mJointNum; }
void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info );
void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info );
void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed );
void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed );
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; }
//Setter for the joints id
void setId( const LLUUID& id ) { mId = id;}
void addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info );
void removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info );
bool hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const;
void clearAttachmentScaleOverrides();
void showAttachmentScaleOverrides(const std::string& av_info) const;
// <edit>
std::string exportString(U32 tabs = 0);
// </edit>
void getAllAttachmentPosOverrides(S32& num_pos_overrides,
std::set<LLVector3>& distinct_pos_overrides);
void getAllAttachmentScaleOverrides(S32& num_scale_overrides,
std::set<LLVector3>& distinct_scale_overrides);
// These are used in checks of whether a pos/scale override is considered significant.
bool aboveJointPosThreshold(const LLVector3& pos) const;
bool aboveJointScaleThreshold(const LLVector3& scale) const;
std::string exportString(U32 tabs);
};
#endif // LL_LLJOINT_H

View File

@@ -1049,7 +1049,7 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
{
case CONSTRAINT_TARGET_TYPE_GROUND:
target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos);
target_pos += mCharacter->getHoverOffset();
//target_pos += mCharacter->getHoverOffset();
// LL_INFOS() << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
break;
case CONSTRAINT_TARGET_TYPE_BODY:
@@ -1468,7 +1468,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;
@@ -1514,7 +1514,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
{
@@ -1710,6 +1717,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
{
@@ -1974,6 +1987,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");
@@ -1987,6 +2002,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);
@@ -1994,6 +2022,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)
{
@@ -2011,6 +2040,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");
@@ -2029,37 +2060,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;
@@ -2255,7 +2303,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
LLCharacter* character = *char_iter;
// look for an existing instance of this motion
LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->findMotion(asset_uuid);
LLKeyframeMotion* motionp = dynamic_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid));
if (motionp)
{
if (0 == status)
@@ -2270,8 +2318,8 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
U8* buffer = new U8[size];
file.read((U8*)buffer, size); /*Flawfinder: ignore*/
LL_DEBUGS() << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;
LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;
LLDataPackerBinaryBuffer dp(buffer, size);
if (motionp->deserialize(dp))
@@ -2315,9 +2363,9 @@ void LLKeyframeDataCache::dumpDiagInfo(int quiet)
if (quiet < 2)
{
LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
LL_INFOS() << " Global Motion Table" << LL_ENDL;
LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
LL_INFOS() << " Global Motion Table (DEBUG only)" << LL_ENDL;
LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
}
// print each loaded mesh, and it's memory usage
@@ -2335,8 +2383,8 @@ void LLKeyframeDataCache::dumpDiagInfo(int quiet)
if (motion_list_p)
{
joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
total_size += joint_motion_kb;
joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
total_size += joint_motion_kb;
}
}

View File

@@ -180,8 +180,8 @@ LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) :
mDeactivateCallback(NULL),
mDeactivateCallbackUserData(NULL)
{
for (int i=0; i<3; ++i)
memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
for (S32 i=0; i<3; ++i)
memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
}
//-----------------------------------------------------------------------------
@@ -237,9 +237,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 )

View File

@@ -274,7 +274,7 @@ protected:
F32 mSendStopTimestamp; // time when simulator should be told to stop this motion
F32 mResidualWeight; // blend weight at beginning of stop motion phase
F32 mFadeWeight; // for fading in and out based on LOD
U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority
U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority
void (*mDeactivateCallback)(void* data);
void* mDeactivateCallbackUserData;
};

View File

@@ -42,7 +42,7 @@
#include "llanimationstates.h"
#include "llstl.h"
const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4;
const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4;
const U32 MAX_MOTION_INSTANCES = 32;
//-----------------------------------------------------------------------------
@@ -517,8 +517,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);
}
//-----------------------------------------------------------------------------
@@ -582,9 +582,9 @@ static LLFastTimer::DeclareTimer 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();

View File

@@ -253,7 +253,7 @@ protected:
S32 mTimeStepCount;
F32 mLastInterp;
U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS];
//<singu>
public:

View File

@@ -2540,7 +2540,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++;
@@ -2554,15 +2554,19 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
joint = weights[idx++];
}
}
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);
}
for (U32 k=0; k<4; k++)
{
joints_with_weights[k] = (F32) joints[k] + wght[k];
}
F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW];
if (wsum <= 0.f)
{
wght = LLVector4(0.999f,0.f,0.f,0.f);
}
for (U32 k=0; k<4; k++)
{
F32 f_combined = (F32) joints[k] + wght[k];
joints_with_weights[k] = f_combined;
// Any weights we added above should wind up non-zero and applied to a specific bone.
// A failure here would indicate a floating point precision error in the math.
llassert((k >= cur_influence) || (f_combined - S32(f_combined) > 0.0f));
}
face.mWeights[cur_vertex].loadua(joints_with_weights.mV);
cur_vertex++;
@@ -4600,6 +4604,7 @@ LLVolumeFace::LLVolumeFace() :
mTexCoords(NULL),
mIndices(NULL),
mWeights(NULL),
mWeightsScrubbed(FALSE),
mOctree(NULL),
mOptimized(FALSE)
{
@@ -4625,6 +4630,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mTexCoords(NULL),
mIndices(NULL),
mWeights(NULL),
mWeightsScrubbed(FALSE),
mOctree(NULL),
mOptimized(FALSE)
{
@@ -4687,6 +4693,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
{
LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
}
mWeightsScrubbed = src.mWeightsScrubbed;
}
if (mNumIndices)
@@ -5992,7 +5999,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
}
else
{ //degenerate, make up a value
normal.set(0,0,1);
if(normal.getF32ptr()[2] >= 0)
normal.set(0.f,0.f,1.f);
else
normal.set(0.f,0.f,-1.f);
}
llassert(std::isfinite(normal.getF32ptr()[0]));

View File

@@ -959,6 +959,8 @@ public:
// mWeights.size() should be empty or match mVertices.size()
LLVector4a* mWeights;
mutable BOOL mWeightsScrubbed;
LLOctreeNode<LLVolumeTriangle>* mOctree;
//whether or not face has been cache optimized

View File

@@ -929,8 +929,10 @@ LLDAELoader::LLDAELoader(
texture_load_func_t texture_load_func,
state_callback_t state_cb,
void* opaque_userdata,
JointTransformMap& jointMap,
JointSet& jointsFromNodes,
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
std::map<std::string, std::string>& jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit,
bool preprocess)
: LLModelLoader(
@@ -941,10 +943,12 @@ LLDAELoader::LLDAELoader(
texture_load_func,
state_cb,
opaque_userdata,
jointMap,
jointsFromNodes),
mGeneratedModelLimit(modelLimit),
mPreprocessDAE(preprocess)
jointTransformMap,
jointsFromNodes,
jointAliasMap,
maxJointsPerMesh),
mGeneratedModelLimit(modelLimit),
mPreprocessDAE(preprocess)
{
}
@@ -1264,28 +1268,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" );
U32 skeleton_count = dae->getDatabase()->getElementCount( NULL, "skeleton" );
std::vector<domInstance_controller::domSkeleton*> skeletons;
for (U32 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 );
//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 )
@@ -1312,74 +1317,81 @@ 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 )
//Has one or more skeletons
for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin();
skel_it != skeletons.end(); ++skel_it)
{
//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 )
domInstance_controller::domSkeleton* pSkeleton = *skel_it;
//Get the root node of the skeleton
daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
if ( pSkeletonRootNode )
{
//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;
//Once we have the root node - start acccessing it's joint components
const int jointCnt = mJointMap.size();
JointMap :: const_iterator jointIt = mJointMap.begin();
//Setup the resolver
daeSIDResolver resolver( pSkeletonRootNode, str );
//Look for the joint
domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
if ( pJoint )
//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 )
{
//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() );
//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;
LLMatrix4 workingTransform;
//Setup the resolver
daeSIDResolver resolver( pSkeletonRootNode, str );
//Translation via SID
if ( pTranslateA )
//Look for the joint
domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
if ( pJoint )
{
extractTranslation( pTranslateA, workingTransform );
}
else
if ( pTranslateB )
// 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( pTranslateB, workingTransform );
extractTranslation( pTranslateA, workingTransform );
}
else
{
//Translation via child from element
daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
if ( pTranslateB )
{
LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
missingSkeletonOrScene = true;
extractTranslation( pTranslateB, workingTransform );
}
else
if ( pTranslateElement )
{
//Translation via child from element
daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
{
extractTranslationViaElement( pTranslateElement, workingTransform );
LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
missingSkeletonOrScene = true;
}
else
{
extractTranslationViaSID( pJoint, workingTransform );
}
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
@@ -1423,7 +1435,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
name = mJointMap[name];
}
model->mSkinInfo.mJointNames.push_back(name);
model->mSkinInfo.mJointMap[name] = j;
model->mSkinInfo.mJointNums.push_back(-1);
}
}
else
@@ -1441,7 +1453,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
name = mJointMap[name];
}
model->mSkinInfo.mJointNames.push_back(name);
model->mSkinInfo.mJointMap[name] = j;
model->mSkinInfo.mJointNums.push_back(-1);
}
}
}
@@ -1469,8 +1481,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);
}
}
}
@@ -1486,9 +1497,18 @@ 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
// 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();
//The joints are reset in the dtor
if ( getRigWithSceneParity() )
//if ( getRigWithSceneParity() )
{
JointMap :: const_iterator masterJointIt = mJointMap.begin();
JointMap :: const_iterator masterJointItEnd = mJointMap.end();
@@ -1502,10 +1522,17 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
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, "");
{
const LLVector3& joint_pos = jointTransform.getTranslation();
if (pJoint->aboveJointPosThreshold(joint_pos))
{
bool override_changed; // not used
pJoint->addAttachmentPosOverride(joint_pos, fake_mesh_id, "", override_changed);
if (model->mSkinInfo.mLockScaleIfJointPosition)
{
pJoint->addAttachmentScaleOverride(pJoint->getDefaultScale(), fake_mesh_id, "");
}
}
}
else
{
@@ -1528,16 +1555,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;
}
}
@@ -1980,13 +2006,13 @@ void LLDAELoader::processJointNode( domNode* pNode, JointTransformMap& jointTran
//-----------------------------------------------------------------------------
daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string const & name )
{
daeElement* pChildOfElement = pElement->getChild(name.c_str());
daeElement* pChildOfElement = pElement->getChild(name.c_str());
if (pChildOfElement)
{
return pChildOfElement;
}
LL_WARNS() << "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
return NULL;
LL_DEBUGS("Mesh")<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
return NULL;
}
void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae )
@@ -2351,7 +2377,11 @@ std::string LLDAELoader::getElementLabel(daeElement *element)
// retrieve index to distinguish items inside same parent
size_t ind = 0;
parent->getChildren().find(element, ind);
index_string = "_" + boost::lexical_cast<std::string>(ind);
if (ind > 0)
{
index_string = "_" + boost::lexical_cast<std::string>(ind);
}
// if parent has a name or ID, use it
std::string name = parent->getAttribute("name");

View File

@@ -53,11 +53,13 @@ public:
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);

View File

@@ -51,8 +51,12 @@ std::string model_names[] =
const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string);
LLModel::LLModel(LLVolumeParams& params, F32 detail)
: LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0)
, mPelvisOffset( 0.0f ), mStatus(NO_ERRORS), mSubmodelID(0)
: LLVolume(params, detail),
mNormalizedScale(1,1,1),
mNormalizedTranslation(0,0,0),
mPelvisOffset( 0.0f ),
mStatus(NO_ERRORS),
mSubmodelID(0)
{
mDecompID = -1;
mLocalID = -1;
@@ -677,6 +681,7 @@ LLSD LLModel::writeModel(
const LLModel::Decomposition& decomp,
BOOL upload_skin,
BOOL upload_joints,
BOOL lock_scale_if_joint_position,
BOOL nowrite,
BOOL as_slm,
int submodel_id)
@@ -696,7 +701,7 @@ LLSD LLModel::writeModel(
if (skinning)
{ //write skinning block
mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints);
mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints, lock_scale_if_joint_position);
}
if (!decomp.mBaseHull.empty() ||
@@ -1042,6 +1047,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
weight_map::iterator best = iter_up;
// iter == mSkinWeights.end()...
F32 min_dist = (iter_up->first - pos).magVec();
bool done = false;
@@ -1390,8 +1396,17 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
return true;
}
LLMeshSkinInfo::LLMeshSkinInfo():
mPelvisOffset(0.0),
mLockScaleIfJointPosition(false),
mInvalidJointsScrubbed(false)
{
}
LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin)
LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin):
mPelvisOffset(0.0),
mLockScaleIfJointPosition(false),
mInvalidJointsScrubbed(false)
{
fromLLSD(skin);
}
@@ -1400,10 +1415,11 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
{
if (skin.has("joint_names"))
{
const U32 joint_count = llmin((U32)skin["joint_names"].size(),(U32)64);
const U32 joint_count = skin["joint_names"].size();
for (U32 i = 0; i < joint_count; ++i)
{
mJointNames.push_back(skin["joint_names"][i]);
mJointNums.push_back(-1);
}
}
@@ -1456,9 +1472,18 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
{
mPelvisOffset = skin["pelvis_offset"].asReal();
}
if (skin.has("lock_scale_if_joint_position"))
{
mLockScaleIfJointPosition = skin["lock_scale_if_joint_position"].asBoolean();
}
else
{
mLockScaleIfJointPosition = false;
}
}
LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const
{
LLSD ret;
@@ -1496,6 +1521,11 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
}
}
if (lock_scale_if_joint_position)
{
ret["lock_scale_if_joint_position"] = lock_scale_if_joint_position;
}
ret["pelvis_offset"] = mPelvisOffset;
}

View File

@@ -42,18 +42,21 @@ class domMesh;
class LLMeshSkinInfo
{
public:
LLUUID mMeshID;
std::vector<std::string> mJointNames;
std::vector<LLMatrix4> mInvBindMatrix;
std::vector<LLMatrix4> mAlternateBindMatrix;
std::map<std::string, U32> mJointMap;
LLMeshSkinInfo() { }
LLMeshSkinInfo();
LLMeshSkinInfo(LLSD& data);
void fromLLSD(LLSD& data);
LLSD asLLSD(bool include_joints) const;
LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
LLUUID mMeshID;
std::vector<std::string> mJointNames;
mutable std::vector<S32> mJointNums;
std::vector<LLMatrix4> mInvBindMatrix;
std::vector<LLMatrix4> mAlternateBindMatrix;
LLMatrix4 mBindShapeMatrix;
float mPelvisOffset;
bool mLockScaleIfJointPosition;
bool mInvalidJointsScrubbed;
};
class LLModel : public LLVolume
@@ -138,6 +141,7 @@ public:
const LLModel::Decomposition& decomp,
BOOL upload_skin,
BOOL upload_joints,
BOOL lock_scale_if_joint_position,
BOOL nowrite = FALSE,
BOOL as_slm = FALSE,
int submodel_id = 0);

View File

@@ -109,9 +109,11 @@ LLModelLoader::LLModelLoader(
texture_load_func_t texture_load_func,
state_callback_t state_cb,
void* opaque_userdata,
JointTransformMap& jointMap,
JointSet& jointsFromNodes )
: mJointList( jointMap )
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)
, mMaxJointsPerMesh(maxJointsPerMesh)
, mJointMap(legalJointNamesMap)
{
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");
assert_main_thread();
sActiveLoaderList.push_back(this) ;
}
@@ -258,6 +150,23 @@ void LLModelLoader::run()
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
}
// static
bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename)
{
slm_filename = model_filename;
std::string::size_type i = model_filename.rfind(".");
if (i != std::string::npos)
{
slm_filename.replace(i, model_filename.size()-1, ".slm");
return true;
}
else
{
return false;
}
}
bool LLModelLoader::doLoadModel()
{
//first, look for a .slm file of the same name that was modified later
@@ -265,20 +174,17 @@ bool LLModelLoader::doLoadModel()
if (mTrySLM)
{
std::string filename = mFilename;
std::string::size_type i = filename.rfind(".");
if (i != std::string::npos)
{
filename.replace(i, filename.size()-1, ".slm");
std::string slm_filename;
if (getSLMFilename(mFilename, slm_filename))
{
llstat slm_status;
if (LLFile::stat(filename, &slm_status) == 0)
if (LLFile::stat(slm_filename, &slm_status) == 0)
{ //slm file exists
llstat dae_status;
if (LLFile::stat(mFilename, &dae_status) != 0 ||
dae_status.st_mtime < slm_status.st_mtime)
{
if (loadFromSLM(filename))
if (loadFromSLM(slm_filename))
{ //slm successfully loaded, if this fails, fall through and
//try loading from dae
@@ -476,8 +382,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
@@ -486,58 +390,26 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
//It's OK that both could end up being true, both default to false
if ( isJointPositionUploadOK )
// 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 +421,39 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
return false;
}
bool result = false;
// 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;
}
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();
// 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;
}

View File

@@ -37,7 +37,7 @@ 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::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
@@ -116,7 +116,8 @@ public:
//map of avatar joints as named in COLLADA assets to internal joint names
JointMap mJointMap;
JointTransformMap& mJointList;
JointSet& mJointsFromNode;
JointNameSet& mJointsFromNode;
U32 mMaxJointsPerMesh;
LLModelLoader(
std::string filename,
@@ -125,16 +126,20 @@ public:
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; }
virtual void setNoOptimize() { mNoOptimize = true; }
virtual void run();
static bool getSLMFilename(const std::string& model_filename, std::string& slm_filename);
// Will try SLM or derived class OpenFile as appropriate
//
virtual bool doLoadModel();
@@ -158,7 +163,6 @@ public:
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
void critiqueJointToNodeMappingFromScene( void );
//Determines if a rig is a legacy from the joint list
bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
@@ -166,9 +170,6 @@ public:
//Determines if a rig is suitable for upload
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
@@ -180,7 +181,7 @@ public:
//-----------------------------------------------------------------------------
bool isNodeAJoint(const char* name)
{
return mJointMap.find(name) != mJointMap.end();
return name != NULL && mJointMap.find(name) != mJointMap.end();
}
protected:
@@ -189,17 +190,14 @@ protected:
LLModelLoader::joint_lookup_func_t mJointLookupFunc;
LLModelLoader::texture_load_func_t mTextureLoadFunc;
LLModelLoader::state_callback_t mStateCallback;
void* mOpaqueData;
void* mOpaqueData;
bool mRigParityWithScene;
bool mRigValidJointUpload;
bool mLegacyRigValid;
bool mNoNormalize;
bool mNoOptimize;
JointSet mMasterJointList;
JointSet mMasterLegacyJointList;
JointTransformMap mJointTransformMap;
static std::list<LLModelLoader*> sActiveLoaderList;

View File

@@ -440,6 +440,7 @@ set(viewer_SOURCE_FILES
llscrollingpanelparambase.cpp
llselectmgr.cpp
llshareavatarhandler.cpp
llskinningutil.cpp
llsky.cpp
llslurl.cpp
llspatialpartition.cpp
@@ -973,6 +974,7 @@ set(viewer_HEADER_FILES
llscrollingpanelparambase.h
llselectmgr.h
llsimplestat.h
llskinningutil.h
llsky.h
llslurl.h
llspatialpartition.h

View File

@@ -26,7 +26,7 @@
ATTRIBUTE vec4 weight4;
uniform mat3x4 matrixPalette[52];
uniform mat3x4 matrixPalette[MAX_JOINTS_PER_MESH_OBJECT];
uniform float maxWeight;
mat4 getObjectSkinnedTransform()

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +1,232 @@
<?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>
<linden_skeleton num_bones="133" 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.025 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.025 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.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
<bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" 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.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" 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.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" 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.000" 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.000" 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.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" 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.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
<bone connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 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.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 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.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 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.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
<bone connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
</bone>
</bone>
</bone>
<bone connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 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.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.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.035 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.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
<bone connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
</bone>
<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.000" 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.000" 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.000" 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.000" 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.000" 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.000" 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="false" 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="false" 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.000" 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.000" group="Limb" name="mHindLimb4Right" 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>
</bone>
</linden_skeleton>

View File

@@ -4580,7 +4580,7 @@ void LLAgent::requestLeaveGodMode()
sendReliableMessage();
}
extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
extern void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value);
extern std::string get_sequential_numbered_file_name(const std::string& prefix,
const std::string& suffix);
@@ -4606,7 +4606,7 @@ void LLAgent::dumpSentAppearance(const std::string& dump_prefix)
if (appearance_version_param)
{
F32 value = appearance_version_param->getWeight();
dump_visual_param(outfile, appearance_version_param, value);
dump_visual_param(file, appearance_version_param, value);
}
for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();

View File

@@ -2624,7 +2624,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
// attachments, even those that are not being removed. This is
// needed to get joint positions all slammed down to their
// pre-attachment states.
gAgentAvatarp->clearAttachmentPosOverrides();
gAgentAvatarp->clearAttachmentOverrides();
// Take off the attachments that will no longer be in the outfit.
// (but don't remove attachments until avatar is fully loaded - should reduce random attaching/detaching/reattaching at log-on)
@@ -2638,7 +2638,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); it != objects_to_retain.end(); ++it)
{
LLViewerObject *objectp = *it;
gAgentAvatarp->addAttachmentPosOverridesForObject(objectp);
gAgentAvatarp->addAttachmentOverridesForObject(objectp);
}
// Add new attachments to match those requested.

View File

@@ -93,6 +93,7 @@
#include "llweb.h"
#include "llsecondlifeurls.h"
#include "llavatarrenderinfoaccountant.h"
#include "llskinningutil.h"
// Linden library includes
#include "llavatarnamecache.h"
@@ -674,6 +675,10 @@ bool LLAppViewer::init()
LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
// initialize skinning util
LLSkinningUtil::initClass();
//set the max heap size.
initMaxHeapSize() ;

View File

@@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "lldrawpoolavatar.h"
#include "llskinningutil.h"
#include "llrender.h"
#include "llvoavatar.h"
@@ -366,7 +367,7 @@ void LLDrawPoolAvatar::endPostDeferredAlpha()
void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
{
const S32 actual_pass[] =
static const S32 actual_pass[] =
{ //map post deferred pass numbers to what render() expects
2, //skinned
4, // rigged fullbright
@@ -1516,33 +1517,18 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
{
if (sShaderLevel > 0)
{ //upload matrix palette to shader
LLMatrix4 mat[JOINT_COUNT];
// upload matrix palette to shader
LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
U32 count = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT);
for (U32 i = 0; i < count; ++i)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
if(!joint)
{
joint = avatar->getJoint("mRoot");
}
if (joint)
{
LLMatrix4a tmp;
tmp.loadu((F32*)skin->mInvBindMatrix[i].mMatrix);
tmp.setMul(joint->getWorldMatrix(),tmp);
mat[i] = LLMatrix4(tmp.getF32ptr());
}
}
stop_glerror();
F32 mp[JOINT_COUNT*12];
F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12];
for (U32 i = 0; i < count; ++i)
{
F32* m = (F32*) mat[i].mMatrix;
F32* m = (F32*) mat[i].getF32ptr();
U32 idx = i*12;

View File

@@ -51,6 +51,7 @@
#include "llmatrix4a.h"
#include "llnotificationsutil.h"
#include "llsdutil_math.h"
#include "llskinningutil.h"
#include "lltextbox.h"
#include "lltoolmgr.h"
#include "llui.h"
@@ -648,6 +649,10 @@ void LLFloaterModelPreview::draw()
{
LLFloater::draw();
if (!mModelPreview)
{
return;
}
mModelPreview->update();
if (!mModelPreview->mLoading)
@@ -1190,7 +1195,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
, mModelNoErrors( true )
, mRigParityWithScene( false )
, mLastJointUpdate( false )
{
mNeedsUpdate = TRUE;
@@ -1309,15 +1313,16 @@ U32 LLModelPreview::calcResourceCost()
std::stringstream ostr;
LLSD ret = LLModel::writeModel(ostr,
instance.mLOD[4],
instance.mLOD[3],
instance.mLOD[2],
instance.mLOD[1],
instance.mLOD[0],
decomp,
mFMP->childGetValue("upload_skin").asBoolean(),
mFMP->childGetValue("upload_joints").asBoolean(),
TRUE,
instance.mLOD[4],
instance.mLOD[3],
instance.mLOD[2],
instance.mLOD[1],
instance.mLOD[0],
decomp,
mFMP->childGetValue("upload_skin").asBoolean(),
mFMP->childGetValue("upload_joints").asBoolean(),
false,
TRUE,
FALSE,
instance.mModel->mSubmodelID);
@@ -1696,7 +1701,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
instance.mLOD[LLModel::LOD_LOW],
instance.mLOD[LLModel::LOD_IMPOSTOR],
decomp,
save_skinweights, save_joint_positions,
save_skinweights,
save_joint_positions,
FALSE, TRUE, instance.mModel->mSubmodelID);
data["mesh"][instance.mModel->mLocalID] = str.str();
@@ -1723,6 +1729,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->mCollisionVolumes.size(); i++)
{
joint_map[av->mCollisionVolumes[i]->getName()] = av->mCollisionVolumes[i]->getName();
}
}
void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm)
{
assert_main_thread();
@@ -1765,8 +1785,11 @@ 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,
filename,
lod,
&LLModelPreview::loadedCallback,
&LLModelPreview::lookupJointByName,
@@ -1775,6 +1798,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"));
@@ -3401,9 +3426,11 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
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++)).loadua(w.mV);
@@ -4098,20 +4125,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)
@@ -4160,6 +4173,22 @@ BOOL LLModelPreview::render()
}
}
}
if (joint_positions)
{
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader)
{
gDebugProgram.bind();
}
getPreviewAvatar()->renderCollisionVolumes();
getPreviewAvatar()->renderBones();
if (shader)
{
shader->bind();
}
}
}
}
@@ -4295,7 +4324,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();

View File

@@ -253,6 +253,7 @@ public:
virtual BOOL needsRender() { return mNeedsUpdate; }
void setPreviewLOD(S32 lod);
void clearModel(S32 lod);
void getJointAliases(JointMap& joint_map);
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
void loadModelCallback(S32 lod);
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
@@ -404,7 +405,7 @@ private:
bool mLastJointUpdate;
JointSet mJointsFromNode;
JointNameSet mJointsFromNode;
JointTransformMap mJointTransformMap;
LLPointer<LLVOAvatar> mPreviewAvatar;

View File

@@ -0,0 +1,225 @@
/**
* @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"
// static
void LLSkinningUtil::initClass()
{
}
// static
U32 LLSkinningUtil::getMaxJointCount()
{
U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT;
return result;
}
// static
U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
{
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
}
// static
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
{
if (skin->mInvalidJointsScrubbed)
{
return;
}
for (U32 j = 0; j < skin->mJointNames.size(); ++j)
{
// Fix invalid names to "mPelvis". Currently meshes with
// invalid names will be blocked on upload, so this is just
// needed for handling of any legacy bad data.
if (!avatar->getJoint(skin->mJointNames[j]))
{
LL_DEBUGS("Avatar") << "Mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
skin->mJointNames[j] = "mPelvis";
}
}
skin->mInvalidJointsScrubbed = true;
}
// static
void LLSkinningUtil::initSkinningMatrixPalette(
LLMatrix4a* mat,
S32 count,
const LLMeshSkinInfo* skin,
LLVOAvatar *avatar)
{
for (U32 j = 0; j < (U32)count; ++j)
{
LLJoint *joint = NULL;
if( skin->mJointNums[j] <= -50 )
{
// Give up silently.
mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix);
continue;
}
else if (skin->mJointNums[j] < 0 )
{
joint = avatar->getJoint(skin->mJointNames[j]);
if (!joint)
{
LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << " Using 'root' fallback." << LL_ENDL;
joint = avatar->getJoint("mRoot");
}
if (joint)
{
//LL_INFOS() << "Found joint " << skin->mJointNames[j] << " Id = " << joint->getJointNum() << LL_ENDL;
skin->mJointNums[j] = joint->getJointNum();
}
else
{
--skin->mJointNums[j];
}
}
else
{
joint = avatar->getJoint(skin->mJointNums[j]);
if (!joint)
{
LL_WARNS_ONCE() << "Joint not found: " << skin->mJointNames[j] << " Id = " << skin->mJointNums[j] << LL_ENDL;
}
}
if (joint)
{
LLMatrix4a bind;
bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix);
mat[j].setMul(joint->getWorldMatrix(), bind);
}
else
{
mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix);
// 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 scrubInvalidJoints().
LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL;
}
}
}
// static
void LLSkinningUtil::checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
{
#ifndef LL_RELEASE_FOR_DOWNLOAD
const S32 max_joints = skin->mJointNames.size();
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
}
void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
{
const S32 max_joints = skin->mJointNames.size();
for (U32 j=0; j<num_vertices; j++)
{
F32 *w = weights[j].getF32ptr();
for (U32 k=0; k<4; ++k)
{
S32 i = llfloor(w[k]);
F32 f = w[k]-i;
i = llclamp(i,0,max_joints-1);
w[k] = i + f;
}
}
checkSkinWeights(weights, num_vertices, skin);
}
// static
void LLSkinningUtil::getPerVertexSkinMatrix(
const 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];
idx[k] = (S32) floorf(w);
wght[k] = w - floorf(w);
scale += wght[k];
}
if (handle_bad_scale && scale <= 0.f)
{
wght = LLVector4(F32_MAX,F32_MAX,F32_MAX,F32_MAX);
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);
}

View File

@@ -0,0 +1,47 @@
/**
* @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 scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
static void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
static void checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
static void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
static void getPerVertexSkinMatrix(const F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
};
#endif

View File

@@ -2912,6 +2912,10 @@ 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)
@@ -3072,7 +3076,7 @@ public:
if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS))
{
avatar->renderJoints();
renderAvatarBones(avatar);
}
if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))

View File

@@ -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()

View File

@@ -223,10 +223,10 @@ LLMenuGL* gMeshesAndMorphsMenu = NULL;
LLContextMenu* gPieRate = NULL;
LLContextMenu* gAttachScreenPieMenu = NULL;
LLContextMenu* gAttachPieMenu = NULL;
LLContextMenu* gAttachBodyPartPieMenus[8];
LLContextMenu* gAttachPieMenu2 = NULL;
LLContextMenu* gDetachPieMenu = NULL;
LLContextMenu* gDetachPieMenu2 = NULL;
LLContextMenu* gDetachScreenPieMenu = NULL;
LLContextMenu* gDetachBodyPartPieMenus[8];
LLMenuItemCallGL* gAFKMenu = NULL;
LLMenuItemCallGL* gBusyMenu = NULL;
@@ -555,6 +555,7 @@ void build_pie_menus()
// TomY TODO: what shall we do about these?
gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true);
gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true);
gDetachPieMenu2 = gMenuHolder->getChild<LLContextMenu>("Object Detach More", true);
if (gPieAvatar) delete gPieAvatar;
gPieAvatar = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_avatar.xml", gMenuHolder);
@@ -564,6 +565,7 @@ void build_pie_menus()
gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD");
gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach");
gAttachPieMenu2 = gMenuHolder->getChild<LLContextMenu>("Object Attach More");
gPieRate = gMenuHolder->getChild<LLContextMenu>("Rate Menu");
if (gPieAttachment) delete gPieAttachment;
@@ -6039,6 +6041,33 @@ class LLAvatarAddFriend : public view_listener_t
}
};
class LLAvatarResetSkeleton: public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
if(avatar)
{
avatar->resetSkeleton(false);
}
return true;
}
};
class LLAvatarResetSkeletonAndAnimations : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
if (avatar)
{
avatar->resetSkeleton(true);
}
return true;
}
};
bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection)
{
S32 option = LLNotification::getSelectedOption(notification, response);
@@ -9411,6 +9440,8 @@ void initialize_menus()
addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
addMenu(new LLObjectEnableMute(), "Avatar.EnableMute");
addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeletonAndAnimations");
addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject");
addMenu(new LLAvatarCopyUUID(), "Avatar.CopyUUID");

View File

@@ -183,8 +183,8 @@ extern LLContextMenu* gAttachScreenPieMenu;
extern LLContextMenu* gDetachScreenPieMenu;
extern LLContextMenu* gAttachPieMenu;
extern LLContextMenu* gDetachPieMenu;
extern LLContextMenu* gAttachBodyPartPieMenus[8];
extern LLContextMenu* gDetachBodyPartPieMenus[8];
extern LLContextMenu* gAttachPieMenu2;
extern LLContextMenu* gDetachPieMenu2;
extern LLMenuItemCallGL* gAFKMenu;
extern LLMenuItemCallGL* gBusyMenu;

View File

@@ -381,7 +381,7 @@ void LLViewerObject::markDead()
if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
{
// This case is needed for indirectly attached mesh objects.
av->resetJointPositionsOnDetach(mesh_id);
av->resetJointsOnDetach(mesh_id);
}
// Mark itself as dead

View File

@@ -33,6 +33,8 @@
#include "llviewerprecompiledheaders.h"
#include <boost/lexical_cast.hpp>
#include "llfeaturemanager.h"
#include "llviewershadermgr.h"
@@ -46,6 +48,8 @@
#include "llsky.h"
#include "llvosky.h"
#include "llrender.h"
#include "lljoint.h"
#include "llskinningutil.h"
#if LL_DARWIN
#include "OpenGL/OpenGL.h"
@@ -583,11 +587,15 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
}
shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) );
std::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++)
{
// Note usage of GL_VERTEX_SHADER_ARB
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB) == 0)
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0)
{
return FALSE;
}
@@ -634,7 +642,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
for (U32 i = 0; i < shaders.size(); i++)
{
// Note usage of GL_FRAGMENT_SHADER_ARB
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, NULL, index_channels[i]) == 0)
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0)
{
return FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -248,11 +248,18 @@ public:
void dumpAnimationState();
virtual LLJoint* getJoint(const std::string &name);
LLJoint* getJoint(S32 num);
void addAttachmentPosOverridesForObject(LLViewerObject *vo);
void resetJointPositionsOnDetach(const LLUUID& mesh_id);
void resetJointPositionsOnDetach(LLViewerObject *vo);
void clearAttachmentPosOverrides();
void addAttachmentOverridesForObject(LLViewerObject *vo);
void resetJointsOnDetach(const LLUUID& mesh_id);
void resetJointsOnDetach(LLViewerObject *vo);
bool jointIsRiggedTo(const std::string& joint_name);
bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo);
void clearAttachmentOverrides();
void rebuildAttachmentOverrides();
void showAttachmentOverrides(bool verbose = false) const;
void getAttachmentOverrideNames( std::set<std::string>& pos_names,
std::set<std::string>& scale_names) const;
/*virtual*/ const LLUUID& getID() const;
/*virtual*/ void addDebugText(const std::string& text);
@@ -416,7 +423,10 @@ public:
void postPelvisSetRecalc( void );
/*virtual*/ BOOL loadSkeletonNode();
void initAttachmentPoints(bool ignore_hud_joints = false);
/*virtual*/ void buildCharacter();
void resetVisualParams();
void resetSkeleton(bool reset_animations);
LLVector3 mCurRootToHeadOffset;
LLVector3 mTargetRootToHeadOffset;
@@ -444,6 +454,7 @@ public:
U32 renderSkinnedAttachments();
U32 renderTransparent(BOOL first_pass);
void renderCollisionVolumes();
void renderBones();
void renderJoints();
static void deleteCachedImages(bool clearAll=true);
static void destroyGL();
@@ -698,9 +709,12 @@ protected:
** APPEARANCE
**/
LLPointer<LLAppearanceMessageContents> mLastProcessedAppearance;
public:
void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg);
void processAvatarAppearance(LLMessageSystem* mesgsys);
void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params);
void hideSkirt();
void startAppearanceAnimation();
/*virtual*/ void bodySizeChanged();
@@ -1018,13 +1032,13 @@ private:
// General
//--------------------------------------------------------------------
public:
void getSortedJointNames(S32 joint_type, std::vector<std::string>& result) const;
static void dumpArchetypeXML_header(LLAPRFile& file, std::string const& archetype_name = "???");
static void dumpArchetypeXML_footer(LLAPRFile& file);
void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false);
void dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables);
void dumpAppearanceMsgParams( const std::string& dump_prefix,
const std::vector<F32>& paramsForDump,
const LLTEContents& tec);
const LLAppearanceMessageContents& contents);
static void dumpBakedStatus();
const std::string getBakedStatusForPrintout() const;
void dumpAvatarTEs(const std::string& context) const;
@@ -1111,6 +1125,8 @@ extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;
extern const F32 MAX_HOVER_Z;
extern const F32 MIN_HOVER_Z;
constexpr U32 NUM_ATTACHMENT_GROUPS = 24;
void dump_sequential_xml(const std::string outprefix, const LLSD& content);
#endif // LL_VOAVATAR_H

View File

@@ -394,128 +394,115 @@ static LLContextMenu* make_part_menu(const std::string& label, bool context)
void LLVOAvatarSelf::buildContextMenus()
{
gAttachBodyPartPieMenus[0] = gDetachBodyPartPieMenus[0] = NULL;
bool context(gSavedSettings.getBOOL("LiruUseContextMenus"));
std::string label = LLTrans::getString("BodyPartsRightArm");
gAttachBodyPartPieMenus[1] = make_part_menu(label, context);
gDetachBodyPartPieMenus[1] = make_part_menu(label, context);
label = LLTrans::getString("BodyPartsHead");
gAttachBodyPartPieMenus[2] = make_part_menu(label, context);
gDetachBodyPartPieMenus[2] = make_part_menu(label, context);
label = LLTrans::getString("BodyPartsLeftArm");
gAttachBodyPartPieMenus[3] = make_part_menu(label, context);
gDetachBodyPartPieMenus[3] = make_part_menu(label, context);
gAttachBodyPartPieMenus[4] = gDetachBodyPartPieMenus[4] = NULL;
label = LLTrans::getString("BodyPartsLeftLeg");
gAttachBodyPartPieMenus[5] = make_part_menu(label, context);
gDetachBodyPartPieMenus[5] = make_part_menu(label, context);
label = LLTrans::getString("BodyPartsTorso");
gAttachBodyPartPieMenus[6] = make_part_menu(label, context);
gDetachBodyPartPieMenus[6] = make_part_menu(label, context);
label = LLTrans::getString("BodyPartsRightLeg");
gAttachBodyPartPieMenus[7] = make_part_menu(label, context);
gDetachBodyPartPieMenus[7] = make_part_menu(label, context);
for (S32 i = 0; i < 8; i++)
struct EntryData
{
if (gAttachBodyPartPieMenus[i])
const char * subMenu;
LLContextMenu* attachMenu;
LLContextMenu* detachMenu;
} entries[NUM_ATTACHMENT_GROUPS] = {
{ nullptr, gAttachPieMenu, gDetachPieMenu }, //Group 0 = Right Hand
{ "BodyPartsRightArm", gAttachPieMenu, gDetachPieMenu },
{ "BodyPartsHead", gAttachPieMenu, gDetachPieMenu },
{ "BodyPartsLeftArm", gAttachPieMenu, gDetachPieMenu },
{ nullptr, gAttachPieMenu, gDetachPieMenu }, //Group 4 = Left Hand
{ "BodyPartsLeftLeg", gAttachPieMenu, gDetachPieMenu },
{ "BodyPartsTorso", gAttachPieMenu, gDetachPieMenu },
{ "BodyPartsRightLeg", gAttachPieMenu, gDetachPieMenu },
// BENTO
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 8 = Right Ring Finger
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 9 = Right Wing
{ "BodyPartsHead", gAttachPieMenu2, gDetachPieMenu2 },
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 11 = Left Wing
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 12 = Left Ring Finger
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 13 = Left Hind Foot
{ "BodyPartsWaist", gAttachPieMenu2, gDetachPieMenu2 },
{ nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 15 = Right Hind Foot
// HUD
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 16 = Center 2
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 17 = Top Right
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 18 = Top
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 19 = Top Left
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 20 = Center
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 21 = Bottom Left
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 22 = Bottom
{ nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu } // Group 23 = Bottom Right
};
for (S32 group = 0; group < NUM_ATTACHMENT_GROUPS; group++)
{
LLContextMenu* attach_menu = entries[group].attachMenu;
LLContextMenu* detach_menu = entries[group].detachMenu;
if (attach_menu && detach_menu)
{
gAttachPieMenu->appendContextSubMenu( gAttachBodyPartPieMenus[i] );
}
else
{
BOOL attachment_found = FALSE;
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
if (entries[group].subMenu != nullptr)
{
std::string label = LLTrans::getString(entries[group].subMenu);
LLContextMenu* new_menu = make_part_menu(label, context); // Attach
attach_menu->appendContextSubMenu(new_menu);
attach_menu = new_menu;
new_menu = make_part_menu(label, context); // Detach
detach_menu->appendContextSubMenu(new_menu);
detach_menu = new_menu;
}
if (!attach_menu || !detach_menu)
{
continue;
}
std::multimap<S32, S32> attachment_pie_menu_map;
// gather up all attachment points assigned to this group, and throw into map sorted by pie slice number
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == i)
if (attachment && attachment->getGroup() == group)
{
LLMenuItemCallGL* item;
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on (Left Hand / Right Hand option)
item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
NULL,
object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
// NULL,
// object_selected_and_point_valid);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first);
gAttachPieMenu->addChild(item);
attachment_found = TRUE;
break;
// use multimap to provide a partial order off of the pie slice key
S32 pie_index = attachment->getPieSlice();
attachment_pie_menu_map.insert(std::make_pair(pie_index, iter->first));
}
}
if (!context && !attachment_found)
// add in requested order to pie menu, inserting separators as necessary
for (std::multimap<S32, S32>::iterator attach_it = attachment_pie_menu_map.begin();
attach_it != attachment_pie_menu_map.end(); ++attach_it)
{
gAttachPieMenu->addSeparator();
}
}
if (gDetachBodyPartPieMenus[i])
{
gDetachPieMenu->appendContextSubMenu( gDetachBodyPartPieMenus[i] );
}
else
{
BOOL attachment_found = FALSE;
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == i)
if (!context) // Singu Note: Separators are only needed to keep slices of pies from moving
{
gDetachPieMenu->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
&handle_detach_from_avatar, object_attached, attachment));
S32 requested_pie_slice = attach_it->first;
while ((S32)attach_menu->getItemCount() < requested_pie_slice)
{
attach_menu->addSeparator();
detach_menu->addSeparator();
}
}
S32 attach_index = attach_it->second;
attachment_found = TRUE;
break;
LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL);
if (attachment)
{
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on
LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
NULL, object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
// NULL, object_selected_and_point_valid);
attach_menu->addChild(item);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index);
detach_menu->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
&handle_detach_from_avatar,
object_attached, attachment));
}
}
if (!context && !attachment_found)
{
gDetachPieMenu->addSeparator();
}
}
}
// add screen attachments
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == 8)
{
LLMenuItemCallGL* item;
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on
item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
NULL,
object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
// NULL,
// object_selected_and_point_valid);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first);
gAttachScreenPieMenu->addChild(item);
gDetachScreenPieMenu->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
&handle_detach_from_avatar, object_attached, attachment));
}
}
@@ -553,67 +540,6 @@ void LLVOAvatarSelf::buildContextMenus()
gDetachSubMenu->addSeparator();
}
}
for (S32 group = 0; group < 8; group++)
{
// skip over groups that don't have sub menus
if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group])
{
continue;
}
std::multimap<S32, S32> attachment_pie_menu_map;
// gather up all attachment points assigned to this group, and throw into map sorted by pie slice number
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if(attachment->getGroup() == group)
{
// use multimap to provide a partial order off of the pie slice key
S32 pie_index = attachment->getPieSlice();
attachment_pie_menu_map.insert(std::make_pair(pie_index, iter->first));
}
}
// add in requested order to pie menu, inserting separators as necessary
S32 cur_pie_slice = 0;
for (std::multimap<S32, S32>::iterator attach_it = attachment_pie_menu_map.begin();
attach_it != attachment_pie_menu_map.end(); ++attach_it)
{
if (!context) // Singu Note: Separators are only needed to keep slices of pies from moving
{
S32 requested_pie_slice = attach_it->first;
while (cur_pie_slice < requested_pie_slice)
{
gAttachBodyPartPieMenus[group]->addSeparator();
gDetachBodyPartPieMenus[group]->addSeparator();
cur_pie_slice++;
}
}
S32 attach_index = attach_it->second;
LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL);
if (attachment)
{
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on
LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
NULL, object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
// NULL, object_selected_and_point_valid);
gAttachBodyPartPieMenus[group]->addChild(item);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index);
gDetachBodyPartPieMenus[group]->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()),
&handle_detach_from_avatar,
object_attached, attachment));
if (!context) cur_pie_slice++;
}
}
}
}
void LLVOAvatarSelf::cleanup()
@@ -3180,7 +3106,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
}
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value);
void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
{
@@ -3208,7 +3134,7 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
it != v_params.end(); ++it)
{
LLVisualParam *param = *it;
dump_visual_param(outfile, param, param->getWeight());
dump_visual_param(file, param, param->getWeight());
}
}
}

View File

@@ -61,6 +61,7 @@
#include "llspatialpartition.h"
#include "llhudmanager.h"
#include "llflexibleobject.h"
#include "llskinningutil.h"
#include "llsky.h"
#include "lltexturefetch.h"
#include "llvector4a.h"
@@ -93,7 +94,7 @@
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
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;
@@ -3833,8 +3834,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
static const LLCachedControl<bool> allow_mesh_picking("SGAllowRiggedMeshSelection");
if (allow_mesh_picking && (gFloaterTools->getVisible() || LLFloaterInspect::findInstance()))
{
updateRiggedVolume();
//genBBoxes(FALSE);
updateRiggedVolume(true);
volume = mRiggedVolume;
transform = false;
}
@@ -4033,12 +4033,12 @@ void LLVOVolume::clearRiggedVolume()
}
}
void LLVOVolume::updateRiggedVolume()
void LLVOVolume::updateRiggedVolume(bool force_update)
{
//Update mRiggedVolume to match current animation frame of avatar.
//Also update position/size in octree.
if (!treatAsRigged())
if ((!force_update) && (!treatAsRigged()))
{
clearRiggedVolume();
@@ -4103,26 +4103,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
//build matrix palette
LLMatrix4a mp[JOINT_COUNT];
static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT;
U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT);
llassert_always(count);
for (U32 j = 0; j < count; ++j)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
if(!joint)
{
joint = avatar->getJoint("mRoot");
}
if (joint)
{
LLMatrix4a mat;
mat.loadu((F32*)skin->mInvBindMatrix[j].mMatrix);
mp[j].setMul(joint->getWorldMatrix(), mat);
}
}
LLMatrix4a mat[kMaxJoints];
U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar);
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
@@ -4136,7 +4121,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
{
continue;
}
LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin);
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
@@ -4146,42 +4131,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
{
LLFastTimer t(FTM_SKIN_RIGGED);
U32 max_joints = LLSkinningUtil::getMaxJointCount();
for (U32 j = 0; j < (U32)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];
const F32 w_floor = floorf(w);
idx[k] = (S32) w_floor;
wght[k] = w - w_floor;
scale += wght[k];
}
if(scale > 0.f)
wght *= 1.f/scale;
else
wght = LLVector4(F32_MAX,F32_MAX,F32_MAX,F32_MAX);
for (U32 k = 0; k < 4; k++)
{
F32 w = wght[k];
LLMatrix4a src;
// clamp k to kMaxJoints to avoid reading garbage off stack in release
src.setMul(mp[(idx[k] < (S32)count) ? idx[k] : 0], w);
final_mat.add(src);
}
LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints);
LLVector4a& v = vol_face.mPositions[j];
LLVector4a t;
@@ -4802,6 +4756,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bool is_rigged = false;
if (rigged && pAvatarVO)
{
pAvatarVO->addAttachmentOverridesForObject(vobj);
/*if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments"))
{
bool verbose = true;
pAvatarVO->showAttachmentOverrides(verbose);
}*/
}
static const LLCachedControl<bool> alt_batching("SHAltBatching",true);
//for each face
@@ -4837,10 +4801,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
// FIXME should this be inside the face loop?
// doesn't seem to depend on any per-face state.
if ( pAvatarVO )
/*if ( pAvatarVO )
{
pAvatarVO->addAttachmentPosOverridesForObject(vobj);
}
pAvatarVO->addAttachmentOverridesForObject(vobj);
}*/
if (pool)
{

View File

@@ -331,7 +331,7 @@ public:
//rigged volume update (for raycasting)
void updateRiggedVolume();
void updateRiggedVolume(bool force_update = false);
LLRiggedVolume* getRiggedVolume();
//returns true if volume should be treated as a rigged volume

View File

@@ -17,7 +17,7 @@
<on_click function="Avatar.AddFriend" />
<on_enable function="Avatar.EnableAddFriend" />
</menu_item_call>
<menu_item_call enabled="false" label="Pay..." mouse_opaque="true" name="Pay...">
<menu_item_call enabled="false" label="Pay..." mouse_opaque="true" name="Pay...">
<on_click function="PayObject" />
<on_enable function="EnablePayObject" />
</menu_item_call>
@@ -33,6 +33,15 @@
<on_click function="Avatar.InviteToGroup" />
</menu_item_call>
<pie_menu label="Tools" name="Tools">
<menu_item_call enabled="true" label="Reload" mouse_opaque="true" name="Reload Textures">
<on_click function="Avatar.ReloadTextures" />
</menu_item_call>
<menu_item_call enabled="true" label="Reset Skeleton" mouse_opaque="true" name="Reset Skeleton">
<on_click function="Avatar.ResetSkeleton" />
</menu_item_call>
<menu_item_call enabled="true" label="Reset Skeleton And Animations" mouse_opaque="true" name="Reset Skeleton And Animations">
<on_click function="Avatar.ResetSkeletonAndAnimations" />
</menu_item_call>
<menu_item_call enabled="false" hidden="false" label="S. Count" mouse_opaque="true" name="ScriptCount">
<on_click function="Object.ScriptCount" />
<on_visible function="Object.VisibleScriptCount" />
@@ -46,9 +55,6 @@
<menu_item_call enabled="true" label="Derender" mouse_opaque="true" name="Derender">
<on_click function="Object.DERENDER" />
</menu_item_call>
<menu_item_call enabled="true" label="Reload" mouse_opaque="true" name="Reload Textures">
<on_click function="Avatar.ReloadTextures" />
</menu_item_call>
</pie_menu>
<menu_item_call enabled="false" label="Eject..." mouse_opaque="true" name="Eject...">
<on_click function="Avatar.Eject" />

View File

@@ -39,6 +39,7 @@
</menu_item_call>
<pie_menu label="Attach HUD" name="Object Attach HUD" />
<pie_menu label="Attach" name="Object Attach" />
<pie_menu label="Attach More" name="Object Attach More" />
<menu_item_call enabled="false" label="Return..." mouse_opaque="true" name="Return...">
<on_click function="Object.Return" />
<on_enable function="Object.EnableReturn" />

View File

@@ -79,7 +79,7 @@
<pie_menu enabled="true" label="HUD" name="Object Detach HUD" />
<menu_item_separator />
<pie_menu enabled="true" label="Detach" name="Object Detach" />
<menu_item_separator />
<pie_menu enabled="true" label="Detach More" name="Object Detach More" />
<menu_item_call enabled="true" label="Detach All" name="Detach All">
<on_click function="Self.RemoveAllAttachments" userdata="" />
<on_enable function="Self.EnableRemoveAllAttachments" />
@@ -89,6 +89,12 @@
<menu_item_call enabled="true" label="Reload" mouse_opaque="true" name="Reload Textures">
<on_click function="Avatar.ReloadTextures" />
</menu_item_call>
<menu_item_call enabled="true" label="Reset Skel" mouse_opaque="true" name="Reset Skeleton">
<on_click function="Avatar.ResetSkeleton" />
</menu_item_call>
<menu_item_call enabled="true" label="Reset Anims" mouse_opaque="true" name="Reset Skeleton And Animations">
<on_click function="Avatar.ResetSkeletonAndAnimations" />
</menu_item_call>
<menu_item_call enabled="true" hidden="false" label="Anims..." mouse_opaque="true"
name="Anims...">
<on_click function="ShowFloater" userdata="anims_explorer" />
@@ -101,9 +107,9 @@
<on_click function="ShowFloater" userdata="script info" />
<on_visible function="Self.VisibleScriptInfo" />
</menu_item_call>
<menu_item_call enabled="true" label="Debug..." mouse_opaque="true" name="Debug Layers">
<!--<menu_item_call enabled="true" label="Debug..." mouse_opaque="true" name="Debug Layers">
<on_click function="Avatar.Debug" />
</menu_item_call>
</menu_item_call>-->
<menu_item_call enabled="true" label="Copy UUID" mouse_opaque="true" name="CopyUUID">
<on_click function="Avatar.CopyUUID" />
</menu_item_call>

View File

@@ -3151,7 +3151,8 @@ Where tag = tag string to match. Removes bot's matching the tag.
<string name="BodyPartsLeftLeg">Left Leg</string>
<string name="BodyPartsTorso">Torso</string>
<string name="BodyPartsRightLeg">Right Leg</string>
<string name="BodyPartsEnhancedSkeleton">Enhanced Skeleton</string>
<string name="BodyPartsWaist">Waist</string>
<!-- mouselook -->
<string name="LeaveMouselook">Press ESC to return to World View</string>
@@ -3289,6 +3290,21 @@ The
<string name="Right Pec">Right Pec</string>
<string name="Neck">Neck</string>
<string name="Avatar Center">Root</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>
@@ -3421,8 +3437,8 @@ The
<string name="ATTACH_LULEG">Left Upper Leg</string>
<string name="ATTACH_LLLEG">Left Lower Leg</string>
<string name="ATTACH_BELLY">Belly</string>
<string name="ATTACH_RPEC">Right Pec</string>
<string name="ATTACH_LPEC">Left Pec</string>
<string name="ATTACH_LEFT_PEC">Left Pec</string>
<string name="ATTACH_RIGHT_PEC">Right Pec</string>
<string name="ATTACH_HUD_CENTER_2">HUD Center 2</string>
<string name="ATTACH_HUD_TOP_RIGHT">HUD Top Right</string>
<string name="ATTACH_HUD_TOP_CENTER">HUD Top Center</string>
@@ -3433,6 +3449,21 @@ The
<string name="ATTACH_HUD_BOTTOM_RIGHT">HUD Bottom Right</string>
<string name="ATTACH_NECK">Neck</string>
<string name="ATTACH_AVATAR_CENTER">Root</string>
<string name="ATTACH_LHAND_RING1">Left Ring Finger</string>
<string name="ATTACH_RHAND_RING1">Right Ring Finger</string>
<string name="ATTACH_TAIL_BASE">Tail Base</string>
<string name="ATTACH_TAIL_TIP">Tail Tip</string>
<string name="ATTACH_LWING">Left Wing</string>
<string name="ATTACH_RWING">Right Wing</string>
<string name="ATTACH_FACE_JAW">Jaw</string>
<string name="ATTACH_FACE_LEAR">Alt Left Ear</string>
<string name="ATTACH_FACE_REAR">Alt Right Ear</string>
<string name="ATTACH_FACE_LEYE">Alt Left Eye</string>
<string name="ATTACH_FACE_REYE">Alt Right Eye</string>
<string name="ATTACH_FACE_TONGUE">Tongue</string>
<string name="ATTACH_GROIN">Groin</string>
<string name="ATTACH_HIND_LFOOT">Left Hind Foot</string>
<string name="ATTACH_HIND_RFOOT">Right Hind Foot</string>
<!-- panel contents -->
<string name="PanelContentsNewScript">New Script</string>