From d748dbce457dabf6bc46eb22c5c5315f50af159c Mon Sep 17 00:00:00 2001
From: Graham Linden <graham@lindenlab.com>
Date: Tue, 31 Jul 2018 17:35:42 +0100
Subject: [PATCH] MAINT-8909

Loosen precision when checking rotation and other false negatives when comparing
faces to see if they can be considered planar aligned. This was causing fields to
be marked tentative (grayed display) incorrectly.
---
 indra/newview/llpanelface.cpp | 25 ++++++++-----
 indra/newview/llpanelface.h   | 70 +++++++++++++++++------------------
 indra/newview/llselectmgr.cpp | 40 ++++++++++++++++++++
 indra/newview/llselectmgr.h   | 18 +++++++--
 4 files changed, 106 insertions(+), 47 deletions(-)

diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index d2d75784e81..b71e98b1022 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -605,12 +605,19 @@ struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor
 			tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]);
 			tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]);
 			F32 st_rot = tep->getRotation();
+
+            bool eq_offset_x = is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12);
+            bool eq_offset_y = is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12);
+            bool eq_scale_x  = is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12);
+            bool eq_scale_y  = is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12);
+            bool eq_rot      = is_approx_equal_fraction(st_rot, aligned_st_rot, 6);
+
 			// needs a fuzzy comparison, because of fp errors
-			if (is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12) && 
-				is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12) && 
-				is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12) &&
-				is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12) &&
-				is_approx_equal_fraction(st_rot, aligned_st_rot, 14))
+			if (eq_offset_x && 
+				eq_offset_y && 
+				eq_scale_x &&
+				eq_scale_y &&
+				eq_rot)
 			{
 				return true;
 			}
@@ -973,9 +980,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			F32 spec_scale_s = 1.f;
 			F32 norm_scale_s = 1.f;
 
-			LLSelectedTE::getScaleS(						diff_scale_s, identical_diff_scale_s);			
-			LLSelectedTEMaterial::getSpecularRepeatX( spec_scale_s, identical_spec_scale_s);
-			LLSelectedTEMaterial::getNormalRepeatX(	norm_scale_s, identical_norm_scale_s);
+			LLSelectedTE::getScaleS(diff_scale_s, identical_diff_scale_s);			
+			LLSelectedTEMaterial::getSpecularRepeatX(spec_scale_s, identical_spec_scale_s);
+			LLSelectedTEMaterial::getNormalRepeatX(norm_scale_s, identical_norm_scale_s);
 
 			diff_scale_s = editable ? diff_scale_s : 1.0f;
 			diff_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
@@ -2438,7 +2445,7 @@ void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical
 			return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
 		}
 	} get_te_face_func;
-	identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return);
+	identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr);
 }
 
 void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index c6f4c2f8267..17850dbc772 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -334,7 +334,7 @@ class LLPanelFace : public LLPanel
 		typename DataType,
 		typename ReturnType,
 		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
-	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value)
+	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = HasTolerance, DataType tolerance = DataType())
 	{
 		DataType data_value;
 		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
@@ -359,7 +359,7 @@ class LLPanelFace : public LLPanel
 			}
 			DataType _default;
 		} GetFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
 		data_to_return = data_value;
 	}
 
@@ -367,7 +367,7 @@ class LLPanelFace : public LLPanel
 		typename DataType,
 		typename ReturnType, // some kids just have to different...
 		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
-	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value)
+	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
 	{
 		DataType data_value;
 		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
@@ -381,7 +381,7 @@ class LLPanelFace : public LLPanel
 			}
 			DataType _default;
 		} GetTEValFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value );
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
 		data_to_return = data_value;
 	}
 
@@ -429,10 +429,10 @@ class LLPanelFace : public LLPanel
 
     // Accessors for selected TE material state
     //
-    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue)                                      \
-        static void MaterialMemberFunc(DataType& data, bool& identical)                                                 \
-        {                                                                                                               \
-            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical,DefaultValue);  \
+    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance)                                           \
+        static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)          \
+        {                                                                                                                                           \
+            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
         }
 
     // Mutators for selected TE material
@@ -445,10 +445,10 @@ class LLPanelFace : public LLPanel
 
     // Accessors for selected TE state proper (legacy settings etc)
     //
-    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue)                                       \
-        static void TexEntryMemberFunc(DataType& data, bool& identical)                                                 \
-        {                                                                                                               \
-            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical,DefaultValue);      \
+    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance)                                        \
+        static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)      \
+        {                                                                                                                                       \
+            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
         }
 
 	class LLSelectedTEMaterial
