From abcddc97cf01fb61bc4b77ab492c02e3985bb1e1 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 13 Jun 2018 19:39:10 +0100
Subject: [PATCH] SL-915, MAINT-8554 - WIP on managing dynamic avatar bounding
 box, using to constrain encroachment by animated objects

---
 indra/newview/llcontrolavatar.cpp | 78 ++++++++++++++++++++++++++++++-
 indra/newview/llcontrolavatar.h   |  2 +
 indra/newview/llskinningutil.cpp  |  1 -
 indra/newview/llvoavatar.cpp      | 11 +++--
 indra/newview/llvoavatar.h        |  1 +
 indra/newview/llvovolume.cpp      | 40 +---------------
 6 files changed, 88 insertions(+), 45 deletions(-)

diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index 5a1add258c2..8291df77052 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -34,6 +34,10 @@
 #include "llmeshrepository.h"
 #include "llviewerregion.h"
 
+#if LL_WINDOWS
+	#pragma optimize("", off)
+#endif
+
 LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) :
     LLVOAvatar(id, pcode, regionp),
     mPlaying(false),
@@ -64,6 +68,41 @@ void LLControlAvatar::initInstance()
 	hideSkirt();
 }
 
+// AXON move to math
+bool box_valid_and_non_zero(const LLVector3* box)
+{
+    if (!box[0].isFinite() || !box[1].isFinite())
+    {
+        return false;
+    }
+    LLVector3 zero_vec;
+    zero_vec.clear();
+    if ((box[0] != zero_vec) || (box[1] != zero_vec))
+    {
+        return true;
+    }
+    return false;
+}
+
+// AXON move to math
+LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box)
+{
+    LLVector3 offset;
+    for (S32 k=0; k<3; k++)
+    {
+        offset[k] = 0;
+        if (pos[k] < box[0][k])
+        {
+            offset[k] = pos[k] - box[0][k];
+        }
+        else if (pos[k] > box[1][k])
+        {
+            offset[k] = pos[k] - box[1][k];
+        }
+    }
+    return offset;
+}
+
 void LLControlAvatar::matchVolumeTransform()
 {
     if (mRootVolp)
@@ -92,12 +131,47 @@ void LLControlAvatar::matchVolumeTransform()
         }
         else
         {
-            setPositionAgent(mRootVolp->getRenderPosition());
+
+            LLVector3 vol_pos = mRootVolp->getRenderPosition();
+            LLVector3 pos_box_offset;
+            pos_box_offset.clear();
+
+            // Fix up position if needed to prevent visual encroachment
+            if (box_valid_and_non_zero(getLastAnimExtents())) // wait for state to settle down
+            {
+                const F32 MAX_LEGAL_OFFSET = 2.0;
+                
+                // The goal here is to ensure that the extent of the avatar's 
+                // bounding box does not wander too far from the
+                // official position of the corresponding volume. We
+                // do this by tracking the distance and applying a
+                // correction to the control avatar position if
+                // needed.
+                LLVector3 uncorrected_extents[2];
+                uncorrected_extents[0] = getLastAnimExtents()[0] - mPositionConstraintFixup;
+                uncorrected_extents[1] = getLastAnimExtents()[1] - mPositionConstraintFixup;
+                pos_box_offset = point_to_box_offset(vol_pos, uncorrected_extents);
+                F32 offset_dist = pos_box_offset.length();
+                if (offset_dist > MAX_LEGAL_OFFSET)
+                {
+                    F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET);
+                    pos_box_offset *= target_dist/offset_dist;
+                }
+                LL_DEBUGS("FixBox") << getFullname() << " fixup needed for offset " 
+                                    << pos_box_offset[0] << "," << pos_box_offset[1] << "," << pos_box_offset[2] 
+                                    << " current fixup "
+                                    << mPositionConstraintFixup[0] << "," << mPositionConstraintFixup[1] << "," << mPositionConstraintFixup[2] 
+                                    << " dist " << offset_dist << LL_ENDL;
+            }
+
+            mPositionConstraintFixup = pos_box_offset;
+
+            setPositionAgent(vol_pos + mPositionConstraintFixup);
             LLQuaternion obj_rot = mRootVolp->getRotation();
             LLQuaternion result_rot = obj_rot;
             setRotation(result_rot);
             mRoot->setWorldRotation(result_rot);
-            mRoot->setPosition(mRootVolp->getRenderPosition());
+            mRoot->setPosition(vol_pos + mPositionConstraintFixup);
         }
     }
 }
diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h
index 02244769b99..c72dc03efc3 100644
--- a/indra/newview/llcontrolavatar.h
+++ b/indra/newview/llcontrolavatar.h
@@ -80,6 +80,8 @@ class LLControlAvatar:
 
     bool mMarkedForDeath;
 
+    LLVector3 mPositionConstraintFixup;
+
 };
 
 typedef std::map<LLUUID, S32> signaled_animation_map_t;
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index 8a499f77cd9..db9877f3026 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -204,7 +204,6 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
     llassert(valid_weights);
 }
 
-// AXON need to remember this has been done
 void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
 {
     if (!skin->mJointNumsInitialized)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7a138b26a4c..68966325974 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1296,14 +1296,16 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
     LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE);
 
     S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
-	LLVector4a buffer(0.0);
+	LLVector4a buffer(0.1);
 	LLVector4a pos;
-	pos.load3(getRenderPosition().mV);
+	pos.load3(mPelvisp->getWorldPosition().mV);
 	newMin.setSub(pos, buffer);
 	newMax.setAdd(pos, buffer);
 
-	//stretch bounding box by joint positions
-    if (box_detail>=1)
+	//stretch bounding box by joint positions. No point doing this for
+	//control avs, where the polymeshes aren't maintained or
+	//displayed.
+    if (box_detail>=1 && !isControlAvatar())
     {
         for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i)
         {
@@ -1316,6 +1318,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
             }
         }
 
+        // AXON shouldn't this section be after all the detail levels?
         LLVector4a center, size;
         center.setAdd(newMin, newMax);
         center.mul(0.5f);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 42b04ef870a..d80f0ad713f 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -525,6 +525,7 @@ class LLVOAvatar :
 	static void updateImpostors();
 	LLRenderTarget mImpostor;
 	BOOL		mNeedsImpostorUpdate;
+    const LLVector3*  getLastAnimExtents() const { return mLastAnimExtents; }
 private:
 	LLVector3	mImpostorOffset;
 	LLVector2	mImpostorDim;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 3387f718df5..7f353ea8aa1 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3604,44 +3604,9 @@ void LLVOVolume::updateRiggingInfo()
         if (skin && avatar && volume)
         {
             LL_DEBUGS("RigSpammish") << "starting, vovol " << this << " lod " << getLOD() << " last " << mLastRiggingInfoLOD << LL_ENDL;
-            // AXON SPAM
-            for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f)
+            if (getLOD()>mLastRiggingInfoLOD || getLOD()==3)
             {
-                LLVolumeFace& vol_face = volume->getVolumeFace(f);
-                if (vol_face.mJointRiggingInfoTab.size()>0)
-                {
-                    LL_DEBUGS("RigSpammish") << "vovol " << this << " lod " << getLOD() << " face " << f << " vf " << &vol_face << " has rig info" << LL_ENDL;
-                }
-                else
-                {
-                    LL_DEBUGS("RigSpammish") << "vovol " << this << " lod " << getLOD() << " face " << f << " vf " << &vol_face << " needs update" << LL_ENDL;
-                }
-            }
-            // We maintain rigging info based on the highest LOD
-            // handled so far. Need to update if either the LOD is
-            // the same but some faces need to be updated, or if
-            // the LOD has increased.
-            bool any_face_needs_rebuild = false;
-            if (getLOD()==mLastRiggingInfoLOD)
-            {
-                // See if any volume face needs its rigging info built.
-                for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f)
-                {
-                    LLVolumeFace& vol_face = volume->getVolumeFace(f);
-                    if (vol_face.mJointRiggingInfoTab.size()==0)
-                    {
-                        // AXON this is overkill since some faces don't contain any valid weights/rigged verts.
-                        any_face_needs_rebuild = true;
-                        break;
-                    }
-                }
-            }
-
-            //if (getLOD()>mLastRiggingInfoLOD ||
-            //    (getLOD()==mLastRiggingInfoLOD && any_face_needs_rebuild))
-            if (getLOD()==3)
-            {
-                // Rigging info has changed
+                // Rigging info may need update
                 mJointRiggingInfoTab.clear();
                 for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f)
                 {
@@ -3656,7 +3621,6 @@ void LLVOVolume::updateRiggingInfo()
                 mLastRiggingInfoLOD = getLOD();
                 LL_DEBUGS("RigSpammish") << "updated rigging info for LLVOVolume " 
                                          << this << " lod " << mLastRiggingInfoLOD 
-                                         << " any faces rebuilt? " << any_face_needs_rebuild
                                          << LL_ENDL;
             }
         }
-- 
GitLab