From 3578df7a0e296107c786781c957ed41affc02b2f Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 19 Dec 2018 13:28:33 -0800 Subject: [PATCH 1/2] material targeting --- .../entities/src/EntityItemProperties.cpp | 12 ++-- libraries/render-utils/src/Model.cpp | 61 +++++++++++++------ libraries/render-utils/src/Model.h | 2 +- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index b6307a83da..72c90092f0 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -779,10 +779,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is * applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of * 0. - * @property {string|number} parentMaterialName="0" - Selects the submesh or submeshes within the parent to apply the material - * to. If in the format "mat::string", all submeshes with material name "string" are replaced. - * Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are - * parsed to 0. + * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. + * If in the format "mat::string", all mesh parts with material name "string" are replaced. + * Otherwise the property value is parsed as an unsigned integer, specifying the mesh parth index to modify. If "all", + * all mesh parts will be replaced. If an array (starts with "[" and ends with "]"), the string will be + * split at each "," and each element will be parsed as either a number or a string if it starts with + * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 1 and 2, and any + * mesh parts with material "string" or "string2". Do not put spaces around the commas. Invalid values + * are parsed to 0. * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or * "projected". In "uv" mode, the material will be evaluated within the UV space of the mesh it is applied to. In * "projected" mode, the 3D transform of the Material Entity will be used to evaluate the texture coordinates for the material. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9cefbf65a8..f3c6ceb178 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1533,29 +1533,56 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialName) { - // try to find all meshes with materials that match parentMaterialName as a string - // if none, return parentMaterialName as a uint - std::vector toReturn; - const QString MATERIAL_NAME_PREFIX = "mat::"; - if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) { - parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); - for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) { - if (_modelMeshMaterialNames[i] == parentMaterialName.toStdString()) { - toReturn.push_back(i); - } - } - } +std::set Model::getMeshIDsFromMaterialID(QString parentMaterialName) { + std::set toReturn; - if (toReturn.empty()) { - toReturn.push_back(parentMaterialName.toUInt()); + const QString all("all"); + if (parentMaterialName == all) { + for (unsigned int i = 0; i < (unsigned int)_modelMeshRenderItemIDs.size(); i++) { + toReturn.insert(i); + } + } else if (!parentMaterialName.isEmpty()) { + auto parseFunc = [this, &toReturn] (QString& target) { + if (target.isEmpty()) { + return; + } + // if target starts with "mat::", try to find all meshes with materials that match target as a string + // otherwise, return target as a uint + const QString MATERIAL_NAME_PREFIX("mat::"); + if (target.startsWith(MATERIAL_NAME_PREFIX)) { + 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); + } + } + return; + } + toReturn.insert(target.toUInt()); + }; + + if (parentMaterialName.length() > 2 && parentMaterialName.startsWith("[") && parentMaterialName.endsWith("]")) { + QStringList list = parentMaterialName.split(",", QString::SkipEmptyParts); + for (int i = 0; i < list.length(); i++) { + auto& target = list[i]; + if (i == 0) { + target = target.replace(0, 1, ""); + } + if (i == list.length() - 1) { + target = target.replace(target.length() - 1, 1, ""); + } + parseFunc(target); + } + } else { + parseFunc(parentMaterialName); + } } return toReturn; } void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { - std::vector shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); + std::set shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { @@ -1578,7 +1605,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par } void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) { - std::vector shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); + std::set shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 93a0626d28..da06eb7ef0 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -513,7 +513,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(QString parentMaterialName); + std::set getMeshIDsFromMaterialID(QString parentMaterialName); }; Q_DECLARE_METATYPE(ModelPointer) From 17ac4138b68f118ddab5b9dff3eb7641ef886d3f Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Fri, 18 Jan 2019 13:43:56 -0800 Subject: [PATCH 2/2] typos --- libraries/entities/src/EntityItemProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 72c90092f0..51e1db063c 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -781,10 +781,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * 0. * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. * If in the format "mat::string", all mesh parts with material name "string" are replaced. - * Otherwise the property value is parsed as an unsigned integer, specifying the mesh parth index to modify. If "all", + * Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. If "all", * all mesh parts will be replaced. If an array (starts with "[" and ends with "]"), the string will be * split at each "," and each element will be parsed as either a number or a string if it starts with - * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 1 and 2, and any + * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 0 and 1, and any * mesh parts with material "string" or "string2". Do not put spaces around the commas. Invalid values * are parsed to 0. * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or