From b482c4a8a9cdb02cedc233767e72888da2befb26 Mon Sep 17 00:00:00 2001
From: HifiExperiments <thingsandstuffblog@gmail.com>
Date: Sun, 3 Nov 2024 15:37:58 -0800
Subject: [PATCH] fix material inspector not grabbing correct material
 sometimes

---
 .../src/avatars-renderer/Avatar.cpp           | 15 +++++-
 .../src/RenderableModelEntityItem.cpp         | 15 +++++-
 .../graphics-scripting/ScriptableModel.cpp    |  5 +-
 libraries/render-utils/src/Model.cpp          | 50 ++++++++++---------
 libraries/render-utils/src/Model.h            |  4 +-
 5 files changed, 59 insertions(+), 30 deletions(-)

diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index fb22db3ce0..ab28dba7a1 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -1957,10 +1957,23 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel() {
     }
     auto result = _skeletonModel->getScriptableModel();
     result.objectID = getSessionUUID().isNull() ? AVATAR_SELF_ID : getSessionUUID();
+
+    std::unordered_map<std::string, graphics::MultiMaterial> materials;
     {
         std::lock_guard<std::mutex> lock(_materialsLock);
-        result.appendMaterials(_materials);
+        materials = _materials;
     }
+
+    for (auto& multiMaterial : materials) {
+        while (!multiMaterial.second.empty()) {
+            auto shapeIDs = _skeletonModel->getMeshIDsAndMaterialNamesFromMaterialID(multiMaterial.first.c_str());
+            for (const auto& shapeID : shapeIDs) {
+                result.appendMaterial(multiMaterial.second.top(), shapeID.first, shapeID.second);
+            }
+            multiMaterial.second.pop();
+        }
+    }
+
     return result;
 }
 
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index eeb7945660..d6e7f77b7b 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -987,10 +987,23 @@ scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScript
 
     auto result = model->getScriptableModel();
     result.objectID = getEntity()->getID();
+
+    std::unordered_map<std::string, graphics::MultiMaterial> materials;
     {
         std::lock_guard<std::mutex> lock(_materialsLock);
-        result.appendMaterials(_materials);
+        materials = _materials;
     }
+
+    for (auto& multiMaterial : materials) {
+        while (!multiMaterial.second.empty()) {
+            auto shapeIDs = model->getMeshIDsAndMaterialNamesFromMaterialID(multiMaterial.first.c_str());
+            for (const auto& shapeID : shapeIDs) {
+                result.appendMaterial(multiMaterial.second.top(), shapeID.first, shapeID.second);
+            }
+            multiMaterial.second.pop();
+        }
+    }
+
     return result;
 }
 
diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
index 3cf70915c3..a515b29826 100644
--- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
+++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
@@ -257,8 +257,9 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) {
 }
 
 void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName) {
-    materialLayers[QString::number(shapeID)].push_back(ScriptableMaterialLayer(materialLayer));
-    materialLayers["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterialLayer(materialLayer));
+    ScriptableMaterialLayer layer = ScriptableMaterialLayer(materialLayer);
+    materialLayers[QString::number(shapeID)].push_back(layer);
+    materialLayers["mat::" + QString::fromStdString(materialName)].push_back(layer);
 }
 
 void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map<std::string, graphics::MultiMaterial>& materialsToAppend) {
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 69a593ed09..409275e3db 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -1653,13 +1653,13 @@ bool Model::isRenderable() const {
     return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
 }
 
-std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
-    std::set<unsigned int> toReturn;
+std::set<std::pair<uint, std::string>> Model::getMeshIDsAndMaterialNamesFromMaterialID(QString parentMaterialName) {
+    std::set<std::pair<uint, std::string>> toReturn;
 
     const QString all("all");
     if (parentMaterialName == all) {
         for (unsigned int i = 0; i < (unsigned int)_modelMeshRenderItemIDs.size(); i++) {
-            toReturn.insert(i);
+            toReturn.insert({ i, i < _modelMeshMaterialNames.size() ? _modelMeshMaterialNames[i] : "" });
         }
     } else if (!parentMaterialName.isEmpty()) {
         auto parseFunc = [this, &toReturn] (QString& target) {
@@ -1673,12 +1673,14 @@ std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialNam
                 std::string targetStdString = target.replace(0, MATERIAL_NAME_PREFIX.size(), "").toStdString();
                 for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
                     if (_modelMeshMaterialNames[i] == targetStdString) {
-                        toReturn.insert(i);
+                        toReturn.insert({ i, _modelMeshMaterialNames[i] });
                     }
                 }
                 return;
             }
-            toReturn.insert(target.toUInt());
+
+            uint result = target.toUInt();
+            toReturn.insert({ result, result < _modelMeshMaterialNames.size() ? _modelMeshMaterialNames[result] : "" });
         };
 
         if (parentMaterialName.length() > 2 && parentMaterialName.startsWith("[") && parentMaterialName.endsWith("]")) {
@@ -1720,15 +1722,15 @@ void Model::applyMaterialMapping() {
             continue;
         }
 
-        std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(mapping.first.c_str()));
+        auto shapeIDs = getMeshIDsAndMaterialNamesFromMaterialID(QString(mapping.first.c_str()));
         if (shapeIDs.size() == 0) {
             continue;
         }
 
         // This needs to be precomputed before the lambda, since the lambdas could be called out of order
         std::unordered_map<unsigned int, quint16> priorityMapPerResource;
-        for (auto shapeID : shapeIDs) {
-            priorityMapPerResource[shapeID] = ++_priorityMap[shapeID];
+        for (const auto& shapeID : shapeIDs) {
+            priorityMapPerResource[shapeID.first] = ++_priorityMap[shapeID.first];
         }
 
         std::weak_ptr<Model> weakSelf = shared_from_this();
@@ -1756,15 +1758,15 @@ void Model::applyMaterialMapping() {
                     networkMaterial = networkMaterialResource->parsedMaterials.networkMaterials[networkMaterialResource->parsedMaterials.names[0]];
                 }
             }
-            for (auto shapeID : shapeIDs) {
-                if (shapeID < modelMeshRenderItemIDs.size()) {
-                    auto itemID = modelMeshRenderItemIDs[shapeID];
-                    auto meshIndex = modelMeshRenderItemShapes[shapeID].meshIndex;
+            for (const auto& shapeID : shapeIDs) {
+                if (shapeID.first < modelMeshRenderItemIDs.size()) {
+                    auto itemID = modelMeshRenderItemIDs[shapeID.first];
+                    auto meshIndex = modelMeshRenderItemShapes[shapeID.first].meshIndex;
                     bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKeyMap.at(meshIndex);
-                    graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, priorityMapPerResource.at(shapeID));
+                    graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, priorityMapPerResource.at(shapeID.first));
                     {
                         std::unique_lock<std::mutex> lock(self->_materialMappingMutex);
-                        self->_materialMapping[shapeID].push_back(material);
+                        self->_materialMapping[shapeID.first].push_back(material);
                     }
                     transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
                             invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
@@ -1787,17 +1789,17 @@ void Model::applyMaterialMapping() {
 }
 
 void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
-    std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
+    auto shapeIDs = getMeshIDsAndMaterialNamesFromMaterialID(QString(parentMaterialName.c_str()));
 
     auto renderItemsKey = _renderItemKeyGlobalFlags;
     PrimitiveMode primitiveMode = getPrimitiveMode();
     bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
 
     render::Transaction transaction;
-    for (auto shapeID : shapeIDs) {
-        if (shapeID < _modelMeshRenderItemIDs.size()) {
-            auto itemID = _modelMeshRenderItemIDs[shapeID];
-            auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
+    for (const auto& shapeID : shapeIDs) {
+        if (shapeID.first < _modelMeshRenderItemIDs.size()) {
+            auto itemID = _modelMeshRenderItemIDs[shapeID.first];
+            auto meshIndex = _modelMeshRenderItemShapes[shapeID.first].meshIndex;
             bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
             transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
                 invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
@@ -1812,14 +1814,14 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
 }
 
 void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
-    std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
+    auto shapeIDs = getMeshIDsAndMaterialNamesFromMaterialID(QString(parentMaterialName.c_str()));
     render::Transaction transaction;
-    for (auto shapeID : shapeIDs) {
-        if (shapeID < _modelMeshRenderItemIDs.size()) {
-            auto itemID = _modelMeshRenderItemIDs[shapeID];
+    for (const auto& shapeID : shapeIDs) {
+        if (shapeID.first < _modelMeshRenderItemIDs.size()) {
+            auto itemID = _modelMeshRenderItemIDs[shapeID.first];
             auto renderItemsKey = _renderItemKeyGlobalFlags;
             PrimitiveMode primitiveMode = getPrimitiveMode();
-            auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
+            auto meshIndex = _modelMeshRenderItemShapes[shapeID.first].meshIndex;
             bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
             bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
             transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index bc9b8fcfff..6b641df002 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -371,6 +371,8 @@ public:
 
     void setBlendshapeCoefficients(const QVector<float>& coefficients) { _blendshapeCoefficients = coefficients; }
 
+    std::set<std::pair<uint, std::string>> getMeshIDsAndMaterialNamesFromMaterialID(QString parentMaterialName);
+
 public slots:
     void loadURLFinished(bool success);
 
@@ -521,8 +523,6 @@ private:
     std::function<float()> _loadingPriorityOperator { []() { return 0.0f; } };
 
     void calculateTextureInfo();
-
-    std::set<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
 };
 
 Q_DECLARE_METATYPE(ModelPointer)