From a4ad75e93c20f140d9503c119201128b0f9e4d0e Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 1 Nov 2022 15:17:22 -0500
Subject: [PATCH] SL-18520 WIP - Use off-by-epsilon and special UUID identifier
 hacks to allow overriding to default values.

---
 indra/llprimitive/llgltfmaterial.cpp | 176 ++++++++++++++++++++-------
 indra/llprimitive/llgltfmaterial.h   |  69 +++++------
 indra/newview/llmaterialeditor.cpp   |  50 ++++----
 3 files changed, 182 insertions(+), 113 deletions(-)

diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index cd629dbbd8e..4b1f89f99fe 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -28,6 +28,7 @@
 
 #include "llgltfmaterial.h"
 
+// NOTE -- this should be the one and only place tiny_gltf.h is included
 #include "tinygltf/tiny_gltf.h"
 
 const char* GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
@@ -35,6 +36,9 @@ const char* GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
 const char* GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
 const char* GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
 
+// special UUID that indicates a null UUID in override data
+static const LLUUID GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
+
 LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)
 {
     *this = rhs;
@@ -296,64 +300,144 @@ void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, Tex
     texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map);
 }
 
+// static
+void LLGLTFMaterial::hackOverrideUUID(LLUUID& id)
+{
+    if (id == LLUUID::null)
+    {
+        id = GLTF_OVERRIDE_NULL_UUID;
+    }
+}
 
-void LLGLTFMaterial::setBaseColorId(const LLUUID& id)
+void LLGLTFMaterial::setBaseColorId(const LLUUID& id, bool for_override)
 {
     mBaseColorId = id;
+    if (for_override)
+    {
+        hackOverrideUUID(mBaseColorId);
+    }
 }
 
-void LLGLTFMaterial::setNormalId(const LLUUID& id)
+void LLGLTFMaterial::setNormalId(const LLUUID& id, bool for_override)
 {
     mNormalId = id;
+    if (for_override)
+    {
+        hackOverrideUUID(mNormalId);
+    }
 }
 
-void LLGLTFMaterial::setMetallicRoughnessId(const LLUUID& id)
+void LLGLTFMaterial::setMetallicRoughnessId(const LLUUID& id, bool for_override)
 {
     mMetallicRoughnessId = id;
+    if (for_override)
+    {
+        hackOverrideUUID(mMetallicRoughnessId);
+    }
 }
 
-void LLGLTFMaterial::setEmissiveId(const LLUUID& id)
+void LLGLTFMaterial::setEmissiveId(const LLUUID& id, bool for_override)
 {
     mEmissiveId = id;
+    if (for_override)
+    {
+        hackOverrideUUID(mEmissiveId);
+    }
 }
 
-void LLGLTFMaterial::setBaseColorFactor(const LLColor3& baseColor, F32 transparency)
+void LLGLTFMaterial::setBaseColorFactor(const LLColor4& baseColor, bool for_override)
 {
-    mBaseColor.set(baseColor, transparency);
+    mBaseColor.set(baseColor);
     mBaseColor.clamp();
+
+    if (for_override)
+    { // hack -- nudge off of default value
+        if (mBaseColor == getDefaultBaseColor())
+        {
+            mBaseColor.mV[3] -= FLT_EPSILON;
+        }
+    }
 }
 
-void LLGLTFMaterial::setAlphaCutoff(F32 cutoff)
+void LLGLTFMaterial::setAlphaCutoff(F32 cutoff, bool for_override)
 {
     mAlphaCutoff = llclamp(cutoff, 0.f, 1.f);
+    if (for_override)
+    { // hack -- nudge off of default value
+        if (mAlphaCutoff == getDefaultAlphaCutoff())
+        {
+            mAlphaCutoff -= FLT_EPSILON;
+        }
+    }
 }
 
-void LLGLTFMaterial::setEmissiveColorFactor(const LLColor3& emissiveColor)
+void LLGLTFMaterial::setEmissiveColorFactor(const LLColor3& emissiveColor, bool for_override)
 {
     mEmissiveColor = emissiveColor;
     mEmissiveColor.clamp();
+
+    if (for_override)
+    { // hack -- nudge off of default value
+        if (mEmissiveColor == getDefaultEmissiveColor())
+        {
+            mEmissiveColor.mV[0] += FLT_EPSILON;
+        }
+    }
+}
+
+void LLGLTFMaterial::setMetallicFactor(F32 metallic, bool for_override)
+{
+    mMetallicFactor = llclamp(metallic, 0.f, for_override ? 1.f - FLT_EPSILON : 1.f);
 }
 
