diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md
index b96c688f25..d387d28718 100644
--- a/documents/Specification/MaterialX.Proposals.md
+++ b/documents/Specification/MaterialX.Proposals.md
@@ -188,7 +188,25 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well.
* `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic.
* `in` (float): the 1D coordinate at which the noise is evaluated.
+
+Expanded 2D Worley noise to support different distance metrics and periodicity.
+
+* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features).
+ * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance".
+ * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic.
+
+
+
+Expanded 3D Worley noise to support different distance metrics and periodicity.
+
+* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features).
+ * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance".
+ * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic.
+
+#### Periodic Noises
+
+In #1201 it was decided that separate periodic versions of all of the noises is preferred to adding it to the existing noises.
### Shape Nodes
diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md
index 070587340c..65027694d8 100644
--- a/documents/Specification/MaterialX.Specification.md
+++ b/documents/Specification/MaterialX.Specification.md
@@ -887,16 +887,12 @@ Standard Noise nodes:
* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features).
- * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance".
- * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic.
* `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0.
* `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates.
* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features).
- * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance".
- * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic.
* `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0.
* `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate.
diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx
index 099465e369..51c7d5fc6e 100644
--- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx
+++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx
@@ -80,10 +80,14 @@
-
+
+
+
+
+
diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx
index d99fab3a8c..a521c756bc 100644
--- a/libraries/bxdf/usd_preview_surface.mtlx
+++ b/libraries/bxdf/usd_preview_surface.mtlx
@@ -152,16 +152,10 @@
-
-
-
-
-
-
-
+
@@ -176,12 +170,8 @@
-
-
-
-
-
+
@@ -223,12 +213,8 @@
-
-
-
-
-
+
diff --git a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp
index d0ddba7e17..5e45ef16cd 100644
--- a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp
+++ b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp
@@ -47,7 +47,7 @@ EMSCRIPTEN_BINDINGS(value)
.function("copy", &mx::Value::copy, ems::pure_virtual())
.function("getTypeString", &mx::Value::getTypeString)
.function("getValueString", &mx::Value::getValueString)
- .class_function("createValueFromStrings", &mx::Value::createValueFromStrings)
+ BIND_CLASS_FUNC("createValueFromStrings", mx::Value, createValueFromStrings, 2, 3, stRef, stRef, mx::ConstTypeDefPtr)
.class_function("setFloatFormat", &mx::Value::setFloatFormat)
.class_function("setFloatPrecision", &mx::Value::setFloatPrecision)
.class_function("getFloatFormat", &mx::Value::getFloatFormat)
diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp
index 22c111f03c..da6c3ca3af 100644
--- a/source/MaterialXCore/Definition.cpp
+++ b/source/MaterialXCore/Definition.cpp
@@ -196,4 +196,12 @@ vector UnitTypeDef::getUnitDefs() const
return unitDefs;
}
+ValuePtr AttributeDef::getValue() const
+{
+ if (!hasValue())
+ return ValuePtr();
+
+ return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType()));
+}
+
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h
index 6498f21c89..0ce7761b6d 100644
--- a/source/MaterialXCore/Definition.h
+++ b/source/MaterialXCore/Definition.h
@@ -423,11 +423,11 @@ class MX_CORE_API TargetDef : public TypedElement
/// @class Member
/// A member element within a TypeDef.
-class MX_CORE_API Member : public TypedElement
+class MX_CORE_API Member : public ValueElement
{
public:
Member(ElementPtr parent, const string& name) :
- TypedElement(parent, CATEGORY, name)
+ ValueElement(parent, CATEGORY, name)
{
}
virtual ~Member() { }
@@ -625,12 +625,7 @@ class MX_CORE_API AttributeDef : public TypedElement
///
/// @return A shared pointer to the typed value of this element, or an
/// empty shared pointer if no value is present.
- ValuePtr getValue() const
- {
- if (!hasValue())
- return ValuePtr();
- return Value::createValueFromStrings(getValueString(), getType());
- }
+ ValuePtr getValue() const;
/// @}
/// @name Elements
diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp
index af47a6a2ba..648d7df000 100644
--- a/source/MaterialXCore/Element.cpp
+++ b/source/MaterialXCore/Element.cpp
@@ -638,6 +638,22 @@ string ValueElement::getResolvedValueString(StringResolverPtr resolver) const
return resolver->resolve(getValueString(), getType());
}
+ValuePtr ValueElement::getValue() const
+{
+ if (!hasValue())
+ return ValuePtr();
+
+ return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType()));
+}
+
+ValuePtr ValueElement::getResolvedValue(StringResolverPtr resolver) const
+{
+ if (!hasValue())
+ return ValuePtr();
+
+ return Value::createValueFromStrings(getResolvedValueString(resolver), getType(), getDocument()->getTypeDef(getType()));
+}
+
ValuePtr ValueElement::getDefaultValue() const
{
ConstElementPtr parent = getParent();
diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h
index a80bc3a49f..fb4bbe07ce 100644
--- a/source/MaterialXCore/Element.h
+++ b/source/MaterialXCore/Element.h
@@ -1037,12 +1037,7 @@ class MX_CORE_API ValueElement : public TypedElement
///
/// @return A shared pointer to the typed value of this element, or an
/// empty shared pointer if no value is present.
- ValuePtr getValue() const
- {
- if (!hasValue())
- return ValuePtr();
- return Value::createValueFromStrings(getValueString(), getType());
- }
+ ValuePtr getValue() const;
/// Return the resolved value of an element as a generic value object, which
/// may be queried to access its data.
@@ -1052,12 +1047,7 @@ class MX_CORE_API ValueElement : public TypedElement
/// will be created at this scope and applied to the return value.
/// @return A shared pointer to the typed value of this element, or an
/// empty shared pointer if no value is present.
- ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const
- {
- if (!hasValue())
- return ValuePtr();
- return Value::createValueFromStrings(getResolvedValueString(resolver), getType());
- }
+ ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const;
/// Return the default value for this element as a generic value object, which
/// may be queried to access its data.
diff --git a/source/MaterialXCore/Exception.h b/source/MaterialXCore/Exception.h
index 4fc0c728ec..4cf51f1cd5 100644
--- a/source/MaterialXCore/Exception.h
+++ b/source/MaterialXCore/Exception.h
@@ -50,6 +50,14 @@ class MX_CORE_API Exception : public std::exception
string _msg;
};
+/// @class ExceptionTypeError
+/// An exception that is thrown when a type mismatch is encountered.
+class MX_CORE_API ExceptionTypeError : public Exception
+{
+ public:
+ using Exception::Exception;
+};
+
MATERIALX_NAMESPACE_END
#endif
diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp
index 68da4b5b9d..bb70aa04ae 100644
--- a/source/MaterialXCore/Value.cpp
+++ b/source/MaterialXCore/Value.cpp
@@ -3,6 +3,8 @@
// SPDX-License-Identifier: Apache-2.0
//
+#include
+#include
#include
#include
@@ -267,12 +269,18 @@ template ValuePtr TypedValue::createFromString(const string& value)
// Value methods
//
-ValuePtr Value::createValueFromStrings(const string& value, const string& type)
+ValuePtr Value::createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef)
{
CreatorMap::iterator it = _creatorMap.find(type);
if (it != _creatorMap.end())
return it->second(value);
+ if (typeDef && !typeDef->getMembers().empty())
+ {
+ // If we're given a TypeDef pointer that has child members, then we can create a new AggregateValue.
+ return AggregateValue::createAggregateValueFromString(value, type, typeDef);
+ }
+
return TypedValue::createFromString(value);
}
@@ -291,6 +299,69 @@ template const T& Value::asA() const
return typedVal->getData();
}
+template <>
+MX_CORE_API bool Value::isA() const
+{
+ return dynamic_cast(this) != nullptr;
+}
+
+template <>
+MX_CORE_API const AggregateValue& Value::asA() const
+{
+ const AggregateValue* typedVal = dynamic_cast(this);
+ if (!typedVal)
+ {
+ throw ExceptionTypeError("Incorrect type specified for value");
+ }
+ return *typedVal;
+}
+
+string AggregateValue::getValueString() const
+{
+ if (_data.empty())
+ return EMPTY_STRING;
+
+ std::string result = "{";
+ std::string separator = "";
+ for (const auto& val : _data)
+ {
+ result += separator + val->getValueString();
+ separator = ";";
+ }
+ result += "}";
+
+ return result;
+}
+
+AggregateValuePtr AggregateValue::createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDef)
+{
+ StringVec subValues = parseStructValueString(value);
+
+ AggregateValuePtr result = AggregateValue::createAggregateValue(type);
+ const auto& members = typeDef->getMembers();
+
+ if (subValues.size() != members.size())
+ {
+ std::stringstream ss;
+ ss << "Wrong number of initializers - expect " << members.size();
+ throw Exception(ss.str());
+ }
+
+ auto doc = typeDef->getDocument();
+ for (size_t i = 0; i < members.size(); ++i)
+ {
+ const auto& member = members[i];
+
+ // This will return nullptr if the type is not a listed typedef.
+ ConstTypeDefPtr subTypeDef = doc->getTypeDef(members[i]->getType());
+
+ // Calling Value::createValueFromStrings() here allows support for recursively nested structs.
+ result->appendValue(Value::createValueFromStrings(subValues[i], member->getType(), subTypeDef));
+ }
+
+ return result;
+}
+
ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int precision) :
_format(Value::getFloatFormat()),
_precision(Value::getFloatPrecision())
diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h
index 764a0ccc01..4dae4ab135 100644
--- a/source/MaterialXCore/Value.h
+++ b/source/MaterialXCore/Value.h
@@ -24,21 +24,22 @@ using BoolVec = vector;
using FloatVec = vector;
class Value;
+class AggregateValue;
/// A shared pointer to a Value
using ValuePtr = shared_ptr;
/// A shared pointer to a const Value
using ConstValuePtr = shared_ptr;
-template class TypedValue;
+/// A shared pointer to an Aggregate Value
+using AggregateValuePtr = shared_ptr;
+/// A shared pointer to a const Aggregate Value
+using ConstAggregateValuePtr = shared_ptr;
-/// @class ExceptionTypeError
-/// An exception that is thrown when a type mismatch is encountered.
-class MX_CORE_API ExceptionTypeError : public Exception
-{
- public:
- using Exception::Exception;
-};
+class TypeDef;
+using ConstTypeDefPtr = shared_ptr;
+
+template class TypedValue;
/// A generic, discriminated value, whose type may be queried dynamically.
class MX_CORE_API Value
@@ -73,7 +74,7 @@ class MX_CORE_API Value
/// Create a new value instance from value and type strings.
/// @return A shared pointer to a typed value, or an empty shared pointer
/// if the conversion to the given data type cannot be performed.
- static ValuePtr createValueFromStrings(const string& value, const string& type);
+ static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr);
/// Create a deep copy of the value.
virtual ValuePtr copy() const = 0;
@@ -193,6 +194,68 @@ template class MX_CORE_API TypedValue : public Value
T _data;
};
+/// A subclass for aggregate values with multiple members
+class MX_CORE_API AggregateValue : public Value
+{
+ public:
+ AggregateValue(const string& typeName) :
+ _typeName(typeName)
+ {
+ }
+ virtual ~AggregateValue() { }
+
+ /// Create a deep copy of the value.
+ ValuePtr copy() const override
+ {
+ auto result = createAggregateValue(_typeName);
+ for (const auto& val : _data)
+ {
+ result->appendValue(val->copy());
+ }
+ return result;
+ }
+
+ /// Append a member value to the aggregate.
+ void appendValue(ConstValuePtr valuePtr)
+ {
+ _data.emplace_back(valuePtr);
+ }
+
+ const vector& getMembers() const
+ {
+ return _data;
+ }
+
+ /// Query an indexed member value from the aggregate.
+ ConstValuePtr getMemberValue(size_t index) const
+ {
+ return _data[index];
+ }
+
+ /// Return type string.
+ const string& getTypeString() const override { return _typeName; }
+
+ /// Return value string.
+ string getValueString() const override;
+
+ //
+ // Static helper methods
+ //
+
+ /// Create a new value from an object of any valid MaterialX type.
+ static AggregateValuePtr createAggregateValue(const string& typeName)
+ {
+ return std::make_shared(typeName);
+ }
+
+ static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr);
+
+ private:
+ const string _typeName;
+
+ vector _data;
+};
+
/// @class ScopedFloatFormatting
/// An RAII class for controlling the float formatting of values.
class MX_CORE_API ScopedFloatFormatting
diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp
index f91305f1a6..651a4ab5ff 100644
--- a/source/MaterialXGenGlsl/GlslSyntax.cpp
+++ b/source/MaterialXGenGlsl/GlslSyntax.cpp
@@ -375,4 +375,41 @@ bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const stri
return true;
}
+StructTypeSyntaxPtr GlslSyntax::createStructSyntax(const string& structTypeName, const string& defaultValue,
+ const string& uniformDefaultValue, const string& typeAlias,
+ const string& typeDefinition) const
+{
+ return std::make_shared(
+ this,
+ structTypeName,
+ defaultValue,
+ uniformDefaultValue,
+ typeAlias,
+ typeDefinition);
+}
+
+string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) const
+{
+ const AggregateValue& aggValue = static_cast(value);
+
+ string result = aggValue.getTypeString() + "(";
+
+ string separator = "";
+ for (const auto& memberValue : aggValue.getMembers())
+ {
+ result += separator;
+ separator = ",";
+
+ auto memberTypeName = memberValue->getTypeString();
+ auto memberTypeDesc = TypeDesc::get(memberTypeName);
+
+ // Recursively use the syntax to generate the output, so we can supported nested structs.
+ result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true);
+ }
+
+ result += ")";
+
+ return result;
+}
+
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h
index 8408534e7e..1e82e354bd 100644
--- a/source/MaterialXGenGlsl/GlslSyntax.h
+++ b/source/MaterialXGenGlsl/GlslSyntax.h
@@ -45,6 +45,20 @@ class MX_GENGLSL_API GlslSyntax : public Syntax
static const StringVec VEC2_MEMBERS;
static const StringVec VEC3_MEMBERS;
static const StringVec VEC4_MEMBERS;
+
+ protected:
+ StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue,
+ const string& uniformDefaultValue, const string& typeAlias,
+ const string& typeDefinition) const override;
+};
+
+/// Specialization of TypeSyntax for aggregate types.
+class MX_GENGLSL_API GlslStructTypeSyntax : public StructTypeSyntax
+{
+ public:
+ using StructTypeSyntax::StructTypeSyntax;
+
+ string getValue(const Value& value, bool uniform) const override;
};
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl
index bef1e430d4..bb6eaf157a 100644
--- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl
+++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl
@@ -441,3 +441,23 @@ export float3 mx_viewdirection_vector3(
::state::coordinate_object,
internal_space_direction));
}
+
+
+export float3 mx_extractGroup(
+ uniform texcoordGroup_struct in = {{0.1,0.1},{0.2,0.2},{0.3,0.3}},
+ uniform int index = 0
+)
+ [[
+ anno::description("Node Group: experimental")
+ ]]
+{
+ result = in.st_0.ss;
+
+ if (index == 1)
+ result = in.st_1.ss;
+ else if (index == 2)
+ result = in.st_2.ss;
+
+ return result;
+}
+
diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp
index f29719a39b..d0d9d96cba 100644
--- a/source/MaterialXGenOsl/OslShaderGenerator.cpp
+++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
#include
#include
@@ -510,10 +511,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage
{
static const std::unordered_map UI_WIDGET_METADATA =
{
- { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) },
- { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) },
- { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) },
- { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) }
+ { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) },
+ { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) },
+ { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) },
+ { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) }
};
static const std::set METADATA_TYPE_BLACKLIST =
diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp
index 6c23382f81..398232bf39 100644
--- a/source/MaterialXGenShader/ShaderGenerator.cpp
+++ b/source/MaterialXGenShader/ShaderGenerator.cpp
@@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen
return impl;
}
+/// Load any struct type definitions from the document in to the type cache.
+void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc)
+{
+ for (const auto& mxTypeDef : doc->getTypeDefs())
+ {
+ const auto& typeDefName = mxTypeDef->getName();
+ const auto& members = mxTypeDef->getMembers();
+
+ // If we don't have any member children then we're not going to consider ourselves a struct.
+ if (members.empty())
+ continue;
+
+ StructTypeDesc newStructTypeDesc;
+ for (const auto& member : members)
+ {
+ auto memberName = member->getName();
+ auto memberTypeName = member->getType();
+ auto memberType = TypeDesc::get(memberTypeName);
+ auto memberDefaultValue = member->getValueString();
+
+ newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue);
+ }
+
+ auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc);
+
+ TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex);
+
+ TypeDescRegistry(structTypeDesc, typeDefName);
+
+ StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName));
+ }
+
+ _syntax->registerStructTypeDescSyntax();
+}
+
+/// Clear any struct type definitions loaded
+void ShaderGenerator::clearStructTypeDefs()
+{
+ StructTypeDesc::clear();
+}
+
namespace
{
diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h
index fa60a4d63e..a2f54fec2e 100644
--- a/source/MaterialXGenShader/ShaderGenerator.h
+++ b/source/MaterialXGenShader/ShaderGenerator.h
@@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator
return _tokenSubstitutions;
}
+ /// Load any struct type definitions from the document in to the type cache.
+ void loadStructTypeDefs(const DocumentPtr& doc);
+
+ /// Clear any struct type definitions loaded
+ void clearStructTypeDefs();
+
/// Register metadata that should be exported to the generated shaders.
/// Supported metadata includes standard UI attributes like "uiname", "uifolder",
/// "uimin", "uimax", etc.
diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp
index 4e90fcbb2d..d52810ffc4 100644
--- a/source/MaterialXGenShader/ShaderNode.cpp
+++ b/source/MaterialXGenShader/ShaderNode.cpp
@@ -437,7 +437,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context)
const string& attrValue = nodeDef.getAttribute(nodedefAttr);
if (!attrValue.empty())
{
- ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName());
+ ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue);
if (!value)
{
value = metadataEntry->value;
@@ -472,7 +472,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context)
if (!attrValue.empty())
{
const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType();
- ValuePtr value = Value::createValueFromStrings(attrValue, type.getName());
+ ValuePtr value = type.createValueFromStrings(attrValue);
if (!value)
{
value = metadataEntry->value;
diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp
index 661aa41660..b8eed3e9b8 100644
--- a/source/MaterialXGenShader/Syntax.cpp
+++ b/source/MaterialXGenShader/Syntax.cpp
@@ -190,6 +190,36 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair<
return false;
}
+void Syntax::registerStructTypeDescSyntax()
+{
+ for (const auto& typeName : StructTypeDesc::getStructTypeNames())
+ {
+ const auto& typeDesc = TypeDesc::get(typeName);
+ const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex());
+
+ string structTypeName = typeName;
+ string defaultValue = typeName + "( ";
+ string uniformDefaultValue = EMPTY_STRING;
+ string typeAlias = EMPTY_STRING;
+ string typeDefinition = "struct " + structTypeName + " { ";
+
+ for (const auto& x : structTypeDesc.getMembers())
+ {
+ string memberName = x._name;
+ string memberType = x._typeDesc.getName();
+ string memberDefaultValue = x._defaultValueStr;
+
+ defaultValue += memberDefaultValue + ", ";
+ typeDefinition += memberType + " " + memberName + "; ";
+ }
+
+ typeDefinition += " };";
+ defaultValue += " )";
+
+ registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition));
+ }
+}
+
const StringVec TypeSyntax::EMPTY_MEMBERS;
TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue,
@@ -246,4 +276,39 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const
return valueString.empty() ? valueString : getName() + "(" + valueString + ")";
}
+StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue,
+ const string& typeAlias, const string& typeDefinition, const StringVec& members) :
+ TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax)
+{
+}
+
+string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const
+{
+ const AggregateValue& aggValue = static_cast(value);
+
+ auto typeDesc = TypeDesc::get(aggValue.getTypeString());
+ auto structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex());
+
+ string result = "{";
+
+ string separator = "";
+ for (const auto& memberValue : aggValue.getMembers())
+ {
+ result += separator;
+ separator = ";";
+
+ auto memberTypeName = memberValue->getTypeString();
+ auto memberTypeDesc = TypeDesc::get(memberTypeName);
+
+ // Recursively use the syntax to generate the output, so we can support nested structs.
+ const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true);
+
+ result += valueStr;
+ }
+
+ result += "}";
+
+ return result;
+}
+
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h
index a4bb7e49b5..6f16633b59 100644
--- a/source/MaterialXGenShader/Syntax.h
+++ b/source/MaterialXGenShader/Syntax.h
@@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN
class Syntax;
class TypeSyntax;
+class StructTypeSyntax;
class TypeDesc;
class ShaderPort;
@@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr;
using ConstSyntaxPtr = shared_ptr;
/// Shared pointer to a TypeSyntax
using TypeSyntaxPtr = shared_ptr;
+/// Shared pointer to a StructTypeSyntax
+using StructTypeSyntaxPtr = shared_ptr;
/// Map holding identifier names and a counter for
/// creating unique names from them.
@@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax
/// Multiple calls will add to the internal set of tokens.
void registerInvalidTokens(const StringMap& tokens);
+ virtual void registerStructTypeDescSyntax();
+
/// Returns a set of names that are reserved words for this language syntax.
const StringSet& getReservedWords() const { return _reservedWords; }
@@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax
/// Protected constructor
Syntax();
+ virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue,
+ const string& uniformDefaultValue, const string& typeAlias,
+ const string& typeDefinition) const
+ {
+ return std::make_shared(
+ this,
+ structTypeName,
+ defaultValue,
+ uniformDefaultValue,
+ typeAlias,
+ typeDefinition);
+ }
+
vector _typeSyntaxes;
std::unordered_map _typeSyntaxIndexByType;
@@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax
string getValue(const Value& value, bool uniform) const override;
};
+/// Specialization of TypeSyntax for aggregate types.
+class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax
+{
+ public:
+ StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue,
+ const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING,
+ const StringVec& members = EMPTY_MEMBERS);
+
+ string getValue(const Value& value, bool uniform) const override;
+
+ protected:
+ const Syntax* _parentSyntax;
+};
+
MATERIALX_NAMESPACE_END
#endif
diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp
index 1267caf14d..5d51680211 100644
--- a/source/MaterialXGenShader/TypeDesc.cpp
+++ b/source/MaterialXGenShader/TypeDesc.cpp
@@ -5,7 +5,7 @@
#include
-#include
+#include
MATERIALX_NAMESPACE_BEGIN
@@ -28,6 +28,16 @@ TypeDescNameMap& typeNameMap()
return map;
}
+using StructTypeDescStorage = vector;
+StructTypeDescStorage& structTypeStorage()
+{
+ // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage
+ // is not thread-safe, and we should consider replacing this with thread-local
+ // data in the GenContext object.
+ static StructTypeDescStorage storage;
+ return storage;
+}
+
} // anonymous namespace
const string TypeDesc::NONE_TYPE_NAME = "none";
@@ -46,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name)
return it != types.end() ? it->second : Type::NONE;
}
-TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name)
+void TypeDesc::remove(const string& name)
+{
+ TypeDescNameMap& typenames = typeNameMap();
+
+ TypeDescMap& types = typeMap();
+
+ auto it = types.find(name);
+ if (it == types.end())
+ return;
+
+ typenames.erase(it->second.typeId());
+ types.erase(it);
+}
+
+ValuePtr TypeDesc::createValueFromStrings(const string& value) const
+{
+ ValuePtr newValue = Value::createValueFromStrings(value, getName());
+ if (!isStruct())
+ return newValue;
+
+ // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed
+ // the optional TypeDef argument, otherwise it just returns a "string" typed Value.
+ // So if this is a struct type we need to create a new AggregateValue.
+
+ StringVec subValues = parseStructValueString(value);
+
+ AggregateValuePtr result = AggregateValue::createAggregateValue(getName());
+ auto structTypeDesc = StructTypeDesc::get(getStructIndex());
+ const auto& members = structTypeDesc.getMembers();
+
+ if (subValues.size() != members.size())
+ {
+ std::stringstream ss;
+ ss << "Wrong number of initializers - expect " << members.size();
+ throw ExceptionShaderGenError(ss.str());
+ }
+
+ for (size_t i = 0; i < members.size(); ++i)
+ {
+ result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i]));
+ }
+
+ return result;
+}
+
+TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name)
{
TypeDescMap& types = typeMap();
TypeDescNameMap& typenames = typeNameMap();
@@ -86,4 +141,74 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material")
} // namespace Type
+//
+// StructTypeDesc methods
+//
+
+void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr)
+{
+ _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr));
+}
+
+vector StructTypeDesc::getStructTypeNames()
+{
+ StructTypeDescStorage& structs = structTypeStorage();
+ vector structNames;
+ for (const auto& x : structs)
+ {
+ structNames.emplace_back(x.typeDesc().getName());
+ }
+ return structNames;
+}
+
+StructTypeDesc& StructTypeDesc::get(unsigned int index)
+{
+ StructTypeDescStorage& structs = structTypeStorage();
+ return structs[index];
+}
+
+uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc)
+{
+ StructTypeDescStorage& structs = structTypeStorage();
+ if (structs.size() >= std::numeric_limits::max())
+ {
+ throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded.");
+ }
+ uint16_t index = static_cast(structs.size());
+ structs.emplace_back(structTypeDesc);
+ return index;
+}
+
+void StructTypeDesc::clear()
+{
+ StructTypeDescStorage& structs = structTypeStorage();
+ for (const auto& structType: structs)
+ {
+ // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it.
+ TypeDesc::remove(structType.typeDesc().getName());
+ }
+ structs.clear();
+}
+
+const string& StructTypeDesc::getName() const
+{
+ return _typedesc.getName();
+}
+
+const vector& StructTypeDesc::getMembers() const
+{
+ return _members;
+}
+
+TypeDesc createStructTypeDesc(std::string_view name)
+{
+ return {name, TypeDesc::BASETYPE_STRUCT};
+}
+
+void registerStructTypeDesc(std::string_view name)
+{
+ auto structTypeDesc = createStructTypeDesc(name);
+ TypeDescRegistry register_struct(structTypeDesc, string(name));
+}
+
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h
index 1a537b7e58..95d2851915 100644
--- a/source/MaterialXGenShader/TypeDesc.h
+++ b/source/MaterialXGenShader/TypeDesc.h
@@ -10,6 +10,7 @@
/// Type descriptor for a MaterialX data type.
#include
+#include
#include
@@ -61,14 +62,21 @@ class MX_GENSHADER_API TypeDesc
/// Empty constructor.
constexpr TypeDesc() noexcept :
- _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { }
+ _id(0),
+ _basetype(BASETYPE_NONE),
+ _semantic(SEMANTIC_NONE),
+ _size(0),
+ _structIndex(0)
+ {
+ }
/// Constructor.
- constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept :
+ constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept :
_id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal.
_basetype(basetype),
_semantic(semantic),
- _size(size)
+ _size(size),
+ _structIndex(structIndex)
{
}
@@ -112,6 +120,12 @@ class MX_GENSHADER_API TypeDesc
/// Return true if the type represents a closure.
bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); }
+ /// Return true if the type represents a struct.
+ bool isStruct() const { return _basetype == BASETYPE_STRUCT; }
+
+ /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false.
+ uint16_t getStructIndex() const { return _structIndex; }
+
/// Equality operator
bool operator==(TypeDesc rhs) const
{
@@ -143,8 +157,14 @@ class MX_GENSHADER_API TypeDesc
/// If no type is found Type::NONE is returned.
static TypeDesc get(const string& name);
+ /// Remove a type description by name, if it exists.
+ static void remove(const string& name);
+
static const string NONE_TYPE_NAME;
+ /// Create a Value from a string for a given typeDesc
+ ValuePtr createValueFromStrings(const string& value) const;
+
private:
/// Simple constexpr hash function, good enough for the small set of short strings that
/// are used for our data type names.
@@ -157,6 +177,7 @@ class MX_GENSHADER_API TypeDesc
uint8_t _basetype;
uint8_t _semantic;
uint16_t _size;
+ uint16_t _structIndex;
};
/// @class TypeDescRegistry
@@ -208,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE
} // namespace Type
+
+/// @class StructTypeDesc
+/// A type descriptor for MaterialX struct types.
+///
+/// All types need to have a type descriptor registered in order for shader generators
+/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then
+/// the type also needs to have an associated StructTypeDesc that describes the members
+/// of the struct.
+///
+class MX_GENSHADER_API StructTypeDesc
+{
+ public:
+ struct StructMemberTypeDesc
+ {
+ StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) :
+ _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr)
+ {
+ }
+ string _name;
+ TypeDesc _typeDesc;
+ string _defaultValueStr;
+ };
+
+ /// Empty constructor.
+ StructTypeDesc() noexcept{}
+
+ void addMember(const string& name, TypeDesc type, string defaultValueStr);
+ void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; }
+
+ /// Return a type description by index.
+ static StructTypeDesc& get(unsigned int index);
+ static vector getStructTypeNames();
+ static uint16_t emplace_back(StructTypeDesc structTypeDesc);
+ static void clear();
+
+ TypeDesc typeDesc() const { return _typedesc; }
+
+ const string& getName() const;
+
+ const vector& getMembers() const;
+
+ private:
+ TypeDesc _typedesc;
+ vector _members;
+};
+
+class MX_GENSHADER_API StructTypeDescRegistry
+{
+ public:
+ StructTypeDescRegistry();
+};
+
MATERIALX_NAMESPACE_END
#endif
diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp
index dbc9b4f980..92cd8f07c7 100644
--- a/source/MaterialXGraphEditor/RenderView.cpp
+++ b/source/MaterialXGraphEditor/RenderView.cpp
@@ -630,6 +630,9 @@ void RenderView::initContext(mx::GenContext& context)
unitSystem->setUnitConverterRegistry(_unitRegistry);
context.getShaderGenerator().setUnitSystem(unitSystem);
context.getOptions().targetDistanceUnit = "meter";
+
+ // Register struct type definitions
+ context.getShaderGenerator().loadStructTypeDefs(_document);
}
void RenderView::drawContents()
diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp
index 881f1b7eea..00fdc65381 100644
--- a/source/MaterialXRender/Util.cpp
+++ b/source/MaterialXRender/Util.cpp
@@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties&
else
{
valueString += val;
- uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType()));
+ uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString));
valueString.clear();
index = 0;
}
diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp
index 788af713b2..064ab898ff 100644
--- a/source/MaterialXRenderGlsl/GlslMaterial.cpp
+++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp
@@ -360,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s
{
valueString = value->getValueString();
}
- uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName()));
+ uniform->setValue(uniform->getType().createValueFromStrings(valueString));
if (_doc)
{
ElementPtr element = _doc->getDescendant(uniform->getPath());
diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp
index b2ca0aa66e..b63e1faecc 100644
--- a/source/MaterialXRenderGlsl/GlslProgram.cpp
+++ b/source/MaterialXRenderGlsl/GlslProgram.cpp
@@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation,
return nullptr;
}
-MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList)
+MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList)
{
auto uniform = uniformList.find(uniformName);
if (uniform != uniformList.end())
@@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList()
for (size_t i = 0; i < uniforms.size(); ++i)
{
const ShaderPort* v = uniforms[i];
- int glType = mapTypeToOpenGLType(v->getType());
- // There is no way to match with an unnamed variable
- if (v->getVariable().empty())
- {
- continue;
- }
-
- // Ignore types which are unsupported in GLSL.
- if (glType == Input::INVALID_OPENGL_TYPE)
- {
- continue;
- }
+ const auto& variablePath = v->getPath();
+ const auto& variableUnit = v->getUnit();
+ const auto& variableColorspace = v->getColorSpace();
+ const auto& variableSemantic = v->getSemantic();
- auto inputIt = _uniformList.find(v->getVariable());
- if (inputIt != _uniformList.end())
+ const auto populateUniformInput =
+ [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound]
+ (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void
{
- Input* input = inputIt->second.get();
- input->path = v->getPath();
- input->unit = v->getUnit();
- input->colorspace = v->getColorSpace();
- input->value = v->getValue();
- if (input->gltype == glType)
- {
- input->typeString = v->getType().getName();
- }
- else
+ auto populateUniformInput_impl =
+ [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound]
+ (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void
{
- errors.push_back(
- "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. "
- + "Name: \"" + v->getVariable()
- + "\". Type: \"" + v->getType().getName()
- + "\". Semantic: \"" + v->getSemantic()
- + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "")
- + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "")
- + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "")
- + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType()))
- );
- uniformTypeMismatchFound = true;
- }
- }
+ if (!typedesc.isStruct())
+ {
+ // Handle non-struct types
+ int glType = mapTypeToOpenGLType(typedesc);
+
+ // There is no way to match with an unnamed variable
+ if (variableName.empty())
+ {
+ return;
+ }
+
+ // Ignore types which are unsupported in GLSL.
+ if (glType == Input::INVALID_OPENGL_TYPE)
+ {
+ return;
+ }
+
+ auto inputIt = _uniformList.find(variableName);
+ if (inputIt != _uniformList.end())
+ {
+ Input* input = inputIt->second.get();
+ input->path = variablePath;
+ input->unit = variableUnit;
+ input->colorspace = variableColorspace;
+ input->value = variableValue;
+ if (input->gltype == glType)
+ {
+ input->typeString = typedesc.getName();
+ }
+ else
+ {
+ errors.push_back(
+ "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. "
+ + "Name: \"" + variableName
+ + "\". Type: \"" + typedesc.getName()
+ + "\". Semantic: \"" + variableSemantic
+ + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "")
+ + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "")
+ + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "")
+ + "\". GLType: " + std::to_string(glType));
+ uniformTypeMismatchFound = true;
+ }
+ }
+ }
+ else
+ {
+ // If we're a struct - we need to loop over each member
+ auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex());
+ auto aggregateValue = std::static_pointer_cast(variableValue);
+
+ const auto& members = structTypeDesc.getMembers();
+ for (size_t i = 0, n = members.size(); i < n; ++i)
+ {
+ const auto& member = members[i];
+ auto memberTypeDesc = member._typeDesc;
+ auto memberVariableName = variableName + "." + member._name;
+ auto memberVariableValue = aggregateValue->getMemberValue(i);
+
+ populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref);
+ }
+ }
+ };
+
+ return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl);
+ };
+
+ populateUniformInput(v->getType(), v->getVariable(), v->getValue());
}
}
@@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList()
if (string::npos != sattributeName.find(colorSet))
{
string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size());
- inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString());
+ inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber);
}
else if (string::npos != sattributeName.find(uvSet))
{
string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size());
- inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString());
+ inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber);
}
_attributeList[sattributeName] = inputPtr;
diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h
index 7d58dbaca7..4addd7d54b 100644
--- a/source/MaterialXRenderGlsl/GlslProgram.h
+++ b/source/MaterialXRenderGlsl/GlslProgram.h
@@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram
string typeString;
/// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during
/// shader generation.
- MaterialX::ValuePtr value;
+ MaterialX::ConstValuePtr value;
/// Is this a constant
bool isConstant;
/// Element path (if any)
@@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram
// Utility to find a uniform value in an uniform list.
// If uniform cannot be found a null pointer will be return.
- ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList);
+ ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList);
// Bind an individual texture to a program uniform location
ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath,
diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm
index 311d84acee..eb13ea7900 100644
--- a/source/MaterialXRenderMsl/MslMaterial.mm
+++ b/source/MaterialXRenderMsl/MslMaterial.mm
@@ -318,7 +318,7 @@
{
valueString = value->getValueString();
}
- uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName()));
+ uniform->setValue(uniform->getType().createValueFromStrings(valueString));
if (_doc)
{
ElementPtr element = _doc->getDescendant(uniform->getPath());
diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h
index b335e29af5..a823662f5f 100644
--- a/source/MaterialXRenderMsl/MslPipelineStateObject.h
+++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h
@@ -99,7 +99,7 @@ class MX_RENDERMSL_API MslProgram
string typeString;
/// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during
/// shader generation.
- MaterialX::ValuePtr value;
+ MaterialX::ConstValuePtr value;
/// Is this a constant
bool isConstant;
/// Element path (if any)
@@ -256,7 +256,7 @@ class MX_RENDERMSL_API MslProgram
// Utility to find a uniform value in an uniform list.
// If uniform cannot be found a null pointer will be return.
- ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList);
+ ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList);
// Bind an individual texture to a program uniform location
ImagePtr bindTexture(id renderCmdEncoder,
diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm
index 2d5685646f..470fa549b2 100644
--- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm
+++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm
@@ -235,12 +235,12 @@ int GetStrideOfMetalType(MTLDataType type)
if (_shader->hasAttribute(HW::ATTR_TRANSPARENT))
{
- psoDesc.colorAttachments[0].blendingEnabled = YES;
- psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
- psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
- psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
- psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
- psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+ psoDesc.colorAttachments[0].blendingEnabled = YES;
+ psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
+ psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
+ psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+ psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
+ psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
_alphaBlendingEnabled = true;
@@ -265,12 +265,12 @@ int GetStrideOfMetalType(MTLDataType type)
if (string::npos != sattributeName.find(colorSet))
{
string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size());
- inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString());
+ inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber);
}
else if (string::npos != sattributeName.find(uvSet))
{
string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size());
- inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString());
+ inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber);
}
_attributeList[sattributeName] = inputPtr;
@@ -566,8 +566,8 @@ int GetStrideOfMetalType(MTLDataType type)
return nullptr;
}
-MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName,
- const MslProgram::InputMap& uniformList)
+MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName,
+ const MslProgram::InputMap& uniformList)
{
auto uniform = uniformList.find(uniformName);
if (uniform != uniformList.end())
@@ -925,31 +925,54 @@ int GetStrideOfMetalType(MTLDataType type)
{
if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct)
{
- for (MTLStructMember* member in arg.bufferStructType.members)
- {
- std::string uboObjectName = std::string(arg.name.UTF8String);
- std::string memberName = member.name.UTF8String;
- std::string uboDotMemberName = uboObjectName + "." + memberName;
+ const auto uboObjectName = string(arg.name.UTF8String);
- InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING);
- _uniformList[uboDotMemberName] = inputPtr;
- _globalUniformNameList[memberName] = uboDotMemberName;
-
- if (MTLArrayType* arrayMember = member.arrayType)
+ const auto addUniformToList =
+ [this, uboObjectName]
+ (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void
+ {
+ auto addUniformToList_impl =
+ [this, uboObjectName]
+ (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void
{
- for (int i = 0; i < arrayMember.arrayLength; ++i)
+ auto memberName = memberNamePrefix + member.name.UTF8String;
+
+ if (MTLStructType* structMember = member.structType)
{
- for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members)
+ for (MTLStructMember* subMember in structMember.members)
{
- std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String;
- std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember;
+ auto namePrefix = memberName + ".";
+ addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref);
+ }
+ }
+ else
+ {
+ auto uboDotMemberName = uboObjectName + "." + memberName;
+
+ InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING);
+ this->_uniformList[uboDotMemberName] = inputPtr;
+ this->_globalUniformNameList[memberName] = uboDotMemberName;
- InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING);
- _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr;
- _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName;
+ if (MTLArrayType* arrayMember = member.arrayType)
+ {
+ for (int i = 0; i < arrayMember.arrayLength; ++i)
+ {
+ for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members)
+ {
+ auto namePrefix = memberName + "[" + std::to_string(i) + "].";
+ addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref);
+ }
+ }
}
}
- }
+ };
+
+ return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl);
+ };
+
+ for (MTLStructMember* member in arg.bufferStructType.members)
+ {
+ addUniformToList(member, arg.index, arg.bufferDataSize, "");
}
}
@@ -1006,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type)
for (size_t i = 0; i < uniforms.size(); ++i)
{
const ShaderPort* v = uniforms[i];
- MTLDataType resourceType = mapTypeToMetalType(v->getType());
-
- // There is no way to match with an unnamed variable
- if (v->getVariable().empty())
- {
- continue;
- }
- // Ignore types which are unsupported in MSL.
- if (resourceType == MTLDataTypeNone)
- {
- continue;
- }
+ const string& variablePath = v->getPath();
+ const string& variableSemantic = v->getSemantic();
- auto inputIt = _uniformList.find(v->getVariable());
- if (inputIt == _uniformList.end())
+ const auto populateUniformInput =
+ [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound]
+ (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void
{
- if (v->getType() == Type::FILENAME)
+ auto populateUniformInput_impl =
+ [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound]
+ (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void
{
- inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable()));
- }
- else
- {
- inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable());
- }
- }
+ // There is no way to match with an unnamed variable
+ if (variableName.empty())
+ {
+ return;
+ }
- if (inputIt != _uniformList.end())
- {
- Input* input = inputIt->second.get();
- input->path = v->getPath();
- input->value = v->getValue();
- if (input->resourceType == resourceType)
- {
- input->typeString = v->getType().getName();
- }
- else
- {
- errors.push_back(
- "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. "
- + "Name: \"" + v->getVariable()
- + "\". Type: \"" + v->getType().getName()
- + "\". Semantic: \"" + v->getSemantic()
- + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "")
- + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType()))
- );
- uniformTypeMismatchFound = true;
- }
- }
+ MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc);
+ // Ignore types which are unsupported in MSL.
+ if (resourceType == MTLDataTypeNone)
+ {
+ return;
+ }
+
+ if (!variableTypeDesc.isStruct())
+ {
+ auto inputIt = _uniformList.find(variableName);
+
+ if (inputIt == _uniformList.end()) {
+ if(variableTypeDesc == Type::FILENAME)
+ {
+ inputIt = _uniformList.find(TEXTURE_NAME(variableName));
+ }
+ else
+ {
+ inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName);
+ }
+ }
+
+ if (inputIt != _uniformList.end())
+ {
+ Input* input = inputIt->second.get();
+ input->path = variablePath;
+ input->value = variableValue;
+ if (input->resourceType == resourceType)
+ {
+ input->typeString = variableTypeDesc.getName();
+ }
+ else
+ {
+ errors.push_back(
+ "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. "
+ + "Name: \"" + variableName
+ + "\". Type: \"" + variableTypeDesc.getName()
+ + "\". Semantic: \"" + variableSemantic
+ + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "")
+ + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc))
+ );
+ uniformTypeMismatchFound = true;
+ }
+ }
+ }
+ else
+ {
+ auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex());
+ auto aggregateValue = std::static_pointer_cast(variableValue);
+
+ const auto& members = structTypeDesc.getMembers();
+ for (size_t i = 0, n = members.size(); i < n; ++i)
+ {
+ const auto& structMember = members[i];
+ auto memberVariableName = variableName+"."+structMember._name;
+ auto memberVariableValue = aggregateValue->getMemberValue(i);
+
+ populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref);
+ }
+ }
+ };
+
+ return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl);
+ };
+
+ populateUniformInput(v->getType(), v->getVariable(), v->getValue());
}
}
@@ -1231,7 +1289,7 @@ int GetStrideOfMetalType(MTLDataType type)
return false;
};
- auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset)
+ auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset)
{
if (value->getTypeString() == "float")
{
@@ -1307,7 +1365,7 @@ throw ExceptionRenderError(
{
if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset))
{
- MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value;
+ auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value;
if (value)
{
setValue(value, uniformBufferData, member.offset);
@@ -1332,39 +1390,60 @@ throw ExceptionRenderError(
if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset))
{
- auto uniformInfo = _uniformList.find(uniformName);
- if (uniformInfo != _uniformList.end())
- {
- MaterialX::ValuePtr value = uniformInfo->second->value;
- if (value)
- {
- setValue(value, uniformBufferData, member.offset);
- }
- }
- else
- {
- }
- }
-
- if (MTLArrayType* arrayMember = member.arrayType)
- {
- for (int i = 0; i < arrayMember.arrayLength; ++i)
+ const auto setUniformValue =
+ [this, setValue]
+ (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void
{
- for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members)
+ auto setUniformValue_impl =
+ [this, setValue]
+ (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void
{
- string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String;
-
- auto uniformInfo = _uniformList.find(uniformNameSubArray);
- if (uniformInfo != _uniformList.end())
+ if(MTLArrayType* arrayMember = member.arrayType)
{
- MaterialX::ValuePtr value = uniformInfo->second->value;
- if (value)
+ for(int i = 0; i < arrayMember.arrayLength; ++i)
{
- setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset);
+ for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members)
+ {
+ string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String;
+ auto uniformInfo = _uniformList.find(uniformNameSubArray);
+ if (uniformInfo != _uniformList.end())
+ {
+ auto value = uniformInfo->second->value;
+ if(value)
+ {
+ setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset);
+ }
+ }
+ }
}
}
- }
- }
+ else if (MTLStructType* structMember = member.structType)
+ {
+ // this code does not support struct recursion yet....
+ for (MTLStructMember* subMember in structMember.members)
+ {
+ string subUniformName = uniformName+"."+subMember.name.UTF8String;
+ setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref);
+ }
+ }
+ else
+ {
+ auto uniformInfo = _uniformList.find(uniformName);
+ if (uniformInfo != _uniformList.end())
+ {
+ auto value = uniformInfo->second->value;
+ if(value)
+ {
+ setValue(value, uniformBufferData, offset);
+ }
+ }
+ }
+ };
+
+ return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl);
+ };
+
+ setUniformValue(member, uniformName, uniformBufferData, member.offset);
}
}
@@ -1415,14 +1494,15 @@ throw ExceptionRenderError(
// A "filename" is not indicative of type, so just return a 2d sampler.
return MTLDataTypeTexture;
}
- else if (type == Type::BSDF ||
- type == Type::MATERIAL ||
+ else if (type == Type::BSDF ||
+ type == Type::MATERIAL ||
type == Type::DISPLACEMENTSHADER ||
- type == Type::EDF ||
- type == Type::VDF ||
- type == Type::SURFACESHADER ||
- type == Type::LIGHTSHADER ||
- type == Type::VOLUMESHADER)
+ type == Type::EDF ||
+ type == Type::VDF ||
+ type == Type::SURFACESHADER ||
+ type == Type::LIGHTSHADER ||
+ type == Type::VOLUMESHADER ||
+ type.isStruct())
return MTLDataTypeStruct;
return MTLDataTypeNone;
diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp
index 94f8b98708..ae7623084e 100644
--- a/source/MaterialXTest/MaterialXCore/Document.cpp
+++ b/source/MaterialXTest/MaterialXCore/Document.cpp
@@ -10,8 +10,6 @@
#include
#include
-#include
-
namespace mx = MaterialX;
TEST_CASE("Document", "[document]")
@@ -123,16 +121,6 @@ TEST_CASE("Document", "[document]")
REQUIRE(doc->validate());
}
-void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label)
-{
- for (const mx::ElementEquivalenceResult& result : results)
- {
- std::cout << label << ": " << "Element: " << result.path1 <<
- ", Element: " << result.path2 << ", Difference Type: " << result.differenceType
- << ", Value: " << result.attributeName << std::endl;
- }
-}
-
TEST_CASE("Document equivalence", "[document]")
{
mx::DocumentPtr doc = mx::createDocument();
@@ -224,44 +212,18 @@ TEST_CASE("Document equivalence", "[document]")
// Check skipping all value compares
options.skipValueComparisons = true;
bool equivalent = doc->isEquivalent(doc2, options, &results);
- if (equivalent)
- {
- std::cout << "Unexpected skip value equivalence:" << std::endl;
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
- else
- {
- printDifferences(results, "Expected value differences");
- }
REQUIRE(!equivalent);
// Check attibute values
options.skipValueComparisons = false;
results.clear();
equivalent = doc->isEquivalent(doc2, options, &results);
- if (!equivalent)
- {
- printDifferences(results, "Unexpected value difference");
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
REQUIRE(equivalent);
unsigned int currentPrecision = mx::Value::getFloatPrecision();
// This will compare 0.012345608 versus: 1, 0.012345611 for input10
options.precision = 8;
equivalent = doc->isEquivalent(doc2, options);
- if (equivalent)
- {
- std::cout << "Unexpected precision equivalence:" << std::endl;
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
- else
- {
- printDifferences(results, "Expected precision difference");
- }
REQUIRE(!equivalent);
options.precision = currentPrecision;
@@ -274,12 +236,6 @@ TEST_CASE("Document equivalence", "[document]")
floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0");
}
equivalent = doc->isEquivalent(doc2, options, &results);
- if (!equivalent)
- {
- printDifferences(results, "Unexpected filtering differences");
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
REQUIRE(equivalent);
for (mx::InputPtr floatInput : floatInputs)
{
@@ -293,16 +249,6 @@ TEST_CASE("Document equivalence", "[document]")
mismatchElement->setName("mismatch_color4");
results.clear();
equivalent = doc->isEquivalent(doc2, options, &results);
- if (!equivalent)
- {
- printDifferences(results, "Expected name mismatch differences");
- }
- else
- {
- std::cout << "Unexpected name match equivalence:" << std::endl;
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
REQUIRE(!equivalent);
mismatchElement->setName(previousName);
results.clear();
@@ -320,15 +266,5 @@ TEST_CASE("Document equivalence", "[document]")
nodeGraph2->setNodeDefString("ND_mygraph");
results.clear();
equivalent = doc->isEquivalent(doc2, options, &results);
- if (!equivalent)
- {
- printDifferences(results, "Expected functional graph differences");
- }
- else
- {
- std::cout << "Unexpected functional graph equivalence:" << std::endl;
- std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl;
- std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl;
- }
REQUIRE(!equivalent);
}
diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp
index ef746bfe05..f3ce7d40de 100644
--- a/source/MaterialXTest/MaterialXCore/Node.cpp
+++ b/source/MaterialXTest/MaterialXCore/Node.cpp
@@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]")
REQUIRE(typeDef->getMembers().size() == scalarCount);
// Reference the custom type.
- std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45");
+ std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}");
constant->setInputValue("value", d65, "spectrum");
REQUIRE(constant->getInput("value")->getType() == "spectrum");
REQUIRE(constant->getInput("value")->getValueString() == d65);
- REQUIRE(constant->getInputValue("value")->isA());
- REQUIRE(constant->getInputValue("value")->asA() == d65);
+ REQUIRE(constant->getInputValue("value")->isA());
+ REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65);
// Validate the document.
REQUIRE(doc->validate());
diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp
index 4a8e61645a..78da7e50f3 100644
--- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp
+++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp
@@ -649,6 +649,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
addColorManagement();
addUnitSystem();
+ // Register struct typedefs from the library files.
+ _shaderGenerator->loadStructTypeDefs(_dependLib);
+
// Test suite setup
addSkipFiles();
@@ -705,6 +708,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
preprocessDocument(doc);
_shaderGenerator->registerShaderMetadata(doc, context);
+ _shaderGenerator->loadStructTypeDefs(doc);
+
// For each new file clear the implementation cache.
// Since the new file might contain implementations with names
// colliding with implementations in previous test cases.
diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp
index 24aea1eb42..c4c69bb812 100644
--- a/source/MaterialXView/Viewer.cpp
+++ b/source/MaterialXView/Viewer.cpp
@@ -1769,6 +1769,9 @@ void Viewer::initContext(mx::GenContext& context)
unitSystem->setUnitConverterRegistry(_unitRegistry);
context.getShaderGenerator().setUnitSystem(unitSystem);
context.getOptions().targetDistanceUnit = "meter";
+
+ // Initialize the struct typedefs from the stdlib
+ context.getShaderGenerator().loadStructTypeDefs(_stdLib);
}
void Viewer::loadStandardLibraries()
diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp
index 501f9d5f04..c36bd6c288 100644
--- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp
+++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp
@@ -6,6 +6,7 @@
#include
#include
+#include
#define BIND_TYPE_INSTANCE(NAME, T) \
py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \
@@ -22,7 +23,10 @@ void bindPyValue(py::module& mod)
py::class_(mod, "Value")
.def("getValueString", &mx::Value::getValueString)
.def("getTypeString", &mx::Value::getTypeString)
- .def_static("createValueFromStrings", &mx::Value::createValueFromStrings);
+ .def_static("createValueFromStrings", &mx::Value::createValueFromStrings,
+ py::arg("value"),
+ py::arg("type"),
+ py::arg("typeDefPtr") = nullptr);
BIND_TYPE_INSTANCE(integer, int)
BIND_TYPE_INSTANCE(boolean, bool)
diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp
index b952bd4651..0c8a086e58 100644
--- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp
+++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp
@@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod)
.def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem)
.def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem)
.def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions)
+ .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs)
+ .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs)
.def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata);
}