@@ -459,19 +459,19 @@ class LLPanelFace : public LLPanel
 		static void getMaxNormalRepeats(F32& repeats, bool& identical);
 		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
 
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null)
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f)
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
 
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
 
 		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
 		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
@@ -507,17 +507,17 @@ class LLPanelFace : public LLPanel
 		static void getObjectScaleT(F32& scale_t, bool& identical);
 		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
 
-		DEF_GET_TE_STATE(U8,U8,getBumpmap,0)
-		DEF_GET_TE_STATE(U8,U8,getShiny,0)
-		DEF_GET_TE_STATE(U8,U8,getFullbright,0)
-		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f)
-		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f)
-		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f)
-		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f)
-		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT)
-		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white)		
+		DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
+		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
+		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
 	};
 };
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 53f09ab62d8..86b88e0a59f 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -7936,3 +7936,43 @@ void LLSelectMgr::sendSelectionMove()
 
 	//saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
 }
+
+bool LLCheckIdenticalFunctor<F32>::same(const F32& a, const F32& b, const F32& tolerance)
+{
+    F32 delta = (a - b);
+    F32 abs_delta = fabs(delta);
+    bool is_samish = abs_delta <= tolerance;
+    if (!is_samish)
+    {
+        int q = 0;
+        q++;
+    }
+    return is_samish;
+}
+
+#define DEF_DUMMY_CHECK_FUNCTOR(T)                                                  \
+bool LLCheckIdenticalFunctor<T>::same(const T& a, const T& b, const T& tolerance)   \
+{                                                                                   \
+    (void)tolerance;                                                                \
+    return a == b;                                                                  \
+}
+
+DEF_DUMMY_CHECK_FUNCTOR(LLUUID)
+DEF_DUMMY_CHECK_FUNCTOR(LLGLenum)
+DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry)
+DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry::e_texgen)
+DEF_DUMMY_CHECK_FUNCTOR(bool)
+DEF_DUMMY_CHECK_FUNCTOR(U8)
+DEF_DUMMY_CHECK_FUNCTOR(int)
+DEF_DUMMY_CHECK_FUNCTOR(LLColor4)
+DEF_DUMMY_CHECK_FUNCTOR(LLMediaEntry)
+DEF_DUMMY_CHECK_FUNCTOR(LLPointer<LLMaterial>)
+DEF_DUMMY_CHECK_FUNCTOR(std::string)
+DEF_DUMMY_CHECK_FUNCTOR(std::vector<std::string>)
+
+bool LLCheckIdenticalFunctor<class LLFace *>::same(class LLFace* const & a, class LLFace* const & b, class LLFace* const & tolerance)   \
+{                                                                                   \
+    (void)tolerance;                                                                \
+    return a == b;                                                                  \
+}
+
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 25ee8619d7f..cbe9200c4e0 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -124,6 +124,11 @@ template <typename T> struct LLSelectedTEGetFunctor
 	virtual T get(LLViewerObject* object, S32 te) = 0;
 };
 
+template <typename T> struct LLCheckIdenticalFunctor
+{
+	static bool same(const T& a, const T& b, const T& tolerance);
+};
+
 typedef enum e_send_type
 {
 	SEND_ONLY_ROOTS,
@@ -313,7 +318,7 @@ class LLObjectSelection : public LLRefCount
 	LLViewerObject* getPrimaryObject() { return mPrimaryObject; }
 
 	// iterate through texture entries
-	template <typename T> bool getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res);
+	template <typename T> bool getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance = false, T tolerance = T());
 	template <typename T> bool isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value);
 	
 	S32 getNumNodes();
@@ -856,7 +861,7 @@ void dialog_refresh_all();
 //-----------------------------------------------------------------------------
 // getSelectedTEValue
 //-----------------------------------------------------------------------------
-template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res)
+template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance, T tolerance)
 {
 	bool have_first = false;
 	bool have_selected = false;
@@ -892,7 +897,14 @@ template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGet
 			{
 				if ( value != selected_value )
 				{
-					identical = false;
+                    if (!has_tolerance)
+                    {
+					    identical = false;
+                    }
+                    else if (!LLCheckIdenticalFunctor<T>::same(value, selected_value, tolerance))
+                    {
+                        identical = false;
+                    }
 				}
 				if (te == selected_te)
 				{
-- 
GitLab