From 9be476e3bb4cde7b086581931ed39ac137207ffe Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Mon, 9 Jul 2018 22:30:50 +0100
Subject: [PATCH] MAINT-7926, MAINT-8400 - fixes related to bounding box and
 LOD calculations for rigged meshes in animated objects

---
 indra/newview/llcontrolavatar.cpp | 13 ++++++++++++-
 indra/newview/lldrawable.cpp      | 20 ++++++++++++++++++++
 indra/newview/llskinningutil.cpp  | 25 ++++++++++++++++++++++---
 indra/newview/llvoavatar.cpp      |  6 +++---
 indra/newview/llvovolume.cpp      | 28 ++++++++++++++++++++++++++--
 indra/newview/llvovolume.h        |  3 +++
 6 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index 88152d2dc64..93b178e0e94 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -316,7 +316,10 @@ void LLControlAvatar::updateDebugText()
         F32 est_tris = 0.f;
         F32 est_streaming_tris = 0.f;
         F32 streaming_cost = 0.f;
-        
+        std::string cam_dist_string = "";
+        S32 cam_dist_count = 0;
+        F32 lod_radius = mRootVolp->mLODRadius;
+
         for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
              it != volumes.end(); ++it)
         {
@@ -351,6 +354,7 @@ void LLControlAvatar::updateDebugText()
                 {
                     // Rigged/animatable mesh
                     type_string += "R";
+                    lod_radius = volp->mLODRadius;
                 }
                 else if (volp->isMesh())
                 {
@@ -362,6 +366,12 @@ void LLControlAvatar::updateDebugText()
                     // Any other prim
                     type_string += "P";
                 }
+                if (cam_dist_count < 4)
+                {
+                    cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + "/" +
+                        LLStringOps::getReadableNumber(volp->mLODAdjustedDistance) + " ";
+                    cam_dist_count++;
+                }
             }
             else
             {
@@ -376,6 +386,7 @@ void LLControlAvatar::updateDebugText()
         addDebugText(llformat("flags %s", animated_object_flag_string.c_str()));
         addDebugText(llformat("tris %d (est %.1f, streaming %.1f), verts %d", total_tris, est_tris, est_streaming_tris, total_verts));
         addDebugText(llformat("pxarea %s rank %d", LLStringOps::getReadableNumber(getPixelArea()).c_str(), getVisibilityRank()));
+        addDebugText(llformat("lod_radius %s dists %s", LLStringOps::getReadableNumber(lod_radius).c_str(),cam_dist_string.c_str()));
         if (mPositionConstraintFixup.length() > 0.0f)
         {
             addDebugText(llformat("pos fix (%.1f %.1f %.1f)", 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 22ed54913a6..6d9c2c5eb8a 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -32,6 +32,7 @@
 #include "material_codes.h"
 
 // viewer includes
+#include "llagent.h"
 #include "llcriticaldamp.h"
 #include "llface.h"
 #include "lllightconstants.h"
@@ -900,6 +901,25 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 					}
 				}
 			}	
+
+            // MAINT-7926 Handle volumes in an animated object as a special case
+            if (volume->getAvatar() && volume->getAvatar()->isControlAvatar())
+            {
+                const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents();
+                LLVector3d cam_pos = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin());
+                LLVector3 cam_region_pos = LLVector3(cam_pos - volume->getRegion()->getOriginGlobal());
+                
+                LLVector3 cam_to_box_offset = point_to_box_offset(cam_region_pos, av_box);
+                //LL_DEBUGS("DynamicBox") << volume->getAvatar()->getFullname() 
+                //                        << " pos (ignored) " << pos
+                //                        << " cam pos " << cam_pos
+                //                        << " cam region pos " << cam_region_pos
+                //                        << " box " << av_box[0] << "," << av_box[1] << LL_ENDL;
+                mDistanceWRTCamera = ll_round(cam_to_box_offset.magVec(), 0.01f);
+                mVObjp->updateLOD();
+                return;
+            }
+            
 		}
 		else
 		{
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index 0878cee1a30..1f39097a98c 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -241,11 +241,29 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
                 for (S32 i=0; i<vol_face.mNumVertices; i++)
                 {
                     LLVector4a& pos = vol_face.mPositions[i];
-                    F32 *w = vol_face.mWeights[i].getF32ptr();
+                    F32 *weights = vol_face.mWeights[i].getF32ptr();
+                    LLVector4 wght;
+                    S32 idx[4];
+                    F32 scale = 0.0f;
+                    for (U32 k = 0; k < 4; k++)
+                    {
+                        F32 w = weights[k];
+                        
+                        idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS-1);
+                        wght[k] = w - idx[k];
+                        scale += wght[k];
+                    }
+                    if (scale > 0.0f)
+                    {
+                        for (U32 k=0; k<4; ++k)
+                        {
+                            wght[k] /= scale;
+                        }
+                    }
                     for (U32 k=0; k<4; ++k)
                     {
-                        S32 joint_index = llfloor(w[k]);
-                        if (w[k]-joint_index > 0.0f)
+						S32 joint_index = idx[k];
+                        if (wght[k] > 0.0f)
                         {
                             S32 joint_num = skin->mJointNums[joint_index];
                             if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS)
@@ -263,6 +281,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
                                 matMul(bind_shape, inv_bind, mat);
                                 LLVector4a pos_joint_space;
                                 mat.affineTransform(pos, pos_joint_space);
+                                pos_joint_space.mul(wght[k]);
                                 LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents();
                                 update_min_max(extents[0], extents[1], pos_joint_space);
                             }
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 9b8af204cfb..1ed105f8d4d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1316,10 +1316,10 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 	newMin = pos;
 	newMax = pos;
 
-	//stretch bounding box by joint positions. No point doing this for
+	//stretch bounding box by joint positions. Doing this for
 	//control avs, where the polymeshes aren't maintained or
-	//displayed.
-    if (box_detail>=1 && !isControlAvatar())
+	//displayed, can give inaccurate boxes due to joints stuck at (0,0,0).
+    if ((box_detail>=1) && !isControlAvatar())
     {
         for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i)
         {
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 7f353ea8aa1..6bcbebb546b 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -108,6 +108,10 @@ static LLTrace::BlockTimerStatHandle FTM_VOLUME_TEXTURES("Volume Textures");
 
 extern BOOL gGLDebugLoggingEnabled;
 
+#if LL_MSVC
+#pragma optimize("", off)
+#endif
+
 // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
 class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
 {
@@ -219,6 +223,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 
 	mFaceMappingChanged = FALSE;
 	mLOD = MIN_LOD;
+    mLODDistance = 0.0f;
+    mLODAdjustedDistance = 0.0f;
+    mLODRadius = 0.0f;
 	mTextureAnimp = NULL;
 	mVolumeChanged = FALSE;
 	mVObjRadius = LLVector3(1,1,0.5f).length();
@@ -1293,7 +1300,19 @@ BOOL LLVOVolume::calcLOD()
 		}
 
 		distance = avatar->mDrawable->mDistanceWRTCamera;
-		radius = avatar->getBinRadius();
+        if (avatar->isControlAvatar())
+        {
+            // MAINT-7926 Handle volumes in an animated object as a special case
+            const LLVector3* box = avatar->getLastAnimExtents();
+            LLVector3 diag = box[1] - box[0];
+            radius = diag.magVec() * 0.5f;
+            //LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL;
+        }
+        else
+        {
+            // Note this isn't really a radius, so distance calcs are off by factor of 2
+            radius = avatar->getBinRadius();
+        }
         if (distance <= 0.f || radius <= 0.f)
         {
             LL_DEBUGS("CalcLOD") << "avatar distance/radius uninitialized, skipping" << LL_ENDL;
@@ -1313,7 +1332,10 @@ BOOL LLVOVolume::calcLOD()
 	
 	//hold onto unmodified distance for debugging
 	//F32 debug_distance = distance;
-	
+
+    mLODDistance = distance;
+    mLODRadius = radius;
+    
 	distance *= sDistanceFactor;
 
 	F32 rampDist = LLVOVolume::sLODFactor * 2;
@@ -1335,6 +1357,8 @@ BOOL LLVOVolume::calcLOD()
 		lod_factor *= DEFAULT_FIELD_OF_VIEW / LLViewerCamera::getInstance()->getDefaultFOV();
 	}
 
+    mLODAdjustedDistance = distance;
+
 	cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor);
 
     if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0))
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 446d4a3d37e..0882fc095de 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -380,6 +380,9 @@ class LLVOVolume : public LLViewerObject
 
 	LLViewerTextureAnim *mTextureAnimp;
 	U8 mTexAnimMode;
+    F32 mLODDistance;
+    F32 mLODAdjustedDistance;
+    F32 mLODRadius;
 private:
 	friend class LLDrawable;
 	friend class LLFace;
-- 
GitLab