-void LLGLTFMaterial::setMetallicFactor(F32 metallic)
+void LLGLTFMaterial::setRoughnessFactor(F32 roughness, bool for_override)
 {
-    mMetallicFactor = llclamp(metallic, 0.f, 1.f);
+    mRoughnessFactor = llclamp(roughness, 0.f, for_override ? 1.f - FLT_EPSILON : 1.f);
 }
 
-void LLGLTFMaterial::setRoughnessFactor(F32 roughness)
+void LLGLTFMaterial::setAlphaMode(const std::string& mode, bool for_override)
 {
-    mRoughnessFactor = llclamp(roughness, 0.f, 1.f);
+    S32 m = getDefaultAlphaMode();
+    if (mode == "MASK")
+    {
+        m = ALPHA_MODE_MASK;
+    }
+    else if (mode == "BLEND")
+    {
+        m = ALPHA_MODE_BLEND;
+    }
+    
+    setAlphaMode(m, for_override);
+}
+
+const char* LLGLTFMaterial::getAlphaMode() const
+{
+    switch (mAlphaMode)
+    {
+    case ALPHA_MODE_MASK: return "MASK";
+    case ALPHA_MODE_BLEND: return "BLEND";
+    default: return "OPAQUE";
+    }
 }
 
-void LLGLTFMaterial::setAlphaMode(S32 mode)
+void LLGLTFMaterial::setAlphaMode(S32 mode, bool for_override)
 {
     mAlphaMode = (AlphaMode) llclamp(mode, (S32) ALPHA_MODE_OPAQUE, (S32) ALPHA_MODE_MASK);
+    if (for_override)
+    {
+        // TODO: what do?
+    }
 }
 
-void LLGLTFMaterial::setDoubleSided(bool double_sided)
+void LLGLTFMaterial::setDoubleSided(bool double_sided, bool for_override)
 {
     // sure, no clamping will ever be needed for a bool, but include the
     // setter for consistency with the clamping API
     mDoubleSided = double_sided;
+    if (for_override)
+    {
+        // TODO: what do?
+    }
 }
 
 void LLGLTFMaterial::setTextureOffset(TextureInfo texture_info, const LLVector2& offset)
@@ -371,102 +455,102 @@ void LLGLTFMaterial::setTextureRotation(TextureInfo texture_info, float rotation
     mTextureTransform[texture_info].mRotation = rotation;
 }
 
-// Default value accessors
+// Default value accessors (NOTE: these MUST match the GLTF specification)
+
+// Make a static default material for accessors
+const LLGLTFMaterial LLGLTFMaterial::sDefault;
 
 LLUUID LLGLTFMaterial::getDefaultBaseColorId()
 {
-    return LLUUID::null;
+    return sDefault.mBaseColorId;
 }
 
 LLUUID LLGLTFMaterial::getDefaultNormalId()
 {
-    return LLUUID::null;
+    return sDefault.mNormalId;
 }
 
 LLUUID LLGLTFMaterial::getDefaultEmissiveId()
 {
-    return LLUUID::null;
+    return sDefault.mEmissiveId;
 }
 
 LLUUID LLGLTFMaterial::getDefaultMetallicRoughnessId()
 {
-    return LLUUID::null;
+    return sDefault.mMetallicRoughnessId;
 }
 
 F32 LLGLTFMaterial::getDefaultAlphaCutoff()
 {
-    return 0.f;
+    return sDefault.mAlphaCutoff;
 }
 
 S32 LLGLTFMaterial::getDefaultAlphaMode()
 {
-    return (S32) ALPHA_MODE_OPAQUE;
+    return (S32) sDefault.mAlphaMode;
 }
 
 F32 LLGLTFMaterial::getDefaultMetallicFactor()
 {
-    return 0.f;
+    return sDefault.mMetallicFactor;
 }
 
 F32 LLGLTFMaterial::getDefaultRoughnessFactor()
 {
-    return 0.f;
+    return sDefault.mRoughnessFactor;
 }
 
 LLColor4 LLGLTFMaterial::getDefaultBaseColor()
 {
-    return LLColor4::white;
+    return sDefault.mBaseColor;
 }
 
 LLColor3 LLGLTFMaterial::getDefaultEmissiveColor()
 {
-    return LLColor3::black;
+    return sDefault.mEmissiveColor;
 }
 
 bool LLGLTFMaterial::getDefaultDoubleSided()
 {
-    return false;
+    return sDefault.mDoubleSided;
 }
 
 LLVector2 LLGLTFMaterial::getDefaultTextureOffset()
 {
-    return LLVector2(0.f, 0.f);
+    return sDefault.mTextureTransform[0].mOffset;
 }
 
 LLVector2 LLGLTFMaterial::getDefaultTextureScale()
 {
-    return LLVector2(1.f, 1.f);
+    return sDefault.mTextureTransform[0].mScale;
 }
 
 F32 LLGLTFMaterial::getDefaultTextureRotation()
 {
-    return 0.f;
+    return sDefault.mTextureTransform[0].mRotation;
 }
 
