From 0a333e9a039288969b3ce207772fee8cbeb2ca83 Mon Sep 17 00:00:00 2001 From: vyacheslavsproductengine Date: Tue, 19 May 2015 19:28:03 +0400 Subject: MAINT-3548 - FIXED-R2 Horizontal & vertical offset values for normal & specular maps still randomly revert to previous settings when building. --- indra/newview/llvovolume.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 0432f6f27c..f435fd754b 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2010,7 +2010,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM LLTextureEntry* texture_entry = pVol->getTE(te); if (texture_entry && (texture_entry->getMaterialID() == pMaterialID)) { - pVol->setTEMaterialParams(te, pMaterialParams); + pVol->setTEMaterialParams(te, pMaterialParams, FALSE); } } } @@ -2081,7 +2081,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture) for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) { LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); - LLViewerObject::setTEMaterialParams(it->first, it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE); } //clear wait-list @@ -2158,7 +2158,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture) for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) { LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); - LLViewerObject::setTEMaterialParams(it->first, it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE); } //clear wait-list @@ -2167,7 +2167,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture) return 0 != new_material.size(); } -S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer) { LLMaterialPtr pMaterial = const_cast(pMaterialParams); @@ -2264,7 +2264,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa } } - S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial); + S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer); LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast(this), te) ? " selected" : " not selected" ) -- cgit v1.2.3 From 251cccd76c8eb1c1ab2422c5cfcd3d7ef9bd9454 Mon Sep 17 00:00:00 2001 From: ruslantproductengine Date: Wed, 10 Jun 2015 17:52:47 +0300 Subject: MAINT-4297 (Mesh models sometimes fail to load completely) MAINT-4449 (Starter avatars deformed or missing alpha under some conditions / graphics cards / LOD ) BUG-7239 (Starter avatars deformed or missing alpha under some conditions / graphics cards / LOD) The reason of problem on avatar (or one of avatar attachments) "deformed" it's selected volume (LLVolume) with a lower LOD. How it works. Why it happens? Each LLVOVolume object has variable mLOD which is indicate which is LLVolume should be assigned to LLPrimitive::mVolumep. The assigment happens in LLVOVolume::setVolume which is call LLPrimitive::setVolume, which is then lookup desired volume in LLVolumeMgr class which is keep as I understand all volume groups for all objects in scene. The data (mesh) for LLVolume class is loading from LL servers by http, and if sucessfully the variable LLVolume::mIsMeshAssetLoaded assigned to true. But sometimes the data may not be ready, and in this case the LLVOVolume::setVolume make request for download mesh (to the LLMeshRepository) and setup one of available lod. All of this things happens in (see: LLVOVolume::setVolume, code: block if (!getVolume()->isMeshAssetLoaded() {...}) When LLMeshRepository sucessfully download the mesh it's set (as I said above LLVolume::mIsMeshAssetLoaded, LLVolume::setMeshAssetLoaded()) and then also notify LLVOVolume::notifyMeshLoaded() about it. This causes add LLVOVolume::mDrawable into the pipline build list (see LLVOVolume::notifyMeshLoaded()) and set LLVOVolume::mSculptChanged; In order to process it later in LLVOVolume::updateGeometry (In order to see the mechanism of LLPipiline build list processing set bp in this method and see the stack). After the LLDrawable will be processed it will be removed form the build queue also all falgs will be reseted (see the end of LLVOVolume::updateGeometry). And here is the problem in variable-flag's "*Changed" processing (in LLVOVolume::updateGeometry): What if by the time of processing the mFaceMappingChanged also will be set (due to other changes in engine)? It means that LLVOVolume::setVolume will not be called and LLPrimitive::mVolumep remain unchaged and would point to the LLVolume for a lower LOD. My changes intended for fix this problem. BTW this is true for not only for standard avatar's. The reason why it is well visible on standard avatars is because it has a more "ugly" lower-LOD-s, than on avatars which is was loaded by the SL-users. For example on my DudtPank avatars I didn't see big difference between LOD-0 and LOD-3. If you want you can "play" with it in LLVOVolume::calcLOD() with add code if(getAvatar() && getAvatar()->isSelf()) { mLOD = } --- indra/newview/llvovolume.cpp | 138 ++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 62 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f435fd754b..cae67907dd 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) +{ + bool regen_faces = false; + + LLVolume *old_volumep, *new_volumep; + F32 old_lod, new_lod; + S32 old_num_faces, new_num_faces; + + old_volumep = getVolume(); + old_lod = old_volumep->getDetail(); + old_num_faces = old_volumep->getNumFaces(); + old_volumep = NULL; + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); + LLVolumeParams volume_params = getVolume()->getParams(); + setVolume(volume_params, 0); + } + + new_volumep = getVolume(); + new_lod = new_volumep->getDetail(); + new_num_faces = new_volumep->getNumFaces(); + new_volumep = NULL; + + if ((new_lod != old_lod) || mSculptChanged) + { + compiled = TRUE; + sNumLODChanges += new_num_faces; + + if ((S32)getNumTEs() != getVolume()->getNumFaces()) + { + setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. + } + + drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); + regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs(); + if (regen_faces) + { + regenFaces(); + } + + if (mSculptChanged) + { //changes in sculpt maps can thrash an object bounding box without + //triggering a spatial group bounding box update -- force spatial group + //to update bounding boxes + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->unbound(); + } + } + } + } + + return regen_faces; +} + BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES); @@ -1664,83 +1724,37 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - if (mVolumeChanged || mFaceMappingChanged ) + boost::function fn_lod_or_sculpt_changed = boost::bind(&LLVOVolume::lodOrSculptChanged, this, drawable, boost::ref(compiled)); + + if (mVolumeChanged || mFaceMappingChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - compiled = TRUE; + bool was_regen_faces = false; if (mVolumeChanged) { - LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); + was_regen_faces = fn_lod_or_sculpt_changed(); drawable->setState(LLDrawable::REBUILD_VOLUME); } - + else if (mSculptChanged) { + compiled = TRUE; + was_regen_faces = fn_lod_or_sculpt_changed(); + } + + if (!was_regen_faces) { LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); regenFaces(); - genBBoxes(FALSE); } + + genBBoxes(FALSE); } - else if ((mLODChanged) || (mSculptChanged)) + else if (mLODChanged || mSculptChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - - LLVolume *old_volumep, *new_volumep; - F32 old_lod, new_lod; - S32 old_num_faces, new_num_faces ; - - old_volumep = getVolume(); - old_lod = old_volumep->getDetail(); - old_num_faces = old_volumep->getNumFaces() ; - old_volumep = NULL ; - - { - LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); - } - - new_volumep = getVolume(); - new_lod = new_volumep->getDetail(); - new_num_faces = new_volumep->getNumFaces() ; - new_volumep = NULL ; - - if ((new_lod != old_lod) || mSculptChanged) - { - compiled = TRUE; - sNumLODChanges += new_num_faces ; - - if((S32)getNumTEs() != getVolume()->getNumFaces()) - { - setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. - } - - drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() - - { - LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); - if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs()) - { - regenFaces(); - } - genBBoxes(FALSE); - - if (mSculptChanged) - { //changes in sculpt maps can thrash an object bounding box without - //triggering a spatial group bounding box update -- force spatial group - //to update bounding boxes - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->unbound(); - } - } - } - } - + compiled = TRUE; + fn_lod_or_sculpt_changed(); genBBoxes(FALSE); } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local -- cgit v1.2.3 From 4a3d2eff64453915648979ae493f9bbaa1c0fcf8 Mon Sep 17 00:00:00 2001 From: ruslantproductengine Date: Mon, 13 Jul 2015 17:59:50 +0300 Subject: MAINT-5015 (Nearby objects often load at wrong LOD at login or after intra-region teleports) The idea and reason in this fix is same as for a MAINT-4297, MAINT-4449, BUG-7239 i.e. it's a just a little another case. --- indra/newview/llvovolume.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index cae67907dd..4b0e4514a0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1639,7 +1639,7 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) { LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); + const LLVolumeParams &volume_params = getVolume()->getParams(); setVolume(volume_params, 0); } @@ -1724,8 +1724,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - boost::function fn_lod_or_sculpt_changed = boost::bind(&LLVOVolume::lodOrSculptChanged, this, drawable, boost::ref(compiled)); - if (mVolumeChanged || mFaceMappingChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); @@ -1734,13 +1732,13 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (mVolumeChanged) { - was_regen_faces = fn_lod_or_sculpt_changed(); + was_regen_faces = lodOrSculptChanged(drawable, compiled); drawable->setState(LLDrawable::REBUILD_VOLUME); } - else if (mSculptChanged) + else if (mSculptChanged || mLODChanged) { compiled = TRUE; - was_regen_faces = fn_lod_or_sculpt_changed(); + was_regen_faces = lodOrSculptChanged(drawable, compiled); } if (!was_regen_faces) { @@ -1754,7 +1752,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); compiled = TRUE; - fn_lod_or_sculpt_changed(); + lodOrSculptChanged(drawable, compiled); genBBoxes(FALSE); } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local -- cgit v1.2.3 From 269cc894a95904578fe34cd89c563dc650349df8 Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine Date: Fri, 17 Jul 2015 07:31:36 +0300 Subject: MAINT-5416 FIXED cannot right-click a rigged mesh that's worn --- indra/newview/llvovolume.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4b0e4514a0..46e853c1e0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3883,7 +3883,7 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const } -BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp, +BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -3902,9 +3902,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& if (mDrawable->isState(LLDrawable::RIGGED)) { - if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf()) + if ((pick_rigged) || ((getAvatar()->isSelf()) && (LLFloater::isVisible(gFloaterTools)))) { - updateRiggedVolume(); + updateRiggedVolume(true); volume = mRiggedVolume; transform = false; } @@ -4083,10 +4083,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& bool LLVOVolume::treatAsRigged() { - return LLFloater::isVisible(gFloaterTools) && - isAttachment() && - getAvatar() && - getAvatar()->isSelf() && + return isSelected() && + isAttachment() && mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED); } @@ -4105,12 +4103,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(); -- cgit v1.2.3 From 57904b4def8c75a865ba503976de98d9ee4c0d94 Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine Date: Thu, 23 Jul 2015 23:59:05 +0300 Subject: MAINT-5416 Reverted changeset: 9bd24c17d908 --- indra/newview/llvovolume.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 46e853c1e0..4b0e4514a0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3883,7 +3883,7 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const } -BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, +BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp, LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -3902,9 +3902,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& if (mDrawable->isState(LLDrawable::RIGGED)) { - if ((pick_rigged) || ((getAvatar()->isSelf()) && (LLFloater::isVisible(gFloaterTools)))) + if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf()) { - updateRiggedVolume(true); + updateRiggedVolume(); volume = mRiggedVolume; transform = false; } @@ -4083,8 +4083,10 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& bool LLVOVolume::treatAsRigged() { - return isSelected() && - isAttachment() && + return LLFloater::isVisible(gFloaterTools) && + isAttachment() && + getAvatar() && + getAvatar()->isSelf() && mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED); } @@ -4103,12 +4105,12 @@ void LLVOVolume::clearRiggedVolume() } } -void LLVOVolume::updateRiggedVolume(bool force_update) +void LLVOVolume::updateRiggedVolume() { //Update mRiggedVolume to match current animation frame of avatar. //Also update position/size in octree. - if ((!force_update) && (!treatAsRigged())) + if (!treatAsRigged()) { clearRiggedVolume(); -- cgit v1.2.3 From 98166af9c711e63b5fedbf2227d3eb2e5fca8600 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 31 Aug 2015 13:06:42 -0400 Subject: SL-133 WIP, SL-134 WIP - more handling for out-of-range joints --- indra/newview/llvovolume.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 267061b83d..1f07d93cc7 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4174,6 +4174,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); if (!joint) { + // Fall back to a point inside the avatar if mesh is + // rigged to an unknown joint. joint = avatar->getJoint("mPelvis"); } if (joint) @@ -4181,6 +4183,12 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons mat[j] = skin->mInvBindMatrix[j]; mat[j] *= joint->getWorldMatrix(); } + else + { + // This shouldn't be possible unless the avatar skeleton + // is corrupt. + llassert(false); + } } for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) @@ -4220,8 +4228,21 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons wght[k] = w - floorf(w); scale += wght[k]; } - - wght *= 1.f/scale; + if (scale > 0.f) + { + wght *= 1.f / scale; + } + else + { + // Complete weighting fail - all zeroes. Just + // pick some values that add up to 1.0 so we + // don't wind up with garbage vertices + // pointing off at (0,0,0) + wght[0] = 1.f; + wght[1] = 0.f; + wght[2] = 0.f; + wght[3] = 0.f; + } for (U32 k = 0; k < 4; k++) { @@ -4229,9 +4250,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLMatrix4a src; // Insure ref'd bone is in our clamped array of mats - llassert(idx[k] < kMaxJoints); - // clamp k to kMaxJoints to avoid reading garbage off stack in release - src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w); + // clamp idx to maxJoints to avoid reading garbage off stack in release + src.setMul(mp[(idx[k] Date: Mon, 14 Sep 2015 11:01:22 -0400 Subject: SL-133 WIP, SL-134 WIP - more extra joint handling --- indra/newview/llvovolume.cpp | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'indra/newview/llvovolume.cpp') diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 1f07d93cc7..dabf6acecf 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4163,7 +4163,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } //build matrix palette - static const size_t kMaxJoints = 64; + static const size_t kMaxJoints = 52; LLMatrix4a mp[kMaxJoints]; LLMatrix4* mat = (LLMatrix4*) mp; @@ -4183,12 +4183,6 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons mat[j] = skin->mInvBindMatrix[j]; mat[j] *= joint->getWorldMatrix(); } - else - { - // This shouldn't be possible unless the avatar skeleton - // is corrupt. - llassert(false); - } } for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) @@ -4228,21 +4222,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons wght[k] = w - floorf(w); scale += wght[k]; } - if (scale > 0.f) - { - wght *= 1.f / scale; - } - else - { - // Complete weighting fail - all zeroes. Just - // pick some values that add up to 1.0 so we - // don't wind up with garbage vertices - // pointing off at (0,0,0) - wght[0] = 1.f; - wght[1] = 0.f; - wght[2] = 0.f; - wght[3] = 0.f; - } + // This is enforced in unpackVolumeFaces() + llassert(scale>0.f); + wght *= 1.f / scale; for (U32 k = 0; k < 4; k++) { @@ -4251,7 +4233,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLMatrix4a src; // Insure ref'd bone is in our clamped array of mats // clamp idx to maxJoints to avoid reading garbage off stack in release - src.setMul(mp[(idx[k]