diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 1fdff19e38..bfba196350 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -841,10 +841,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 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 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
* "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 ec29fb009e..515fbc4381 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -1486,29 +1486,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()) {
@@ -1531,7 +1558,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 0f8eb782c3..8b14c5b29b 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)