-void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
+// static
+void LLGLTFMaterial::applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id)
 {
-    LL_PROFILE_ZONE_SCOPED;
-    // TODO: potentially reimplement this with a more general purpose JSON merge
-
-    if (override_mat.mBaseColorId != getDefaultBaseColorId())
+    if (override_id != GLTF_OVERRIDE_NULL_UUID)
     {
-        mBaseColorId = override_mat.mBaseColorId;
+        dst_id = override_id;
     }
-
-    if (override_mat.mNormalId != getDefaultNormalId())
+    else
     {
-        mNormalId = override_mat.mNormalId;
+        dst_id = LLUUID::null;
     }
+}
 
-    if (override_mat.mMetallicRoughnessId != getDefaultMetallicRoughnessId())
-    {
-        mMetallicRoughnessId = override_mat.mMetallicRoughnessId;
-    }
+void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
+{
+    LL_PROFILE_ZONE_SCOPED;
 
-    if (override_mat.mEmissiveId != getDefaultEmissiveId())
-    {
-        mEmissiveId = override_mat.mEmissiveId;
-    }
+    applyOverrideUUID(mBaseColorId, override_mat.mBaseColorId);
+    applyOverrideUUID(mNormalId, override_mat.mNormalId);
+    applyOverrideUUID(mMetallicRoughnessId, override_mat.mMetallicRoughnessId);
+    applyOverrideUUID(mEmissiveId, override_mat.mEmissiveId);
 
     if (override_mat.mBaseColor != getDefaultBaseColor())
     {
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index d94ce6e2818..a385539cc5f 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -45,6 +45,9 @@ class LLGLTFMaterial : public LLRefCount
 {
 public:
 
+    // default material for reference
+    static const LLGLTFMaterial sDefault;
+
     struct TextureTransform
     {
         LLVector2 mOffset = { 0.f, 0.f };
@@ -69,12 +72,13 @@ class LLGLTFMaterial : public LLRefCount
     LLUUID mMetallicRoughnessId;
     LLUUID mEmissiveId;
 
+    // NOTE : initialize values to defaults according to the GLTF spec
     LLColor4 mBaseColor = LLColor4(1, 1, 1, 1);
     LLColor3 mEmissiveColor = LLColor3(0, 0, 0);
 
-    F32 mMetallicFactor = 0.f;
-    F32 mRoughnessFactor = 0.f;
-    F32 mAlphaCutoff = 0.f;
+    F32 mMetallicFactor = 1.f;
+    F32 mRoughnessFactor = 1.f;
+    F32 mAlphaCutoff = 0.5f;
 
     bool mDoubleSided = false;
     AlphaMode mAlphaMode = ALPHA_MODE_OPAQUE;
@@ -105,19 +109,22 @@ class LLGLTFMaterial : public LLRefCount
     std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform;
 
     //setters for various members (will clamp to acceptable ranges)
+    // for_override - set to true if this value is being set as part of an override (important for handling override to default value)
+
+    void setBaseColorId(const LLUUID& id, bool for_override = false);
+    void setNormalId(const LLUUID& id, bool for_override = false);
+    void setMetallicRoughnessId(const LLUUID& id, bool for_override = false);
+    void setEmissiveId(const LLUUID& id, bool for_override = false);
 
-    void setBaseColorId(const LLUUID& id);
-    void setNormalId(const LLUUID& id);
-    void setMetallicRoughnessId(const LLUUID& id);
-    void setEmissiveId(const LLUUID& id);
+    void setBaseColorFactor(const LLColor4& baseColor, bool for_override = false);
+    void setAlphaCutoff(F32 cutoff, bool for_override = false);
+    void setEmissiveColorFactor(const LLColor3& emissiveColor, bool for_override = false);
+    void setMetallicFactor(F32 metallic, bool for_override = false);
+    void setRoughnessFactor(F32 roughness, bool for_override = false);
+    void setAlphaMode(S32 mode, bool for_override = false);
+    void setDoubleSided(bool double_sided, bool for_override = false);
 
-    void setBaseColorFactor(const LLColor3& baseColor, F32 transparency);
-    void setAlphaCutoff(F32 cutoff);
-    void setEmissiveColorFactor(const LLColor3& emissiveColor);
-    void setMetallicFactor(F32 metallic);
-    void setRoughnessFactor(F32 roughness);
-    void setAlphaMode(S32 mode);
-    void setDoubleSided(bool double_sided);
+    //NOTE: texture offsets only exist in overrides, so "for_override" is not needed
 
     void setTextureOffset(TextureInfo texture_info, const LLVector2& offset);
     void setTextureScale(TextureInfo texture_info, const LLVector2& scale);
@@ -139,34 +146,16 @@ class LLGLTFMaterial : public LLRefCount
     static LLVector2 getDefaultTextureScale();
     static F32 getDefaultTextureRotation();
 
+    
+    static void hackOverrideUUID(LLUUID& id);
+    static void applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id);
+
     // set mAlphaMode from string.
     // Anything otherthan "MASK" or "BLEND" sets mAlphaMode to ALPHA_MODE_OPAQUE
-    void setAlphaMode(const std::string& mode)
-    {
-        if (mode == "MASK")
-        {
-            mAlphaMode = ALPHA_MODE_MASK;
-        }
-        else if (mode == "BLEND")
-        {
-            mAlphaMode = ALPHA_MODE_BLEND;
-        }
-        else
-        {
-            mAlphaMode = ALPHA_MODE_OPAQUE;
-        }
-    }
-
-    const char* getAlphaMode() const
-    {
-        switch (mAlphaMode)
-        {
-        case ALPHA_MODE_MASK: return "MASK";
-        case ALPHA_MODE_BLEND: return "BLEND";
-        default: return "OPAQUE";
-        }
-    }
-
+    void setAlphaMode(const std::string& mode, bool for_override = false);
+   
+    const char* getAlphaMode() const;
+    
     // set the contents of this LLGLTFMaterial from the given json
     // returns true if successful
     // json - the json text to load from
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index c99e7307ed1..0ae8dcbcf7e 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -70,21 +70,20 @@ static const std::string LIVE_MATERIAL_EDITOR_KEY = "Live Editor";
 
 // Dirty flags
 static const U32 MATERIAL_BASE_COLOR_DIRTY = 0x1 << 0;
-static const U32 MATERIAL_BASE_TRANSPARENCY_DIRTY = 0x1 << 1;
-static const U32 MATERIAL_BASE_COLOR_TEX_DIRTY = 0x1 << 2;
+static const U32 MATERIAL_BASE_COLOR_TEX_DIRTY = 0x1 << 1;
 
-static const U32 MATERIAL_NORMAL_TEX_DIRTY = 0x1 << 3;
+static const U32 MATERIAL_NORMAL_TEX_DIRTY = 0x1 << 2;
 
-static const U32 MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY = 0x1 << 4;
-static const U32 MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY = 0x1 << 5;
-static const U32 MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY = 0x1 << 6;
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY = 0x1 << 3;
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY = 0x1 << 4;
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY = 0x1 << 5;
 
-static const U32 MATERIAL_EMISIVE_COLOR_DIRTY = 0x1 << 7;
-static const U32 MATERIAL_EMISIVE_TEX_DIRTY = 0x1 << 8;
+static const U32 MATERIAL_EMISIVE_COLOR_DIRTY = 0x1 << 6;
+static const U32 MATERIAL_EMISIVE_TEX_DIRTY = 0x1 << 7;
 
-static const U32 MATERIAL_DOUBLE_SIDED_DIRTY = 0x1 << 9;
-static const U32 MATERIAL_ALPHA_MODE_DIRTY = 0x1 << 10;
-static const U32 MATERIAL_ALPHA_CUTOFF_DIRTY = 0x1 << 11;
+static const U32 MATERIAL_DOUBLE_SIDED_DIRTY = 0x1 << 8;
+static const U32 MATERIAL_ALPHA_MODE_DIRTY = 0x1 << 9;
+static const U32 MATERIAL_ALPHA_CUTOFF_DIRTY = 0x1 << 10;
 
 LLUUID LLMaterialEditor::mOverrideObjectId;
 S32 LLMaterialEditor::mOverrideObjectTE = -1;
@@ -384,7 +383,7 @@ BOOL LLMaterialEditor::postBuild()
 
     // BaseColor
     childSetCommitCallback("base color", changes_callback, (void*)&MATERIAL_BASE_COLOR_DIRTY);
-    childSetCommitCallback("transparency", changes_callback, (void*)&MATERIAL_BASE_TRANSPARENCY_DIRTY);
+    childSetCommitCallback("transparency", changes_callback, (void*)&MATERIAL_BASE_COLOR_DIRTY);
     childSetCommitCallback("alpha mode", changes_callback, (void*)&MATERIAL_ALPHA_MODE_DIRTY);
     childSetCommitCallback("alpha cutoff", changes_callback, (void*)&MATERIAL_ALPHA_CUTOFF_DIRTY);
 
@@ -2263,55 +2262,52 @@ class LLRenderMaterialOverrideFunctor : public LLSelectedTEFunctor
             // Override object's values with values from editor where appropriate
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_BASE_COLOR_DIRTY)
             {
-                material->mBaseColor = mEditor->getBaseColor();
-            }
-            if (mEditor->getUnsavedChangesFlags() & MATERIAL_BASE_TRANSPARENCY_DIRTY)
-            {
-                material->mBaseColor.mV[3] = mEditor->getTransparency();
+                LLColor4 baseColor = mEditor->getBaseColor();
+                material->setBaseColorFactor(mEditor->getBaseColor(), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_BASE_COLOR_TEX_DIRTY)
             {
-                material->mBaseColorId = mEditor->getBaseColorId();
+                material->setBaseColorId(mEditor->getBaseColorId(), true);
             }
 
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_NORMAL_TEX_DIRTY)
             {
-                material->mNormalId = mEditor->getNormalId();
+                material->setNormalId(mEditor->getNormalId(), true);
             }
 
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY)
             {
-                material->mMetallicRoughnessId = mEditor->getMetallicRoughnessId();
+                material->setMetallicRoughnessId(mEditor->getMetallicRoughnessId(), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY)
             {
-                material->mMetallicFactor = mEditor->getMetalnessFactor();
+                material->setMetallicFactor(mEditor->getMetalnessFactor(), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY)
             {
-                material->mRoughnessFactor = mEditor->getRoughnessFactor();
+                material->setRoughnessFactor(mEditor->getRoughnessFactor(), true);
             }
 
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_EMISIVE_COLOR_DIRTY)
             {
-                material->mEmissiveColor = mEditor->getEmissiveColor();
+                material->setEmissiveColorFactor(LLColor3(mEditor->getEmissiveColor()), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_EMISIVE_TEX_DIRTY)
             {
-                material->mEmissiveId = mEditor->getEmissiveId();
+                material->setEmissiveId(mEditor->getEmissiveId(), true);
             }
 
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_DOUBLE_SIDED_DIRTY)
             {
-                material->mDoubleSided = mEditor->getDoubleSided();
+                material->setDoubleSided(mEditor->getDoubleSided(), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_ALPHA_MODE_DIRTY)
             {
-                material->setAlphaMode(mEditor->getAlphaMode());
+                material->setAlphaMode(mEditor->getAlphaMode(), true);
             }
             if (mEditor->getUnsavedChangesFlags() & MATERIAL_ALPHA_CUTOFF_DIRTY)
             {
-                material->mAlphaCutoff = mEditor->getAlphaCutoff();
+                material->setAlphaCutoff(mEditor->getAlphaCutoff(), true);
             }
 
             std::string overrides_json = material->asJSON();
-- 
GitLab