From b138ca8aeec421f6e5b1412e7c7fbcefd87570d0 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 6 Apr 2016 16:12:39 -0400
Subject: [PATCH] SL-366 - more cases where skinned weights can go awry, and a
 bunch more asserts to verify.

---
 indra/llmath/llvolume.cpp               | 10 ++++++----
 indra/llprimitive/llmodel.cpp           |  3 +--
 indra/newview/llfloatermodelpreview.cpp |  5 ++++-
 indra/newview/llskinningutil.cpp        |  9 ++++++++-
 4 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 725e50ee2be..e5b1cf536dd 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2544,7 +2544,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 						U16 influence = weights[idx++];
 						influence |= ((U16) weights[idx++] << 8);
 
-						F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
+						F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f);
 						wght.mV[cur_influence] = w;
 						joints[cur_influence] = joint;
 						cur_influence++;
@@ -2561,11 +2561,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
                     F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW];
                     if (wsum <= 0.f)
                     {
-                        wght = LLVector4(0.99999f,0.f,0.f,0.f);
+                        wght = LLVector4(0.999f,0.f,0.f,0.f);
                     }
-                    for (U32 k=0; k<4; k++)
+                    for (U32 k=0; k<cur_influence; k++)
                     {
-                        joints_with_weights[k] = (F32) joints[k] + wght[k];
+                        F32 f_combined = (F32) joints[k] + wght[k];
+                        llassert(f_combined-(S32)f_combined>0); // If this fails, we have a floating point precision error.
+                        joints_with_weights[k] = f_combined;
                     }
 					face.mWeights[cur_vertex].loadua(joints_with_weights.mV);
 
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index adf392fa217..398f0997f37 100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1001,7 +1001,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO
 
 LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
 {
-	//1. If a vertex has been weighted then we'll find it via pos and return it's weight list
+	//1. If a vertex has been weighted then we'll find it via pos and return its weight list
 	weight_map::iterator iterPos = mSkinWeights.begin();
 	weight_map::iterator iterEnd = mSkinWeights.end();
 	
@@ -1224,7 +1224,6 @@ bool LLModel::loadModel(std::istream& is)
 	}
 
 	return false;
-
 }
 
 bool LLModel::isMaterialListSubset( LLModel* ref )
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index ceb3566d956..cda704f47b6 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -3317,14 +3317,17 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 					LLVector3 pos(vf.mPositions[i].getF32ptr());
 
 					const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos);
+                    llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this
 
 					LLVector4 w(0,0,0,0);
 					
 					for (U32 i = 0; i < weight_list.size(); ++i)
 					{
-						F32 wght = llmin(weight_list[i].mWeight, 0.999999f);
+						F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f);
 						F32 joint = (F32) weight_list[i].mJointIdx;
 						w.mV[i] = joint + wght;
+                        llassert(w.mV[i]-(S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values
+                                                             //should not cause floating point precision issues.
 					}
 
 					*(weights_strider++) = w;
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index fbe45c8ea69..732afdfa9a4 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -291,12 +291,15 @@ void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, con
         {
             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
@@ -310,7 +313,7 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
     LLMatrix4a& final_mat,
     U32 max_joints)
 {
-
+    bool valid_weights = true;
     final_mat.clear();
 
     S32 idx[4];
@@ -336,6 +339,7 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
     if (handle_bad_scale && scale <= 0.f)
     {
         wght = LLVector4(1.0f, 0.0f, 0.0f, 0.0f);
+        valid_weights = false;
     }
     else
     {
@@ -353,5 +357,8 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
 
         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);
 }
 
-- 
GitLab