From 548d80d546b85428be9c745f5198944de7d91b8b Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 13 May 2018 17:30:19 -0700 Subject: [PATCH 01/27] Inheritance updates for MaterialX v1.36 - Replace the MaterialInherit and LookInherit elements with inherit attributes. - Add support for NodeDef inheritance. - Update build version to 1.36.0. --- CMakeLists.txt | 4 +- source/MaterialXCore/Definition.cpp | 21 +++--- source/MaterialXCore/Document.cpp | 30 ++++++-- source/MaterialXCore/Element.cpp | 24 ++++++- source/MaterialXCore/Element.h | 66 ++++++++++++----- source/MaterialXCore/Interface.cpp | 108 ++++++++++++++++++++++++++-- source/MaterialXCore/Interface.h | 50 +++++++++++-- source/MaterialXCore/Look.cpp | 22 ------ source/MaterialXCore/Look.h | 62 ---------------- source/MaterialXCore/Material.cpp | 26 +------ source/MaterialXCore/Material.h | 63 ---------------- source/MaterialXCore/Traversal.cpp | 13 ++-- source/MaterialXCore/Util.h | 1 - source/MaterialXTest/Material.cpp | 57 ++++++++------- source/PyMaterialX/PyElement.cpp | 11 +-- source/PyMaterialX/PyInterface.cpp | 10 ++- source/PyMaterialX/PyLook.cpp | 8 --- source/PyMaterialX/PyMaterial.cpp | 8 --- 18 files changed, 309 insertions(+), 275 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23be2c1af4..fdee162372 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ project(MaterialX) set(MATERIALX_MAJOR_VERSION 1) -set(MATERIALX_MINOR_VERSION 35) -set(MATERIALX_BUILD_VERSION 5) +set(MATERIALX_MINOR_VERSION 36) +set(MATERIALX_BUILD_VERSION 0) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) cmake_minimum_required(VERSION 3.1) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 2eb0129266..08f3f06777 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -34,28 +34,25 @@ const string Implementation::LANGUAGE_ATTRIBUTE = "language"; InterfaceElementPtr NodeDef::getImplementation(const string& target, const string& language) const { - for (InterfaceElementPtr element : getDocument()->getMatchingImplementations(getName())) + for (InterfaceElementPtr interface : getDocument()->getMatchingImplementations(getName())) { - // Skip if target does not match - if (!targetStringsMatch(element->getTarget(), target)) + if (!targetStringsMatch(interface->getTarget(), target)) { continue; } - - // Only check language against implementations. Other elements such - // as nodegraphs do not have language specific implementations. - // if (!language.empty()) { - ImplementationPtr implementation = element->asA(); - if (implementation && implementation->getLanguage() != language) + // If the given interface is an implementation element, as opposed to + // a node graph, then check for a language string match. + ImplementationPtr implement = interface->asA(); + if (implement && implement->getLanguage() != language) { continue; } } - - return element; + return interface; } + return InterfaceElementPtr(); } @@ -66,7 +63,7 @@ vector NodeDef::getInstantiatingShaderRefs() const { for (ShaderRefPtr shaderRef : mat->getShaderRefs()) { - if (shaderRef->getNodeDef() == getSelf()) + if (shaderRef->getNodeDef()->hasInheritedBase(getSelf())) { shaderRefs.push_back(shaderRef); } diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index f93d926c18..d8aed778ce 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -296,10 +296,6 @@ void Document::generateRequireString() { requireSet.insert(REQUIRE_STRING_OVERRIDE); } - else if (elem->isA()) - { - requireSet.insert(REQUIRE_STRING_MATINHERIT); - } } string requireStr; @@ -532,6 +528,32 @@ void Document::upgradeVersion() minorVersion = 35; } + // Upgrade from v1.35 to v1.36 + if (majorVersion == 1 && minorVersion == 35) + { + for (ElementPtr elem : traverseTree()) + { + if (elem->isA() || elem->isA()) + { + vector origChildren = elem->getChildren(); + for (ElementPtr child : origChildren) + { + if (child->getCategory() == "materialinherit") + { + elem->setInheritString(child->getAttribute("material")); + elem->removeChild(child->getName()); + } + else if (child->getCategory() == "lookinherit") + { + elem->setInheritString(child->getAttribute("look")); + elem->removeChild(child->getName()); + } + } + } + } + minorVersion = 36; + } + if (majorVersion == MATERIALX_MAJOR_VERSION && minorVersion == MATERIALX_MINOR_VERSION) { diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 253282500e..01992dbbc3 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace MaterialX { @@ -17,6 +19,7 @@ const string Element::TYPE_ATTRIBUTE = "type"; const string Element::FILE_PREFIX_ATTRIBUTE = "fileprefix"; const string Element::GEOM_PREFIX_ATTRIBUTE = "geomprefix"; const string Element::COLOR_SPACE_ATTRIBUTE = "colorspace"; +const string Element::INHERIT_ATTRIBUTE = "inherit"; const string Element::TARGET_ATTRIBUTE = "target"; const string ValueElement::VALUE_ATTRIBUTE = "value"; const string ValueElement::PUBLIC_NAME_ATTRIBUTE = "publicname"; @@ -288,6 +291,18 @@ ConstElementPtr Element::getRoot() const return root; } +bool Element::hasInheritedBase(ConstElementPtr elem) const +{ + for (ConstElementPtr iterElem : traverseInheritance()) + { + if (iterElem == elem) + { + return true; + } + } + return false; +} + bool Element::hasInheritanceCycle() const { try @@ -376,6 +391,11 @@ bool Element::validate(string* message) const { validateRequire(getDocument()->hasColorManagementSystem(), res, message, "Colorspace set without color management system"); } + if (hasInheritString()) + { + bool validInherit = getInheritsFrom() && getInheritsFrom()->getCategory() == getCategory(); + validateRequire(validInherit, res, message, "Invalid element inheritance"); + } for (ElementPtr child : getChildren()) { res = child->validate(message) && res; @@ -480,7 +500,7 @@ ValuePtr ValueElement::getDefaultValue() const NodeDefPtr decl = getParent()->asA()->getDeclaration(); if (decl) { - ValueElementPtr value = decl->getChildOfType(getName()); + ValueElementPtr value = decl->getActiveValueElement(getName()); if (value) { return value->getValue(); @@ -593,10 +613,8 @@ INSTANTIATE_CONCRETE_SUBCLASS(GeomInfo, "geominfo") INSTANTIATE_CONCRETE_SUBCLASS(Implementation, "implementation") INSTANTIATE_CONCRETE_SUBCLASS(Input, "input") INSTANTIATE_CONCRETE_SUBCLASS(Look, "look") -INSTANTIATE_CONCRETE_SUBCLASS(LookInherit, "lookinherit") INSTANTIATE_CONCRETE_SUBCLASS(Material, "material") INSTANTIATE_CONCRETE_SUBCLASS(MaterialAssign, "materialassign") -INSTANTIATE_CONCRETE_SUBCLASS(MaterialInherit, "materialinherit") INSTANTIATE_CONCRETE_SUBCLASS(Member, "member") INSTANTIATE_CONCRETE_SUBCLASS(Node, "node") INSTANTIATE_CONCRETE_SUBCLASS(NodeDef, "nodedef") diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index f202f0bdba..63afceadd9 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -255,6 +255,54 @@ class Element : public std::enable_shared_from_this return getAttribute(TARGET_ATTRIBUTE); } + /// @} + /// @name Inheritance + /// @{ + + /// Set the inherit string of this element. + void setInheritString(const string& inherit) + { + setAttribute(INHERIT_ATTRIBUTE, inherit); + } + + /// Return true if this element has an inherit string. + bool hasInheritString() const + { + return hasAttribute(INHERIT_ATTRIBUTE); + } + + /// Return the inherit string of this element. + const string& getInheritString() const + { + return getAttribute(INHERIT_ATTRIBUTE); + } + + /// Set the element that this one directly inherits from. + void setInheritsFrom(ConstElementPtr super) + { + if (super) + { + setInheritString(super->getName()); + } + else + { + removeAttribute(INHERIT_ATTRIBUTE); + } + } + + /// Return the element, if any, that this one directly inherits from. + ElementPtr getInheritsFrom() const + { + return getRoot()->getChild(getInheritString()); + } + + /// Return true if this element has the given element as an inherited base, + /// taking the full inheritance chain into account. + bool hasInheritedBase(ConstElementPtr elem) const; + + /// Return true if the inheritance chain for this element contains a cycle. + bool hasInheritanceCycle() const; + /// @} /// @name Subclass /// @{ @@ -469,23 +517,6 @@ class Element : public std::enable_shared_from_this return getRoot()->asA(); } - /// @} - /// @name Inheritance - /// @{ - - /// Set the element that this one inherits from, if inheritance is - /// supported by this element subclass. - virtual void setInheritsFrom(ElementPtr elem) { }; - - /// Return the element, if any, that this one inherits from. - virtual ElementPtr getInheritsFrom() const - { - return nullptr; - } - - /// Return true if the inheritance chain for this element contains a cycle. - bool hasInheritanceCycle() const; - /// @} /// @name Traversal /// @{ @@ -680,6 +711,7 @@ class Element : public std::enable_shared_from_this static const string FILE_PREFIX_ATTRIBUTE; static const string GEOM_PREFIX_ATTRIBUTE; static const string COLOR_SPACE_ATTRIBUTE; + static const string INHERIT_ATTRIBUTE; static const string TARGET_ATTRIBUTE; protected: diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 42ad8e8a10..9862b3414f 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -91,7 +91,7 @@ Edge Parameter::getUpstreamEdge(ConstMaterialPtr material, size_t index) const // Apply BindParam elements to the Parameter. for (ShaderRefPtr shaderRef : material->getActiveShaderRefs()) { - if (shaderRef->getNodeDef() == nodeDef) + if (shaderRef->getNodeDef()->hasInheritedBase(nodeDef)) { for (BindParamPtr bindParam : shaderRef->getBindParams()) { @@ -133,7 +133,7 @@ Edge Input::getUpstreamEdge(ConstMaterialPtr material, size_t index) const // Apply BindInput elements to the Input. for (ShaderRefPtr shaderRef : material->getActiveShaderRefs()) { - if (shaderRef->getNodeDef() == nodeDef) + if (shaderRef->getNodeDef()->hasInheritedBase(nodeDef)) { for (BindInputPtr bindInput : shaderRef->getBindInputs()) { @@ -205,6 +205,102 @@ bool Output::validate(string* message) const // InterfaceElement methods // +ParameterPtr InterfaceElement::getActiveParameter(const string& name) const +{ + for (ConstElementPtr elem : traverseInheritance()) + { + ParameterPtr param = elem->asA()->getParameter(name); + if (param) + { + return param; + } + } + return nullptr; +} + +vector InterfaceElement::getActiveParameters() const +{ + vector activeParams; + for (ConstElementPtr elem : traverseInheritance()) + { + vector params = elem->asA()->getParameters(); + activeParams.insert(activeParams.end(), params.begin(), params.end()); + } + return activeParams; +} + +InputPtr InterfaceElement::getActiveInput(const string& name) const +{ + for (ConstElementPtr elem : traverseInheritance()) + { + InputPtr input = elem->asA()->getInput(name); + if (input) + { + return input; + } + } + return nullptr; +} + +vector InterfaceElement::getActiveInputs() const +{ + vector activeInputs; + for (ConstElementPtr elem : traverseInheritance()) + { + vector inputs = elem->asA()->getInputs(); + activeInputs.insert(activeInputs.end(), inputs.begin(), inputs.end()); + } + return activeInputs; +} + +OutputPtr InterfaceElement::getActiveOutput(const string& name) const +{ + for (ConstElementPtr elem : traverseInheritance()) + { + OutputPtr output = elem->asA()->getOutput(name); + if (output) + { + return output; + } + } + return nullptr; +} + +vector InterfaceElement::getActiveOutputs() const +{ + vector activeOutputs; + for (ConstElementPtr elem : traverseInheritance()) + { + vector outputs = elem->asA()->getOutputs(); + activeOutputs.insert(activeOutputs.end(), outputs.begin(), outputs.end()); + } + return activeOutputs; +} + +ValueElementPtr InterfaceElement::getActiveValueElement(const string& name) const +{ + for (ConstElementPtr elem : traverseInheritance()) + { + ValueElementPtr valueElem = elem->asA()->getChildOfType(name); + if (valueElem) + { + return valueElem; + } + } + return nullptr; +} + +vector InterfaceElement::getActiveValueElements() const +{ + vector activeValueElems; + for (ConstElementPtr elem : traverseInheritance()) + { + vector valueElems = elem->asA()->getChildrenOfType(); + activeValueElems.insert(activeValueElems.end(), valueElems.begin(), valueElems.end()); + } + return activeValueElems; +} + ValuePtr InterfaceElement::getParameterValue(const string& name, const string& target) const { ParameterPtr param = getParameter(name); @@ -307,17 +403,17 @@ bool InterfaceElement::isTypeCompatible(InterfaceElementPtr rhs) const { return false; } - for (ParameterPtr param : getParameters()) + for (ParameterPtr param : getActiveParameters()) { - ParameterPtr matchingParam = rhs->getParameter(param->getName()); + ParameterPtr matchingParam = rhs->getActiveParameter(param->getName()); if (matchingParam && matchingParam->getType() != param->getType()) { return false; } } - for (InputPtr input : getInputs()) + for (InputPtr input : getActiveInputs()) { - InputPtr matchingInput = rhs->getInput(input->getName()); + InputPtr matchingInput = rhs->getActiveInput(input->getName()); if (matchingInput && matchingInput->getType() != input->getType()) { return false; diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index cede81f75a..16c644b0da 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -327,6 +327,14 @@ class InterfaceElement : public TypedElement removeChildOfType(name); } + /// Return the first Parameter with the given name that belongs to this + /// interface, taking interface inheritance into account. + ParameterPtr getActiveParameter(const string& name) const; + + /// Return a vector of all Parameter elements that belong to this interface, + /// taking interface inheritance into account. + vector getActiveParameters() const; + /// @} /// @name Inputs /// @{ @@ -368,8 +376,16 @@ class InterfaceElement : public TypedElement removeChildOfType(name); } + /// Return the first Input with the given name that belongs to this + /// interface, taking interface inheritance into account. + InputPtr getActiveInput(const string& name) const; + + /// Return a vector of all Input elements that belong to this interface, + /// taking inheritance into account. + vector getActiveInputs() const; + /// @} - /// @name Output Elements + /// @name Outputs /// @{ /// Add an Output to this element. @@ -398,17 +414,39 @@ class InterfaceElement : public TypedElement return getChildrenOfType(); } + /// Return the number of Output elements. + size_t getOutputCount() const + { + return _outputCount; + } + /// Remove the Output, if any, with the given name. void removeOutput(const string& name) { removeChildOfType(name); } - /// Return the number of Output elements. - size_t getOutputCount() const - { - return _outputCount; - } + /// Return the first Output with the given name that belongs to this + /// interface, taking interface inheritance into account. + OutputPtr getActiveOutput(const string& name) const; + + /// Return a vector of all Output elements that belong to this interface, + /// taking inheritance into account. + vector getActiveOutputs() const; + + /// @} + /// @name Value Elements + /// @{ + + /// Return the first value element with the given name that belongs to this + /// interface, taking interface inheritance into account. + /// Examples of value elements are Parameter, Input, and Output. + ValueElementPtr getActiveValueElement(const string& name) const; + + /// Return a vector of all value elements that belong to this interface, + /// taking inheritance into account. + /// Examples of value elements are Parameter, Input, and Output. + vector getActiveValueElements() const; /// @} /// @name Values diff --git a/source/MaterialXCore/Look.cpp b/source/MaterialXCore/Look.cpp index 8bf1e55692..8ccd124b21 100644 --- a/source/MaterialXCore/Look.cpp +++ b/source/MaterialXCore/Look.cpp @@ -74,28 +74,6 @@ vector Look::getActiveVisibilities() const return activeVisibilities; } -void Look::setInheritsFrom(ElementPtr look) -{ - for (LookInheritPtr inherit : getLookInherits()) - { - removeLookInherit(inherit->getName()); - } - if (look) - { - addLookInherit(look->getName()); - } -} - -ElementPtr Look::getInheritsFrom() const -{ - vector inherits = getLookInherits(); - if (inherits.empty()) - { - return nullptr; - } - return getRoot()->getChildOfType(inherits[0]->getName()); -} - // // MaterialAssign methods // diff --git a/source/MaterialXCore/Look.h b/source/MaterialXCore/Look.h index f933cc0ad4..88464c023e 100644 --- a/source/MaterialXCore/Look.h +++ b/source/MaterialXCore/Look.h @@ -22,11 +22,6 @@ using LookPtr = shared_ptr; /// A shared pointer to a const Look using ConstLookPtr = shared_ptr; -/// A shared pointer to a LookInherit -using LookInheritPtr = shared_ptr; -/// A shared pointer to a const LookInherit -using ConstLookInheritPtr = shared_ptr; - /// A shared pointer to a MaterialAssign using MaterialAssignPtr = shared_ptr; /// A shared pointer to a const MaterialAssign @@ -193,68 +188,11 @@ class Look : public Element } /// @} - /// @name LookInherit Elements - /// @{ - - /// Add a LookInherit to the look. - /// @param name The name of the new LookInherit. - /// If no name is specified, then a unique name will automatically be - /// generated. - /// @return A shared pointer to the new LookInherit. - LookInheritPtr addLookInherit(const string& name = EMPTY_STRING) - { - return addChild(name); - } - - /// Return the LookInherit, if any, with the given name. - LookInheritPtr getLookInherit(const string& name) const - { - return getChildOfType(name); - } - - /// Return a vector of all LookInherit elements in the look. - vector getLookInherits() const - { - return getChildrenOfType(); - } - - /// Remove the LookInherit, if any, with the given name. - void removeLookInherit(const string& name) - { - removeChildOfType(name); - } - - /// @} - /// @name Inheritance - /// @{ - - /// Set the look element that this one inherits from. - void setInheritsFrom(ElementPtr look) override; - - /// Return the look element, if any, that this one inherits from. - ElementPtr getInheritsFrom() const override; - - /// @} public: static const string CATEGORY; }; -/// @class LookInherit -/// A look inheritance element within a Look. -class LookInherit : public Element -{ -public: - LookInherit(ElementPtr parent, const string& name) : - Element(parent, CATEGORY, name) - { - } - virtual ~LookInherit() { } - -public: - static const string CATEGORY; -}; - /// @class MaterialAssign /// A material assignment element within a Look. class MaterialAssign : public GeomElement diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index 625d843acb..7c8fed3844 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -87,28 +87,6 @@ vector Material::getReferencingMaterialAssigns() const return matAssigns; } -void Material::setInheritsFrom(ElementPtr mat) -{ - for (MaterialInheritPtr inherit : getMaterialInherits()) - { - removeMaterialInherit(inherit->getName()); - } - if (mat) - { - addMaterialInherit(mat->getName()); - } -} - -ElementPtr Material::getInheritsFrom() const -{ - vector inherits = getMaterialInherits(); - if (inherits.empty()) - { - return nullptr; - } - return getRoot()->getChildOfType(inherits[0]->getName()); -} - vector Material::getPrimaryShaderParameters(const string& target, const string& type) const { NodeDefPtr nodeDef = getPrimaryShaderNodeDef(target, type); @@ -116,7 +94,7 @@ vector Material::getPrimaryShaderParameters(const string& target, if (nodeDef) { InterfaceElementPtr implement = nodeDef->getImplementation(); - for (ParameterPtr nodeDefParam : nodeDef->getParameters()) + for (ParameterPtr nodeDefParam : nodeDef->getActiveParameters()) { ParameterPtr implementParam = implement ? implement->getParameter(nodeDefParam->getName()) : nullptr; res.push_back(implementParam ? implementParam : nodeDefParam); @@ -132,7 +110,7 @@ vector Material::getPrimaryShaderInputs(const string& target, const st if (nodeDef) { InterfaceElementPtr implement = nodeDef->getImplementation(); - for (InputPtr nodeDefInput : nodeDef->getInputs()) + for (InputPtr nodeDefInput : nodeDef->getActiveInputs()) { InputPtr implementInput = implement ? implement->getInput(nodeDefInput->getName()) : nullptr; res.push_back(implementInput ? implementInput : nodeDefInput); diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index 50ab4a8411..3972880f90 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -42,11 +42,6 @@ using OverridePtr = shared_ptr; /// A shared pointer to a const Override using ConstOverridePtr = shared_ptr; -/// A shared pointer to a MaterialInherit -using MaterialInheritPtr = shared_ptr; -/// A shared pointer to a const MaterialInherit -using ConstMaterialInheritPtr = shared_ptr; - /// @class Material /// A material element within a Document. /// @@ -143,49 +138,6 @@ class Material : public Element const T& value, const string& type = EMPTY_STRING); - /// @} - /// @name MaterialInherit Elements - /// @{ - - /// Add a MaterialInherit to the material. - /// @param name The name of the new MaterialInherit. - /// If no name is specified, then a unique name will automatically be - /// generated. - /// @return A shared pointer to the new MaterialInherit. - MaterialInheritPtr addMaterialInherit(const string& name = EMPTY_STRING) - { - MaterialInheritPtr ptr = addChild(name); - return ptr; - } - - /// Return the MaterialInherit, if any, with the given name. - MaterialInheritPtr getMaterialInherit(const string& name) const - { - return getChildOfType(name); - } - - /// Return a vector of all MaterialInherit elements in the material. - vector getMaterialInherits() const - { - return getChildrenOfType(); - } - - /// Remove the MaterialInherit, if any, with the given name. - void removeMaterialInherit(const string& name) - { - removeChildOfType(name); - } - - /// @} - /// @name Inheritance - /// @{ - - /// Set the material element that this one inherits from. - void setInheritsFrom(ElementPtr mat) override; - - /// Return the material element, if any, that this one inherits from. - ElementPtr getInheritsFrom() const override; - /// @} /// @name NodeDef References /// @{ @@ -587,21 +539,6 @@ class Override : public ValueElement static const string CATEGORY; }; -/// @class MaterialInherit -/// A material inheritance element within a Material. -class MaterialInherit : public Element -{ - public: - MaterialInherit(ElementPtr parent, const string& name) : - Element(parent, CATEGORY, name) - { - } - virtual ~MaterialInherit() { } - - public: - static const string CATEGORY; -}; - template OverridePtr Material::setOverrideValue(const string& name, const T& value, const string& type) diff --git a/source/MaterialXCore/Traversal.cpp b/source/MaterialXCore/Traversal.cpp index 2f8a7e1235..7ea4514ddd 100644 --- a/source/MaterialXCore/Traversal.cpp +++ b/source/MaterialXCore/Traversal.cpp @@ -199,15 +199,16 @@ InheritanceIterator& InheritanceIterator::operator++() if (_elem) { ElementPtr super = _elem->getInheritsFrom(); - - // Check for cycles. - if (_pathElems.count(super)) + if (super && super->getCategory() == _elem->getCategory()) { - throw ExceptionFoundCycle("Encountered cycle at element: " + super->asString()); + // Check for cycles. + if (_pathElems.count(super)) + { + throw ExceptionFoundCycle("Encountered cycle at element: " + super->asString()); + } + _pathElems.insert(super); } - _elem = super; - _pathElems.insert(super); } return *this; } diff --git a/source/MaterialXCore/Util.h b/source/MaterialXCore/Util.h index f0fe6acf55..aaf1611ca2 100644 --- a/source/MaterialXCore/Util.h +++ b/source/MaterialXCore/Util.h @@ -17,7 +17,6 @@ namespace MaterialX extern const string EMPTY_STRING; using ElementPtr = shared_ptr; -using NodeGraphPtr = shared_ptr; /// Return the version of the MaterialX library as a string. string getVersionString(); diff --git a/source/MaterialXTest/Material.cpp b/source/MaterialXTest/Material.cpp index 4b00d1250c..a73621bc1e 100644 --- a/source/MaterialXTest/Material.cpp +++ b/source/MaterialXTest/Material.cpp @@ -14,51 +14,57 @@ TEST_CASE("Material", "[material]") { mx::DocumentPtr doc = mx::createDocument(); - // Create a shader nodedef. - mx::NodeDefPtr shaderDef = doc->addNodeDef("shader1", "surfaceshader", "simpleSrf"); - mx::InputPtr diffColor = shaderDef->setInputValue("diffColor", mx::Color3(1.0f)); - mx::InputPtr specColor = shaderDef->setInputValue("specColor", mx::Color3(0.0f)); - mx::ParameterPtr roughness = shaderDef->setParameterValue("roughness", 0.25f); + // Create a base shader nodedef. + mx::NodeDefPtr simpleSrf = doc->addNodeDef("nd_simpleSrf", "surfaceshader", "simpleSrf"); + mx::InputPtr diffColor = simpleSrf->setInputValue("diffColor", mx::Color3(1.0f)); + mx::InputPtr specColor = simpleSrf->setInputValue("specColor", mx::Color3(0.0f)); + mx::ParameterPtr roughness = simpleSrf->setParameterValue("roughness", 0.25f); roughness->setPublicName("editRoughness"); - REQUIRE(shaderDef->getInputValue("diffColor")->asA() == mx::Color3(1.0f)); - REQUIRE(shaderDef->getInputValue("specColor")->asA() == mx::Color3(0.0f)); - REQUIRE(shaderDef->getParameterValue("roughness")->asA() == 0.25f); + REQUIRE(simpleSrf->getInputValue("diffColor")->asA() == mx::Color3(1.0f)); + REQUIRE(simpleSrf->getInputValue("specColor")->asA() == mx::Color3(0.0f)); + REQUIRE(simpleSrf->getParameterValue("roughness")->asA() == 0.25f); + + // Create an inherited shader nodedef. + mx::NodeDefPtr anisoSrf = doc->addNodeDef("nd_anisoSrf", "surfaceshader", "anisoSrf"); + anisoSrf->setInheritsFrom(simpleSrf); + mx::ParameterPtr anisotropy = anisoSrf->setParameterValue("anisotropy", 0.0f); + REQUIRE(anisoSrf->getInheritsFrom() == simpleSrf); // Create a material. mx::MaterialPtr material = doc->addMaterial(); REQUIRE(material->getPrimaryShaderName().empty()); // Add a shader reference. - mx::ShaderRefPtr shaderRef = material->addShaderRef("shaderRef1", "simpleSrf"); - REQUIRE(shaderDef->getInstantiatingShaderRefs()[0] == shaderRef); - REQUIRE(shaderRef->getNodeDef() == shaderDef); - REQUIRE(material->getPrimaryShaderName() == shaderRef->getNodeString()); - REQUIRE(material->getPrimaryShaderParameters().size() == 1); + mx::ShaderRefPtr refAnisoSrf = material->addShaderRef("sr_anisoSrf", "anisoSrf"); + REQUIRE(anisoSrf->getInstantiatingShaderRefs()[0] == refAnisoSrf); + REQUIRE(refAnisoSrf->getNodeDef() == anisoSrf); + REQUIRE(material->getPrimaryShaderName() == refAnisoSrf->getNodeString()); + REQUIRE(material->getPrimaryShaderParameters().size() == 2); REQUIRE(material->getPrimaryShaderInputs().size() == 2); // Bind a shader input to a value. - mx::BindInputPtr bindInput = shaderRef->addBindInput("specColor"); + mx::BindInputPtr bindInput = refAnisoSrf->addBindInput("specColor"); bindInput->setValue(mx::Color3(0.5f)); REQUIRE(specColor->getBoundValue(material)->asA() == mx::Color3(0.5f)); REQUIRE(specColor->getDefaultValue()->asA() == mx::Color3(0.0f)); // Bind a shader parameter to a value. - mx::BindParamPtr bindParam = shaderRef->addBindParam("roughness"); + mx::BindParamPtr bindParam = refAnisoSrf->addBindParam("roughness"); bindParam->setValue(0.5f); REQUIRE(roughness->getBoundValue(material)->asA() == 0.5f); REQUIRE(roughness->getDefaultValue()->asA() == 0.25f); // Add an invalid shader reference. - mx::ShaderRefPtr shaderRef2 = material->addShaderRef("shaderRef2", "invalidSrf"); + mx::ShaderRefPtr refInvalid = material->addShaderRef("sr_invalidSrf", "invalidSrf"); REQUIRE(!doc->validate()); - material->removeShaderRef("shaderRef2"); + material->removeShaderRef("sr_invalidSrf"); REQUIRE(doc->validate()); // Create an inherited material. mx::MaterialPtr material2 = doc->addMaterial(); material2->setInheritsFrom(material); - REQUIRE(material2->getPrimaryShaderName() == shaderRef->getNodeString()); - REQUIRE(material2->getPrimaryShaderParameters().size() == 1); + REQUIRE(material2->getPrimaryShaderName() == refAnisoSrf->getNodeString()); + REQUIRE(material2->getPrimaryShaderParameters().size() == 2); REQUIRE(material2->getPrimaryShaderInputs().size() == 2); REQUIRE(roughness->getBoundValue(material2)->asA() == 0.5f); @@ -75,10 +81,9 @@ TEST_CASE("Material", "[material]") REQUIRE(material2->getPrimaryShaderInputs().empty()); REQUIRE(roughness->getBoundValue(material2)->asA() == 0.25f); - // Remove shader references. - material->removeShaderRef(shaderRef->getName()); - material->removeShaderRef(shaderRef2->getName()); - REQUIRE(shaderDef->getInstantiatingShaderRefs().empty()); + // Remove shader reference. + material->removeShaderRef(refAnisoSrf->getName()); + REQUIRE(anisoSrf->getInstantiatingShaderRefs().empty()); REQUIRE(material->getPrimaryShaderName().empty()); REQUIRE(material->getPrimaryShaderParameters().empty()); REQUIRE(material->getPrimaryShaderInputs().empty()); @@ -89,11 +94,11 @@ TEST_CASE("Material", "[material]") REQUIRE(roughness->getBoundValue(material)->asA() == 0.5f); // Add an invalid override. - mx::OverridePtr anisoOverride = material->setOverrideValue("anisotropic", 0.1f); - REQUIRE(!anisoOverride->getReceiver()); + mx::OverridePtr invalidOverride = material->setOverrideValue("invalid", 0.1f); + REQUIRE(!invalidOverride->getReceiver()); // Remove overrides. material->removeOverride(roughOverride->getName()); - material->removeOverride(anisoOverride->getName()); + material->removeOverride(invalidOverride->getName()); REQUIRE(roughness->getBoundValue(material)->asA() == 0.25f); } diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index 843b1d72f3..2b27db0879 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -55,6 +55,13 @@ void bindPyElement(py::module& mod) .def("setTarget", &mx::Element::setTarget) .def("hasTarget", &mx::Element::hasTarget) .def("getTarget", &mx::Element::getTarget) + .def("setInheritString", &mx::Element::setInheritString) + .def("hasInheritString", &mx::Element::hasInheritString) + .def("getInheritString", &mx::Element::getInheritString) + .def("setInheritsFrom", &mx::Element::setInheritsFrom) + .def("getInheritsFrom", &mx::Element::getInheritsFrom) + .def("hasInheritedBase", &mx::Element::hasInheritedBase) + .def("hasInheritanceCycle", &mx::Element::hasInheritanceCycle) .def("addChildOfCategory", &mx::Element::addChildOfCategory) .def("_getChild", &mx::Element::getChild) .def("getChildren", &mx::Element::getChildren) @@ -70,9 +77,6 @@ void bindPyElement(py::module& mod) .def("getParent", static_cast(&mx::Element::getParent)) .def("getRoot", static_cast(&mx::Element::getRoot)) .def("getDocument", static_cast(&mx::Element::getDocument)) - .def("setInheritsFrom", &mx::Element::setInheritsFrom) - .def("getInheritsFrom", &mx::Element::getInheritsFrom) - .def("hasInheritanceCycle", &mx::Element::hasInheritanceCycle) .def("traverseTree", &mx::Element::traverseTree) .def("traverseGraph", &mx::Element::traverseGraph, py::arg("material") = nullptr) @@ -112,7 +116,6 @@ void bindPyElement(py::module& mod) BIND_ELEMENT_FUNC_INSTANCE(Look) BIND_ELEMENT_FUNC_INSTANCE(Material) BIND_ELEMENT_FUNC_INSTANCE(MaterialAssign) - BIND_ELEMENT_FUNC_INSTANCE(MaterialInherit) BIND_ELEMENT_FUNC_INSTANCE(Node) BIND_ELEMENT_FUNC_INSTANCE(NodeDef) BIND_ELEMENT_FUNC_INSTANCE(NodeGraph) diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index 1766db43dd..4cc111033b 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -43,18 +43,26 @@ void bindPyInterface(py::module& mod) .def("getParameters", &mx::InterfaceElement::getParameters) .def("getParameterCount", &mx::InterfaceElement::getParameterCount) .def("removeParameter", &mx::InterfaceElement::removeParameter) + .def("getActiveParameter", &mx::InterfaceElement::getActiveParameter) + .def("getActiveParameters", &mx::InterfaceElement::getActiveParameters) .def("addInput", &mx::InterfaceElement::addInput, py::arg("name"), py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getInput", &mx::InterfaceElement::getInput) .def("getInputs", &mx::InterfaceElement::getInputs) .def("getInputCount", &mx::InterfaceElement::getInputCount) .def("removeInput", &mx::InterfaceElement::removeInput) + .def("getActiveInput", &mx::InterfaceElement::getActiveInput) + .def("getActiveInputs", &mx::InterfaceElement::getActiveInputs) .def("addOutput", &mx::InterfaceElement::addOutput, py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getOutput", &mx::InterfaceElement::getOutput) .def("getOutputs", &mx::InterfaceElement::getOutputs) - .def("removeOutput", &mx::InterfaceElement::removeOutput) .def("getOutputCount", &mx::InterfaceElement::getOutputCount) + .def("removeOutput", &mx::InterfaceElement::removeOutput) + .def("getActiveOutput", &mx::InterfaceElement::getActiveOutput) + .def("getActiveOutputs", &mx::InterfaceElement::getActiveOutputs) + .def("getActiveValueElement", &mx::InterfaceElement::getActiveValueElement) + .def("getActiveValueElements", &mx::InterfaceElement::getActiveValueElements) .def("_getParameterValue", &mx::InterfaceElement::getParameterValue) .def("_getInputValue", &mx::InterfaceElement::getInputValue) .def("getDeclaration", &mx::InterfaceElement::getDeclaration, diff --git a/source/PyMaterialX/PyLook.cpp b/source/PyMaterialX/PyLook.cpp index 1823402b6d..b0a1671d7e 100644 --- a/source/PyMaterialX/PyLook.cpp +++ b/source/PyMaterialX/PyLook.cpp @@ -16,11 +16,6 @@ namespace mx = MaterialX; void bindPyLook(py::module& mod) { py::class_(mod, "Look") - .def("addLookInherit", &mx::Look::addLookInherit, - py::arg("name") = mx::EMPTY_STRING) - .def("getLookInherit", &mx::Look::getLookInherit) - .def("getLookInherits", &mx::Look::getLookInherits) - .def("removeLookInherit", &mx::Look::removeLookInherit) .def("addMaterialAssign", &mx::Look::addMaterialAssign, py::arg("name") = mx::EMPTY_STRING, py::arg("material") = mx::EMPTY_STRING) .def("getMaterialAssign", &mx::Look::getMaterialAssign) @@ -46,9 +41,6 @@ void bindPyLook(py::module& mod) .def("removeVisibility", &mx::Look::removeVisibility) .def_readonly_static("CATEGORY", &mx::Look::CATEGORY); - py::class_(mod, "LookInherit") - .def_readonly_static("CATEGORY", &mx::Look::CATEGORY); - py::class_(mod, "MaterialAssign") .def("setMaterial", &mx::MaterialAssign::setMaterial) .def("hasMaterial", &mx::MaterialAssign::hasMaterial) diff --git a/source/PyMaterialX/PyMaterial.cpp b/source/PyMaterialX/PyMaterial.cpp index edf10518df..6419b93dc3 100644 --- a/source/PyMaterialX/PyMaterial.cpp +++ b/source/PyMaterialX/PyMaterial.cpp @@ -29,11 +29,6 @@ void bindPyMaterial(py::module& mod) .def("getOverrides", &mx::Material::getOverrides) .def("getActiveOverrides", &mx::Material::getActiveOverrides) .def("removeOverride", &mx::Material::removeOverride) - .def("addMaterialInherit", &mx::Material::addMaterialInherit, - py::arg("name") = mx::EMPTY_STRING) - .def("getMaterialInherit", &mx::Material::getMaterialInherit) - .def("getMaterialInherits", &mx::Material::getMaterialInherits) - .def("removeMaterialInherit", &mx::Material::removeMaterialInherit) .def("getShaderNodeDefs", &mx::Material::getShaderNodeDefs, py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) .def("getReferencingMaterialAssigns", &mx::Material::getReferencingMaterialAssigns) @@ -97,7 +92,4 @@ void bindPyMaterial(py::module& mod) py::class_(mod, "Override") .def("getReceiver", &mx::Override::getReceiver) .def_readonly_static("CATEGORY", &mx::Override::CATEGORY); - - py::class_(mod, "MaterialInherit") - .def_readonly_static("CATEGORY", &mx::MaterialInherit::CATEGORY); } From 6050b1a2dba205d66afe357a223a1d4ef2773e32 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 14 May 2018 15:15:24 -0700 Subject: [PATCH 02/27] Override updates for MaterialX v1.36 - Remove support for Override elements and public names. - In legacy documents, convert overrides of top-level parameters and inputs to BindParameter and BindInput elements. --- source/MaterialXCore/Document.cpp | 73 ++++++++++---------------- source/MaterialXCore/Document.h | 11 ---- source/MaterialXCore/Element.cpp | 10 ++-- source/MaterialXCore/Element.h | 36 +++---------- source/MaterialXCore/Interface.cpp | 14 ----- source/MaterialXCore/Material.cpp | 20 ------- source/MaterialXCore/Material.h | 84 ------------------------------ source/MaterialXTest/Material.cpp | 15 ------ source/PyMaterialX/PyDocument.cpp | 2 - source/PyMaterialX/PyElement.cpp | 4 -- source/PyMaterialX/PyMaterial.cpp | 24 --------- 11 files changed, 38 insertions(+), 255 deletions(-) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index d8aed778ce..576911c1cc 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -69,7 +69,6 @@ class Document::Cache { // Clear the existing cache. portElementMap.clear(); - publicElementMap.clear(); nodeDefMap.clear(); implementationMap.clear(); @@ -88,12 +87,6 @@ class Document::Cache portElem->getNodeName(), portElem)); } - if (valueElem && valueElem->hasPublicName()) - { - publicElementMap.insert(std::pair( - valueElem->getPublicName(), - valueElem)); - } if (nodeDef && nodeDef->hasNodeString()) { nodeDefMap.insert(std::pair( @@ -123,7 +116,6 @@ class Document::Cache std::mutex mutex; bool valid; std::unordered_multimap portElementMap; - std::unordered_multimap publicElementMap; std::unordered_multimap nodeDefMap; std::unordered_multimap implementationMap; }; @@ -247,38 +239,6 @@ vector Document::getMatchingImplementations(const string& n return implementations; } -ElementPtr Document::getPublicElement(const string& publicName) const -{ - // Refresh the cache. - _cache->refresh(); - - // Return any element with the given public name. - auto it = _cache->publicElementMap.find(publicName); - if (it != _cache->publicElementMap.end()) - { - return it->second; - } - - return ElementPtr(); -} - -vector Document::getPublicElements(const string& publicName) const -{ - // Refresh the cache. - _cache->refresh(); - - // Find all elements with the given public name. - vector publicElements; - auto keyRange = _cache->publicElementMap.equal_range(publicName); - for (auto it = keyRange.first; it != keyRange.second; ++it) - { - publicElements.push_back(it->second); - } - - // Return the matches. - return publicElements; -} - void Document::generateRequireString() { std::set requireSet; @@ -292,10 +252,6 @@ void Document::generateRequireString() requireSet.insert(REQUIRE_STRING_MATNODEGRAPH); } } - else if (elem->isA()) - { - requireSet.insert(REQUIRE_STRING_OVERRIDE); - } } string requireStr; @@ -533,7 +489,9 @@ void Document::upgradeVersion() { for (ElementPtr elem : traverseTree()) { - if (elem->isA() || elem->isA()) + MaterialPtr material = elem->asA(); + LookPtr look = elem->asA(); + if (material || look) { vector origChildren = elem->getChildren(); for (ElementPtr child : origChildren) @@ -548,6 +506,31 @@ void Document::upgradeVersion() elem->setInheritString(child->getAttribute("look")); elem->removeChild(child->getName()); } + else if (material && child->getCategory() == "override") + { + for (ShaderRefPtr shaderRef : material->getShaderRefs()) + { + NodeDefPtr nodeDef = shaderRef->getNodeDef(); + for (ValueElementPtr valueElem : nodeDef->getActiveValueElements()) + { + if (valueElem->getAttribute("publicname") == child->getName() && + !shaderRef->getChild(child->getName())) + { + if (valueElem->isA()) + { + BindParamPtr bindParam = shaderRef->addBindParam(valueElem->getName(), valueElem->getType()); + bindParam->setValueString(child->getAttribute("value")); + } + else if (valueElem->isA()) + { + BindInputPtr bindInput = shaderRef->addBindInput(valueElem->getName(), valueElem->getType()); + bindInput->setValueString(child->getAttribute("value")); + } + } + } + } + elem->removeChild(child->getName()); + } } } } diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index f5f1112118..c9336acb5d 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -406,17 +406,6 @@ class Document : public Element /// Implementation element or NodeGraph element. vector getMatchingImplementations(const string& nodeDef) const; - /// @} - /// @name Public Elements - /// @{ - - /// Return any element with the given public name. If multiple matches - /// exist, then an arbitrary selection is made. - ElementPtr getPublicElement(const string& publicName) const; - - /// Return a vector of all elements with the given public name. - vector getPublicElements(const string& publicName) const; - /// @} /// @name Require String /// @{ diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 01992dbbc3..369f915c89 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -9,8 +9,6 @@ #include #include -#include - namespace MaterialX { @@ -22,7 +20,6 @@ const string Element::COLOR_SPACE_ATTRIBUTE = "colorspace"; const string Element::INHERIT_ATTRIBUTE = "inherit"; const string Element::TARGET_ATTRIBUTE = "target"; const string ValueElement::VALUE_ATTRIBUTE = "value"; -const string ValueElement::PUBLIC_NAME_ATTRIBUTE = "publicname"; const string ValueElement::INTERFACE_NAME_ATTRIBUTE = "interfacename"; const string ValueElement::IMPLEMENTATION_NAME_ATTRIBUTE = "implname"; @@ -291,11 +288,11 @@ ConstElementPtr Element::getRoot() const return root; } -bool Element::hasInheritedBase(ConstElementPtr elem) const +bool Element::hasInheritedBase(ConstElementPtr base) const { - for (ConstElementPtr iterElem : traverseInheritance()) + for (ConstElementPtr elem : traverseInheritance()) { - if (iterElem == elem) + if (elem == base) { return true; } @@ -619,7 +616,6 @@ INSTANTIATE_CONCRETE_SUBCLASS(Member, "member") INSTANTIATE_CONCRETE_SUBCLASS(Node, "node") INSTANTIATE_CONCRETE_SUBCLASS(NodeDef, "nodedef") INSTANTIATE_CONCRETE_SUBCLASS(NodeGraph, "nodegraph") -INSTANTIATE_CONCRETE_SUBCLASS(Override, "override") INSTANTIATE_CONCRETE_SUBCLASS(Output, "output") INSTANTIATE_CONCRETE_SUBCLASS(Parameter, "parameter") INSTANTIATE_CONCRETE_SUBCLASS(Property, "property") diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 63afceadd9..6456010476 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -298,7 +298,7 @@ class Element : public std::enable_shared_from_this /// Return true if this element has the given element as an inherited base, /// taking the full inheritance chain into account. - bool hasInheritedBase(ConstElementPtr elem) const; + bool hasInheritedBase(ConstElementPtr base) const; /// Return true if the inheritance chain for this element contains a cycle. bool hasInheritanceCycle() const; @@ -543,8 +543,8 @@ class Element : public std::enable_shared_from_this /// Traverse the dataflow graph from the given element to each of its /// upstream sources in depth-first order, using pre-order visitation. - /// @param material An optional material element, whose data bindings and - /// overrides will be applied to the traversal. + /// @param material An optional material element, whose data bindings will + /// be applied to the traversal. /// @throws ExceptionFoundCycle if a cycle is encountered. /// @return A GraphIterator object. /// @details Example usage with an implicit iterator: @@ -570,8 +570,8 @@ class Element : public std::enable_shared_from_this /// Return the Edge with the given index that lies directly upstream from /// this element in the dataflow graph. - /// @param material An optional material element, whose data bindings and - /// overrides will be applied to the query. + /// @param material An optional material element, whose data bindings will + /// be applied to the query. /// @param index An optional index of the edge to be returned, where the /// valid index range may be determined with getUpstreamEdgeCount. /// @return The upstream Edge, if valid, or an empty Edge object. @@ -586,8 +586,8 @@ class Element : public std::enable_shared_from_this /// Return the Element with the given index that lies directly upstream /// from this one in the dataflow graph. - /// @param material An optional material element, whose data bindings and - /// overrides will be applied to the query. + /// @param material An optional material element, whose data bindings will + /// be applied to the query. /// @param index An optional index of the element to be returned, where the /// valid index range may be determined with getUpstreamEdgeCount. /// @return The upstream Element, if valid, or an empty ElementPtr. @@ -826,28 +826,6 @@ class ValueElement : public TypedElement /// will be created at this scope and applied to the return value. string getResolvedValueString(StringResolverPtr resolver = nullptr) const; - /// @} - /// @name Public Names - /// @{ - - /// Set the public name of an element. - void setPublicName(const string& name) - { - setAttribute(PUBLIC_NAME_ATTRIBUTE, name); - } - - /// Return true if the given element has a public name. - bool hasPublicName() const - { - return hasAttribute(PUBLIC_NAME_ATTRIBUTE); - } - - /// Return the public name of an element. - const string& getPublicName() const - { - return getAttribute(PUBLIC_NAME_ATTRIBUTE); - } - /// @} /// @name Interface Names /// @{ diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 9862b3414f..d969f35b98 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -103,13 +103,6 @@ Edge Parameter::getUpstreamEdge(ConstMaterialPtr material, size_t index) const } } } - - // Apply Override elements to the Parameter. - OverridePtr override = material->getOverride(getPublicName()); - if (override) - { - return Edge(getSelfNonConst(), nullptr, override); - } } return NULL_EDGE; @@ -155,13 +148,6 @@ Edge Input::getUpstreamEdge(ConstMaterialPtr material, size_t index) const } } } - - // Apply Override elements to the Input. - OverridePtr override = material->getOverride(getPublicName()); - if (override) - { - return Edge(getSelfNonConst(), nullptr, override); - } } return NULL_EDGE; diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index 7c8fed3844..1410e178dd 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -41,17 +41,6 @@ vector Material::getActiveShaderRefs() const return activeShaderRefs; } -vector Material::getActiveOverrides() const -{ - vector activeOverrides; - for (ConstElementPtr elem : traverseInheritance()) - { - vector overrides = elem->asA()->getOverrides(); - activeOverrides.insert(activeOverrides.end(), overrides.begin(), overrides.end()); - } - return activeOverrides; -} - vector Material::getShaderNodeDefs(const string& target, const string& type) const { vector nodeDefs; @@ -237,13 +226,4 @@ Edge ShaderRef::getUpstreamEdge(ConstMaterialPtr material, size_t index) const return NULL_EDGE; } -// -// Override methods -// - -ConstElementPtr Override::getReceiver() const -{ - return getDocument()->getPublicElement(getName()); -} - } // namespace MaterialX diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index 3972880f90..213f7b4dac 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -37,11 +37,6 @@ using BindInputPtr = shared_ptr; /// A shared pointer to a const BindInput using ConstBindInputPtr = shared_ptr; -/// A shared pointer to an Override -using OverridePtr = shared_ptr; -/// A shared pointer to a const Override -using ConstOverridePtr = shared_ptr; - /// @class Material /// A material element within a Document. /// @@ -96,48 +91,6 @@ class Material : public Element removeChildOfType(name); } - /// @} - /// @name Override Elements - /// @{ - - /// Add a Override to the material. - /// @param name The name of the new Override. - /// If no name is specified, then a unique name will automatically be - /// generated. - /// @return A shared pointer to the new Override. - OverridePtr addOverride(const string& name) - { - return addChild(name); - } - - /// Return the Override, if any, with the given name. - OverridePtr getOverride(const string& name) const - { - return getChildOfType(name); - } - - /// Return a vector of all Override elements that belong to this material, - /// taking material inheritance into account. - vector getActiveOverrides() const; - - /// Return a vector of all Override elements - vector getOverrides() const - { - return getChildrenOfType(); - } - - /// Remove the Override, if any, with the given name. - void removeOverride(const string& name) - { - removeChildOfType(name); - } - - /// Set the value of an override by its name, creating a child element - /// to hold the override if needed. - template OverridePtr setOverrideValue(const string& name, - const T& value, - const string& type = EMPTY_STRING); - /// @} /// @name NodeDef References /// @{ @@ -513,43 +466,6 @@ class ShaderRef : public Element static const string NODE_DEF_ATTRIBUTE; }; -/// @class Override -/// An override element within a Material. -/// -/// An Override modifies the uniform value of a public Parameter or Input -/// within the scope of a Material. -class Override : public ValueElement -{ - public: - Override(ElementPtr parent, const string& name) : - ValueElement(parent, CATEGORY, name) - { - } - virtual ~Override() { } - - /// @name Connections - /// @{ - - /// Return the element, if any, that is modified by this override. - ConstElementPtr getReceiver() const; - - /// @} - - public: - static const string CATEGORY; -}; - -template OverridePtr Material::setOverrideValue(const string& name, - const T& value, - const string& type) -{ - OverridePtr override = getChildOfType(name); - if (!override) - override = addChild(name); - override->setValue(value, type); - return override; -} - } // namespace MaterialX #endif diff --git a/source/MaterialXTest/Material.cpp b/source/MaterialXTest/Material.cpp index a73621bc1e..92c87787bc 100644 --- a/source/MaterialXTest/Material.cpp +++ b/source/MaterialXTest/Material.cpp @@ -19,7 +19,6 @@ TEST_CASE("Material", "[material]") mx::InputPtr diffColor = simpleSrf->setInputValue("diffColor", mx::Color3(1.0f)); mx::InputPtr specColor = simpleSrf->setInputValue("specColor", mx::Color3(0.0f)); mx::ParameterPtr roughness = simpleSrf->setParameterValue("roughness", 0.25f); - roughness->setPublicName("editRoughness"); REQUIRE(simpleSrf->getInputValue("diffColor")->asA() == mx::Color3(1.0f)); REQUIRE(simpleSrf->getInputValue("specColor")->asA() == mx::Color3(0.0f)); REQUIRE(simpleSrf->getParameterValue("roughness")->asA() == 0.25f); @@ -87,18 +86,4 @@ TEST_CASE("Material", "[material]") REQUIRE(material->getPrimaryShaderName().empty()); REQUIRE(material->getPrimaryShaderParameters().empty()); REQUIRE(material->getPrimaryShaderInputs().empty()); - - // Add a valid override. - mx::OverridePtr roughOverride = material->setOverrideValue("editRoughness", 0.5f); - REQUIRE(roughOverride->getReceiver() == roughness); - REQUIRE(roughness->getBoundValue(material)->asA() == 0.5f); - - // Add an invalid override. - mx::OverridePtr invalidOverride = material->setOverrideValue("invalid", 0.1f); - REQUIRE(!invalidOverride->getReceiver()); - - // Remove overrides. - material->removeOverride(roughOverride->getName()); - material->removeOverride(invalidOverride->getName()); - REQUIRE(roughness->getBoundValue(material)->asA() == 0.25f); } diff --git a/source/PyMaterialX/PyDocument.cpp b/source/PyMaterialX/PyDocument.cpp index f57936d1f2..86d6a64922 100644 --- a/source/PyMaterialX/PyDocument.cpp +++ b/source/PyMaterialX/PyDocument.cpp @@ -71,8 +71,6 @@ void bindPyDocument(py::module& mod) .def("getImplementation", &mx::Document::getImplementation) .def("getImplementations", &mx::Document::getImplementations) .def("removeImplementation", &mx::Document::removeImplementation) - .def("getPublicElement", &mx::Document::getPublicElement) - .def("getPublicElements", &mx::Document::getPublicElements) .def("setRequireString", &mx::Document::setRequireString) .def("hasRequireString", &mx::Document::hasRequireString) .def("getRequireString", &mx::Document::getRequireString) diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index 2b27db0879..16c858a0ee 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -119,7 +119,6 @@ void bindPyElement(py::module& mod) BIND_ELEMENT_FUNC_INSTANCE(Node) BIND_ELEMENT_FUNC_INSTANCE(NodeDef) BIND_ELEMENT_FUNC_INSTANCE(NodeGraph) - BIND_ELEMENT_FUNC_INSTANCE(Override) BIND_ELEMENT_FUNC_INSTANCE(Parameter) BIND_ELEMENT_FUNC_INSTANCE(Property) BIND_ELEMENT_FUNC_INSTANCE(PropertySet) @@ -139,9 +138,6 @@ void bindPyElement(py::module& mod) .def("getValueString", &mx::ValueElement::getValueString) .def("getResolvedValueString", &mx::ValueElement::getResolvedValueString, py::arg("resolver") = nullptr) - .def("setPublicName", &mx::ValueElement::setPublicName) - .def("hasPublicName", &mx::ValueElement::hasPublicName) - .def("getPublicName", &mx::ValueElement::getPublicName) .def("setInterfaceName", &mx::ValueElement::setInterfaceName) .def("hasInterfaceName", &mx::ValueElement::hasInterfaceName) .def("getInterfaceName", &mx::ValueElement::getInterfaceName) diff --git a/source/PyMaterialX/PyMaterial.cpp b/source/PyMaterialX/PyMaterial.cpp index 6419b93dc3..471b88bfa6 100644 --- a/source/PyMaterialX/PyMaterial.cpp +++ b/source/PyMaterialX/PyMaterial.cpp @@ -12,9 +12,6 @@ namespace py = pybind11; namespace mx = MaterialX; -#define BIND_MATERIAL_FUNC_INSTANCE(NAME, T) \ -.def("_setOverrideValue" #NAME, &mx::Material::setOverrideValue, py::arg("name"), py::arg("value"), py::arg("type") = mx::EMPTY_STRING) - void bindPyMaterial(py::module& mod) { py::class_(mod, "Material") @@ -24,11 +21,6 @@ void bindPyMaterial(py::module& mod) .def("getShaderRefs", &mx::Material::getShaderRefs) .def("getActiveShaderRefs", &mx::Material::getActiveShaderRefs) .def("removeShaderRef", &mx::Material::removeShaderRef) - .def("_addOverride", &mx::Material::addOverride) - .def("getOverride", &mx::Material::getOverride) - .def("getOverrides", &mx::Material::getOverrides) - .def("getActiveOverrides", &mx::Material::getActiveOverrides) - .def("removeOverride", &mx::Material::removeOverride) .def("getShaderNodeDefs", &mx::Material::getShaderNodeDefs, py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) .def("getReferencingMaterialAssigns", &mx::Material::getReferencingMaterialAssigns) @@ -42,18 +34,6 @@ void bindPyMaterial(py::module& mod) py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) .def("getBoundGeomStrings", &mx::Material::getBoundGeomStrings) .def("getBoundGeomCollections", &mx::Material::getBoundGeomCollections) - BIND_MATERIAL_FUNC_INSTANCE(integer, int) - BIND_MATERIAL_FUNC_INSTANCE(boolean, bool) - BIND_MATERIAL_FUNC_INSTANCE(float, float) - BIND_MATERIAL_FUNC_INSTANCE(color2, mx::Color2) - BIND_MATERIAL_FUNC_INSTANCE(color3, mx::Color3) - BIND_MATERIAL_FUNC_INSTANCE(color4, mx::Color4) - BIND_MATERIAL_FUNC_INSTANCE(vector2, mx::Vector2) - BIND_MATERIAL_FUNC_INSTANCE(vector3, mx::Vector3) - BIND_MATERIAL_FUNC_INSTANCE(vector4, mx::Vector4) - BIND_MATERIAL_FUNC_INSTANCE(matrix33, mx::Matrix33) - BIND_MATERIAL_FUNC_INSTANCE(matrix44, mx::Matrix44) - BIND_MATERIAL_FUNC_INSTANCE(string, std::string) .def_readonly_static("CATEGORY", &mx::Material::CATEGORY); py::class_(mod, "BindParam") @@ -88,8 +68,4 @@ void bindPyMaterial(py::module& mod) .def("removeBindInput", &mx::ShaderRef::removeBindInput) .def("getReferencedOutputs", &mx::ShaderRef::getReferencedOutputs) .def_readonly_static("CATEGORY", &mx::ShaderRef::CATEGORY); - - py::class_(mod, "Override") - .def("getReceiver", &mx::Override::getReceiver) - .def_readonly_static("CATEGORY", &mx::Override::CATEGORY); } From a0fd0cfd67f41d00f81c4861984a5ca5477a87e5 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 14 May 2018 17:28:24 -0700 Subject: [PATCH 03/27] Initial Variant and VariantSet classes for v1.36 --- python/MaterialXTest/main.py | 6 ++ source/MaterialXCore/Document.h | 33 +++++++++++ source/MaterialXCore/Element.cpp | 2 + source/MaterialXCore/Variant.h | 95 ++++++++++++++++++++++++++++++ source/MaterialXTest/Look.cpp | 6 ++ source/PyMaterialX/PyDocument.cpp | 5 ++ source/PyMaterialX/PyMaterialX.cpp | 2 + source/PyMaterialX/PyVariant.cpp | 25 ++++++++ 8 files changed, 174 insertions(+) create mode 100644 source/MaterialXCore/Variant.h create mode 100644 source/PyMaterialX/PyVariant.cpp diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index 41fd4cf342..b753d1056c 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -299,6 +299,12 @@ def test_BuildDocument(self): propertySetAssign.setGeom('/robot1') self.assertTrue(propertySetAssign.getGeom() == '/robot1') + # Create a variant set. + variantSet = doc.addVariantSet() + original = variantSet.addVariant("original") + damaged = variantSet.addVariant("damaged") + self.assertTrue(len(variantSet.getVariants()) == 2) + # Generate and verify require string. doc.generateRequireString() self.assertTrue('matnodegraph' in doc.getRequireString()) diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index c9336acb5d..f4c15ffa2b 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace MaterialX { @@ -369,6 +370,38 @@ class Document : public Element removeChildOfType(name); } + /// @} + /// @name VariantSet Elements + /// @{ + + /// Add a VariantSet to the document. + /// @param name The name of the new VariantSet. + /// If no name is specified, then a unique name will automatically be + /// generated. + /// @return A shared pointer to the new VariantSet. + VariantSetPtr addVariantSet(const string& name = EMPTY_STRING) + { + return addChild(name); + } + + /// Return the VariantSet, if any, with the given name. + VariantSetPtr getVariantSet(const string& name) const + { + return getChildOfType(name); + } + + /// Return a vector of all VariantSet elements in the document. + vector getVariantSets() const + { + return getChildrenOfType(); + } + + /// Remove the VariantSet, if any, with the given name. + void removeVariantSet(const string& name) + { + removeChildOfType(name); + } + /// @} /// @name Implementation Elements /// @{ diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 369f915c89..98999ac9ab 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -624,6 +624,8 @@ INSTANTIATE_CONCRETE_SUBCLASS(PropertySet, "propertyset") INSTANTIATE_CONCRETE_SUBCLASS(PropertySetAssign, "propertysetassign") INSTANTIATE_CONCRETE_SUBCLASS(ShaderRef, "shaderref") INSTANTIATE_CONCRETE_SUBCLASS(TypeDef, "typedef") +INSTANTIATE_CONCRETE_SUBCLASS(Variant, "variant") +INSTANTIATE_CONCRETE_SUBCLASS(VariantSet, "variantset") INSTANTIATE_CONCRETE_SUBCLASS(Visibility, "visibility") } // namespace MaterialX diff --git a/source/MaterialXCore/Variant.h b/source/MaterialXCore/Variant.h new file mode 100644 index 0000000000..c5239b7da0 --- /dev/null +++ b/source/MaterialXCore/Variant.h @@ -0,0 +1,95 @@ +// +// TM & (c) 2017 Lucasfilm Entertainment Company Ltd. and Lucasfilm Ltd. +// All rights reserved. See LICENSE.txt for license. +// + +#ifndef MATERIALX_VARIANT_H +#define MATERIALX_VARIANT_H + +/// @file +/// Variant element subclasses + +#include + +#include + +namespace MaterialX +{ + +/// A shared pointer to a Variant +using VariantPtr = shared_ptr; +/// A shared pointer to a const Variant +using ConstVariantPtr = shared_ptr; + +/// A shared pointer to a VariantSet +using VariantSetPtr = shared_ptr; +/// A shared pointer to a const VariantSet +using ConstVariantSetPtr = shared_ptr; + +/// @class Variant +/// A variant element within a VariantSet +class Variant : public InterfaceElement +{ + public: + Variant(ElementPtr parent, const string& name) : + InterfaceElement(parent, CATEGORY, name) + { + } + virtual ~Variant() { } + +public: + static const string CATEGORY; +}; + +/// @class VariantSet +/// A variant set element within a Document. +class VariantSet : public Element +{ + public: + VariantSet(ElementPtr parent, const string& name) : + Element(parent, CATEGORY, name) + { + } + virtual ~VariantSet() { } + + /// @} + /// @name Varient Elements + /// @{ + + /// Add a Variant to the variant set. + /// @param name The name of the new Variant. + /// If no name is specified, then a unique name will automatically be + /// generated. + /// @return A shared pointer to the new Variant. + VariantPtr addVariant(const string& name = EMPTY_STRING) + { + return addChild(name); + } + + /// Return the Variant, if any, with the given name. + VariantPtr getVariant(const string& name) const + { + return getChildOfType(name); + } + + /// Return a vector of all Variant elements in the look. + vector getVariants() const + { + return getChildrenOfType(); + } + + /// Remove the Variant, if any, with the given name. + void removeVariant(const string& name) + { + removeChildOfType(name); + } + + /// @} + + public: + static const string CATEGORY; +}; + +} // namespace MaterialX + +#endif diff --git a/source/MaterialXTest/Look.cpp b/source/MaterialXTest/Look.cpp index 09a492a561..2f322ca475 100644 --- a/source/MaterialXTest/Look.cpp +++ b/source/MaterialXTest/Look.cpp @@ -52,6 +52,12 @@ TEST_CASE("Look", "[look]") mx::PropertySetAssignPtr propertySetAssign = look->addPropertySetAssign(propertySet->getName()); propertySetAssign->setGeom("/robot1"); REQUIRE(propertySetAssign->getGeom() == "/robot1"); + + // Create a variant set. + mx::VariantSetPtr variantSet = doc->addVariantSet("damageVars"); + mx::VariantPtr original = variantSet->addVariant("original"); + mx::VariantPtr damaged = variantSet->addVariant("damaged"); + REQUIRE(variantSet->getVariants().size() == 2); // Create a visibility element. mx::VisibilityPtr visibility = look->addVisibility(); diff --git a/source/PyMaterialX/PyDocument.cpp b/source/PyMaterialX/PyDocument.cpp index 86d6a64922..6c33ca4873 100644 --- a/source/PyMaterialX/PyDocument.cpp +++ b/source/PyMaterialX/PyDocument.cpp @@ -66,6 +66,11 @@ void bindPyDocument(py::module& mod) .def("getPropertySet", &mx::Document::getPropertySet) .def("getPropertySets", &mx::Document::getPropertySets) .def("removePropertySet", &mx::Document::removePropertySet) + .def("addVariantSet", &mx::Document::addVariantSet, + py::arg("name") = mx::EMPTY_STRING) + .def("getVariantSet", &mx::Document::getVariantSet) + .def("getVariantSets", &mx::Document::getVariantSets) + .def("removeVariantSet", &mx::Document::removeVariantSet) .def("addImplementation", &mx::Document::addImplementation, py::arg("name") = mx::EMPTY_STRING) .def("getImplementation", &mx::Document::getImplementation) diff --git a/source/PyMaterialX/PyMaterialX.cpp b/source/PyMaterialX/PyMaterialX.cpp index 82640e300e..3556c86941 100644 --- a/source/PyMaterialX/PyMaterialX.cpp +++ b/source/PyMaterialX/PyMaterialX.cpp @@ -21,6 +21,7 @@ void bindPyTraversal(py::module& mod); void bindPyTypes(py::module& mod); void bindPyUtil(py::module& mod); void bindPyValue(py::module& mod); +void bindPyVariant(py::module& mod); void bindPyXmlIo(py::module& mod); PYBIND11_MODULE(PyMaterialX, mod) @@ -37,6 +38,7 @@ PYBIND11_MODULE(PyMaterialX, mod) bindPyDefinition(mod); bindPyNode(mod); bindPyMaterial(mod); + bindPyVariant(mod); bindPyDocument(mod); bindPyTypes(mod); bindPyUtil(mod); diff --git a/source/PyMaterialX/PyVariant.cpp b/source/PyMaterialX/PyVariant.cpp new file mode 100644 index 0000000000..307f6e05d8 --- /dev/null +++ b/source/PyMaterialX/PyVariant.cpp @@ -0,0 +1,25 @@ +// +// TM & (c) 2017 Lucasfilm Entertainment Company Ltd. and Lucasfilm Ltd. +// All rights reserved. See LICENSE.txt for license. +// + +#include + +#include + +namespace py = pybind11; +namespace mx = MaterialX; + +void bindPyVariant(py::module& mod) +{ + py::class_(mod, "Variant") + .def_readonly_static("CATEGORY", &mx::Variant::CATEGORY); + + py::class_(mod, "VariantSet") + .def("addVariant", &mx::VariantSet::addVariant, + py::arg("name") = mx::EMPTY_STRING) + .def("getVariant", &mx::VariantSet::getVariant) + .def("getVariants", &mx::VariantSet::getVariants) + .def("removeVariant", &mx::VariantSet::removeVariant) + .def_readonly_static("CATEGORY", &mx::VariantSet::CATEGORY); +} From c83c5382d535ac96c2f5aff4fd640b6b0cd42305 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Tue, 15 May 2018 17:49:55 -0700 Subject: [PATCH 04/27] Collection and Token updates for MaterialX v1.36 - Replace CollectionAdd and CollectionRemove elements with Collection attributes. - Add the Token element class, and replace the legacy use of GeomAttr elements in string substitutions with tokens. --- python/MaterialXTest/main.py | 6 +- source/MaterialXCore/Document.cpp | 68 ++++++----- source/MaterialXCore/Document.h | 2 - source/MaterialXCore/Element.cpp | 9 +- source/MaterialXCore/Element.h | 25 ++++ source/MaterialXCore/Geom.cpp | 4 + source/MaterialXCore/Geom.h | 179 +++++++++++++++++------------ source/MaterialXCore/Interface.cpp | 24 ++++ source/MaterialXCore/Interface.h | 75 ++++++++++-- source/MaterialXTest/Geom.cpp | 21 ++-- source/MaterialXTest/Look.cpp | 6 +- source/PyMaterialX/PyElement.cpp | 8 +- source/PyMaterialX/PyGeom.cpp | 35 +++--- source/PyMaterialX/PyInterface.cpp | 15 ++- 14 files changed, 320 insertions(+), 157 deletions(-) diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index b753d1056c..9368086930 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -277,10 +277,8 @@ def test_BuildDocument(self): # Bind the material to a collection. matAssign2 = look.addMaterialAssign("matAssign2", material.getName()) collection = doc.addCollection() - collectionAdd = collection.addCollectionAdd() - collectionAdd.setGeom("/robot2") - collectionRemove = collection.addCollectionRemove() - collectionRemove.setGeom("/robot2/left_arm") + collection.setIncludeGeom("/robot2") + collection.setExcludeGeom("/robot2/left_arm") matAssign2.setCollection(collection) self.assertTrue(material.getBoundGeomCollections()[0] == collection) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 576911c1cc..a47485e9c1 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -491,45 +491,53 @@ void Document::upgradeVersion() { MaterialPtr material = elem->asA(); LookPtr look = elem->asA(); - if (material || look) + GeomInfoPtr geomInfo = elem->asA(); + + vector origChildren = elem->getChildren(); + for (ElementPtr child : origChildren) { - vector origChildren = elem->getChildren(); - for (ElementPtr child : origChildren) + if (material && child->getCategory() == "override") { - if (child->getCategory() == "materialinherit") - { - elem->setInheritString(child->getAttribute("material")); - elem->removeChild(child->getName()); - } - else if (child->getCategory() == "lookinherit") + for (ShaderRefPtr shaderRef : material->getShaderRefs()) { - elem->setInheritString(child->getAttribute("look")); - elem->removeChild(child->getName()); - } - else if (material && child->getCategory() == "override") - { - for (ShaderRefPtr shaderRef : material->getShaderRefs()) + NodeDefPtr nodeDef = shaderRef->getNodeDef(); + for (ValueElementPtr valueElem : nodeDef->getActiveValueElements()) { - NodeDefPtr nodeDef = shaderRef->getNodeDef(); - for (ValueElementPtr valueElem : nodeDef->getActiveValueElements()) + if (valueElem->getAttribute("publicname") == child->getName() && + !shaderRef->getChild(child->getName())) { - if (valueElem->getAttribute("publicname") == child->getName() && - !shaderRef->getChild(child->getName())) + if (valueElem->isA()) + { + BindParamPtr bindParam = shaderRef->addBindParam(valueElem->getName(), valueElem->getType()); + bindParam->setValueString(child->getAttribute("value")); + } + else if (valueElem->isA()) { - if (valueElem->isA()) - { - BindParamPtr bindParam = shaderRef->addBindParam(valueElem->getName(), valueElem->getType()); - bindParam->setValueString(child->getAttribute("value")); - } - else if (valueElem->isA()) - { - BindInputPtr bindInput = shaderRef->addBindInput(valueElem->getName(), valueElem->getType()); - bindInput->setValueString(child->getAttribute("value")); - } + BindInputPtr bindInput = shaderRef->addBindInput(valueElem->getName(), valueElem->getType()); + bindInput->setValueString(child->getAttribute("value")); } } } - elem->removeChild(child->getName()); + } + elem->removeChild(child->getName()); + } + else if (material && child->getCategory() == "materialinherit") + { + elem->setInheritString(child->getAttribute("material")); + elem->removeChild(child->getName()); + } + else if (look && child->getCategory() == "lookinherit") + { + elem->setInheritString(child->getAttribute("look")); + elem->removeChild(child->getName()); + } + else if (geomInfo && child->isA()) + { + GeomAttrPtr geomAttr = child->asA(); + if (geomAttr->getType() == "string") + { + geomInfo->removeChild(geomAttr->getName()); + geomInfo->setTokenValue(geomAttr->getName(), geomAttr->getValueString()); } } } diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index f4c15ffa2b..0eb9f8f424 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -519,8 +519,6 @@ class Document : public Element /// @param message An optional output string, to which a description of /// each error will be appended. /// @return True if the document passes all tests, false otherwise. - /// @todo This method currently checks only a small subset of the MaterialX - /// rule set, and additional coverage is needed. bool validate(string* message = nullptr) const override; /// @} diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 98999ac9ab..586e4d4b46 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -418,10 +418,10 @@ StringResolverPtr Element::createStringResolver(const string& geom) const { if (!geomStringsMatch(geom, geomInfo->getGeom())) continue; - for (GeomAttrPtr geomAttr : geomInfo->getGeomAttrs()) + for (TokenPtr token : geomInfo->getTokens()) { - string key = "%" + geomAttr->getName(); - string value = geomAttr->getResolvedValueString(); + string key = "%" + token->getName(); + string value = token->getResolvedValueString(); resolver->setFilenameSubstitution(key, value); } } @@ -601,8 +601,6 @@ INSTANTIATE_SUBCLASS(T) INSTANTIATE_CONCRETE_SUBCLASS(BindParam, "bindparam") INSTANTIATE_CONCRETE_SUBCLASS(BindInput, "bindinput") INSTANTIATE_CONCRETE_SUBCLASS(Collection, "collection") -INSTANTIATE_CONCRETE_SUBCLASS(CollectionAdd, "collectionadd") -INSTANTIATE_CONCRETE_SUBCLASS(CollectionRemove, "collectionremove") INSTANTIATE_CONCRETE_SUBCLASS(Document, "materialx") INSTANTIATE_CONCRETE_SUBCLASS(GenericElement, "generic") INSTANTIATE_CONCRETE_SUBCLASS(GeomAttr, "geomattr") @@ -623,6 +621,7 @@ INSTANTIATE_CONCRETE_SUBCLASS(PropertyAssign, "propertyassign") INSTANTIATE_CONCRETE_SUBCLASS(PropertySet, "propertyset") INSTANTIATE_CONCRETE_SUBCLASS(PropertySetAssign, "propertysetassign") INSTANTIATE_CONCRETE_SUBCLASS(ShaderRef, "shaderref") +INSTANTIATE_CONCRETE_SUBCLASS(Token, "token") INSTANTIATE_CONCRETE_SUBCLASS(TypeDef, "typedef") INSTANTIATE_CONCRETE_SUBCLASS(Variant, "variant") INSTANTIATE_CONCRETE_SUBCLASS(VariantSet, "variantset") diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 6456010476..eec4968c37 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -33,6 +33,11 @@ using ValueElementPtr = shared_ptr; /// A shared pointer to a const ValueElement using ConstValueElementPtr = shared_ptr; +/// A shared pointer to a Token +using TokenPtr = shared_ptr; +/// A shared pointer to a const Token +using ConstTokenPtr = shared_ptr; + /// A shared pointer to a StringResolver using StringResolverPtr = shared_ptr; @@ -692,6 +697,8 @@ class Element : public std::enable_shared_from_this /// may be the univeral geometry name "*", which requests that all /// GeomAttr string substitutions be used. /// @return A shared pointer to a StringResolver. + /// @todo The StringResolver returned by this method doesn't yet take + /// interface tokens into account. StringResolverPtr createStringResolver(const string& geom = EMPTY_STRING) const; /// Return a single-line description of this element, including its category, @@ -944,6 +951,24 @@ class ValueElement : public TypedElement static const string IMPLEMENTATION_NAME_ATTRIBUTE; }; +/// @class Token +/// A token element representing a string value. +/// +/// Token elements are used to define input and output values for string +/// substitutions in image filenames. +class Token : public ValueElement +{ + public: + Token(ElementPtr parent, const string& name) : + ValueElement(parent, CATEGORY, name) + { + } + virtual ~Token() { } + + public: + static const string CATEGORY; +}; + /// @class GenericElement /// A generic element subclass, for instantiating elements with unrecognized categories. class GenericElement : public Element diff --git a/source/MaterialXCore/Geom.cpp b/source/MaterialXCore/Geom.cpp index 814a880ae7..8a98cb0a68 100644 --- a/source/MaterialXCore/Geom.cpp +++ b/source/MaterialXCore/Geom.cpp @@ -16,6 +16,10 @@ const string UV_TILE_TOKEN = "%UVTILE"; const string GeomElement::GEOM_ATTRIBUTE = "geom"; const string GeomElement::COLLECTION_ATTRIBUTE = "collection"; +const string Collection::INCLUDE_GEOM_ATTRIBUTE = "includegeom"; +const string Collection::INCLUDE_COLLECTION_ATTRIBUTE = "includecollection"; +const string Collection::EXCLUDE_GEOM_ATTRIBUTE = "excludegeom"; +const string Collection::EXCLUDE_COLLECTION_ATTRIBUTE = "excludecollection"; bool geomStringsMatch(const string& geom1, const string& geom2) { diff --git a/source/MaterialXCore/Geom.h b/source/MaterialXCore/Geom.h index 6e040bb6a7..b4c854a878 100644 --- a/source/MaterialXCore/Geom.h +++ b/source/MaterialXCore/Geom.h @@ -40,16 +40,6 @@ using CollectionPtr = shared_ptr; /// A shared pointer to a const Collection using ConstCollectionPtr = shared_ptr; -/// A shared pointer to a CollectionAdd -using CollectionAddPtr = shared_ptr; -/// A shared pointer to a const CollectionAdd -using ConstCollectionAddPtr = shared_ptr; - -/// A shared pointer to a CollectionRemove -using CollectionRemovePtr = shared_ptr; -/// A shared pointer to a const CollectionRemove -using ConstCollectionRemovePtr = shared_ptr; - /// @class GeomElement /// The base class for geometric elements, which support bindings to geometries /// and geometric collections. @@ -149,7 +139,7 @@ class GeomInfo : public GeomElement return getChildOfType(name); } - /// Return a vector of all GeomAttr elements in the element. + /// Return a vector of all GeomAttr elements. vector getGeomAttrs() const { return getChildrenOfType(); @@ -161,12 +151,59 @@ class GeomInfo : public GeomElement removeChildOfType(name); } - /// Set the value of a geomattr by its name, creating a child element - /// to hold the geomattr if needed. + /// @} + /// @name Tokens + /// @{ + + /// Add a Token to this element. + /// @param name The name of the new Token. + /// If no name is specified, then a unique name will automatically be + /// generated. + /// @return A shared pointer to the new Token. + TokenPtr addToken(const string& name = EMPTY_STRING) + { + return addChild(name); + } + + /// Return the Token, if any, with the given name. + TokenPtr getToken(const string& name) const + { + return getChildOfType(name); + } + + /// Return a vector of all Token elements. + vector getTokens() const + { + return getChildrenOfType(); + } + + /// Remove the Token, if any, with the given name. + void removeToken(const string& name) + { + removeChildOfType(name); + } + + /// @} + /// @name Values + /// @{ + + /// Set the value of a GeomAttr by its name, creating a child element + /// to hold the GeomAttr if needed. template GeomAttrPtr setGeomAttrValue(const string& name, const T& value, const string& type = EMPTY_STRING); + /// Set the string value of a Token by its name, creating a child element + /// to hold the Token if needed. + TokenPtr setTokenValue(const string& name, const string& value) + { + TokenPtr token = getToken(name); + if (!token) + token = addToken(name); + token->setValue(value); + return token; + } + /// @} public: @@ -201,103 +238,101 @@ class Collection : public Element } virtual ~Collection() { } - /// @name CollectionAdd Elements + /// @name Include Geometry /// @{ - /// Add a CollectionAdd to the collection. - /// @param name The name of the new CollectionAdd. - /// If no name is specified, then a unique name will automatically be - /// generated. - /// @return A shared pointer to the new CollectionAdd. - CollectionAddPtr addCollectionAdd(const string& name = EMPTY_STRING) + /// Set the include geometry string of this element. + void setIncludeGeom(const string& geom) { - return addChild(name); + setAttribute(INCLUDE_GEOM_ATTRIBUTE, geom); } - /// Return the CollectionAdd, if any, with the given name. - CollectionAddPtr getCollectionAdd(const string& name) const + /// Return true if this element has an include geometry string. + bool hasIncludeGeom() { - return getChildOfType(name); + return hasAttribute(INCLUDE_GEOM_ATTRIBUTE); } - /// Return a vector of all CollectionAdd elements in the collection - vector getCollectionAdds() const + /// Return the include geometry string of this element. + const string& getIncludeGeom() const { - return getChildrenOfType(); + return getAttribute(INCLUDE_GEOM_ATTRIBUTE); } - /// Remove the CollectionAdd, if any, with the given name. - void removeCollectionAdd(const string& name) + /// @} + /// @name Include Collection + /// @{ + + /// Set the include collection string of this element. + void setIncludeCollection(const string& collection) { - removeChildOfType(name); + setAttribute(INCLUDE_COLLECTION_ATTRIBUTE, collection); } - /// @} - /// @name CollectionRemove Elements - /// @{ + /// Return true if this element has an include collection string. + bool hasIncludeCollection() + { + return hasAttribute(INCLUDE_COLLECTION_ATTRIBUTE); + } - /// Add a CollectionRemove to the collection. - /// @param name The name of the new CollectionRemove. - /// If no name is specified, then a unique name will automatically be - /// generated. - /// @return A shared pointer to the new CollectionRemove. - CollectionRemovePtr addCollectionRemove(const string& name = EMPTY_STRING) + /// Return the include collection string of this element. + const string& getIncludeCollection() const { - return addChild(name); + return getAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } - /// Return the CollectionRemove, if any, with the given name. - CollectionRemovePtr getCollectionRemove(const string& name) const + /// @} + /// @name Exclude Geometry + /// @{ + + /// Set the exclude geometry string of this element. + void setExcludeGeom(const string& geom) { - return getChildOfType(name); + setAttribute(EXCLUDE_GEOM_ATTRIBUTE, geom); } - /// Return a vector of all CollectionRemove elements in the collection - vector getCollectionRemoves() const + /// Return true if this element has an exclude geometry string. + bool hasExcludeGeom() { - return getChildrenOfType(); + return hasAttribute(EXCLUDE_GEOM_ATTRIBUTE); } - /// Remove the CollectionRemove, if any, with the given name. - void removeCollectionRemove(const string& name) + /// Return the exclude geometry string of this element. + const string& getExcludeGeom() const { - removeChildOfType(name); + return getAttribute(EXCLUDE_GEOM_ATTRIBUTE); } /// @} + /// @name Exclude Collection + /// @{ - public: - static const string CATEGORY; -}; - -/// @class CollectionAdd -/// A collection add element within a Collection. -class CollectionAdd : public GeomElement -{ - public: - CollectionAdd(ElementPtr parent, const string& name) : - GeomElement(parent, CATEGORY, name) + /// Set the exclude collection string of this element. + void setExcludeCollection(const string& collection) { + setAttribute(EXCLUDE_COLLECTION_ATTRIBUTE, collection); } - virtual ~CollectionAdd() { } - public: - static const string CATEGORY; -}; + /// Return true if this element has an exclude collection string. + bool hasExcludeCollection() + { + return hasAttribute(EXCLUDE_COLLECTION_ATTRIBUTE); + } -/// @class CollectionRemove -/// A collection remove element within a Collection. -class CollectionRemove : public GeomElement -{ - public: - CollectionRemove(ElementPtr parent, const string& name) : - GeomElement(parent, CATEGORY, name) + /// Return the exclude collection string of this element. + const string& getExcludeCollection() const { + return getAttribute(EXCLUDE_COLLECTION_ATTRIBUTE); } - virtual ~CollectionRemove() { } + + /// @} public: static const string CATEGORY; + static const string INCLUDE_GEOM_ATTRIBUTE; + static const string INCLUDE_COLLECTION_ATTRIBUTE; + static const string EXCLUDE_GEOM_ATTRIBUTE; + static const string EXCLUDE_COLLECTION_ATTRIBUTE; }; template GeomAttrPtr GeomInfo::setGeomAttrValue(const string& name, diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index d969f35b98..f718408f0a 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -263,6 +263,30 @@ vector InterfaceElement::getActiveOutputs() const return activeOutputs; } +TokenPtr InterfaceElement::getActiveToken(const string& name) const +{ + for (ConstElementPtr elem : traverseInheritance()) + { + TokenPtr token = elem->asA()->getToken(name); + if (token) + { + return token; + } + } + return nullptr; +} + +vector InterfaceElement::getActiveTokens() const +{ + vector activeTokens; + for (ConstElementPtr elem : traverseInheritance()) + { + vector tokens = elem->asA()->getTokens(); + activeTokens.insert(activeTokens.end(), tokens.begin(), tokens.end()); + } + return activeTokens; +} + ValueElementPtr InterfaceElement::getActiveValueElement(const string& name) const { for (ConstElementPtr elem : traverseInheritance()) diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 16c644b0da..0537f68554 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -290,13 +290,14 @@ class InterfaceElement : public TypedElement /// @name Parameters /// @{ - /// Add a Parameter to this element. + /// Add a Parameter to this interface. /// @param name The name of the new Parameter. /// If no name is specified, then a unique name will automatically be /// generated. /// @param type An optional type string. /// @return A shared pointer to the new Parameter. - ParameterPtr addParameter(const string& name, const string& type = DEFAULT_TYPE_STRING) + ParameterPtr addParameter(const string& name = DEFAULT_TYPE_STRING, + const string& type = DEFAULT_TYPE_STRING) { ParameterPtr child = addChild(name); child->setType(type); @@ -339,13 +340,14 @@ class InterfaceElement : public TypedElement /// @name Inputs /// @{ - /// Add an Input to this element. + /// Add an Input to this interface. /// @param name The name of the new Input. /// If no name is specified, then a unique name will automatically be /// generated. /// @param type An optional type string. /// @return A shared pointer to the new Input. - InputPtr addInput(const string& name, const string& type = DEFAULT_TYPE_STRING) + InputPtr addInput(const string& name = DEFAULT_TYPE_STRING, + const string& type = DEFAULT_TYPE_STRING) { InputPtr child = addChild(name); child->setType(type); @@ -388,7 +390,7 @@ class InterfaceElement : public TypedElement /// @name Outputs /// @{ - /// Add an Output to this element. + /// Add an Output to this interface. /// @param name The name of the new Output. /// If no name is specified, then a unique name will automatically be /// generated. @@ -434,18 +436,58 @@ class InterfaceElement : public TypedElement /// taking inheritance into account. vector getActiveOutputs() const; + /// @} + /// @name Tokens + /// @{ + + /// Add a Token to this interface. + /// @param name The name of the new Token. + /// If no name is specified, then a unique name will automatically be + /// generated. + /// @return A shared pointer to the new Token. + TokenPtr addToken(const string& name = EMPTY_STRING) + { + return addChild(name); + } + + /// Return the Token, if any, with the given name. + TokenPtr getToken(const string& name) const + { + return getChildOfType(name); + } + + /// Return a vector of all Token elements. + vector getTokens() const + { + return getChildrenOfType(); + } + + /// Remove the Token, if any, with the given name. + void removeToken(const string& name) + { + removeChildOfType(name); + } + + /// Return the first Token with the given name that belongs to this + /// interface, taking interface inheritance into account. + TokenPtr getActiveToken(const string& name) const; + + /// Return a vector of all Token elements that belong to this interface, + /// taking inheritance into account. + vector getActiveTokens() const; + /// @} /// @name Value Elements /// @{ /// Return the first value element with the given name that belongs to this /// interface, taking interface inheritance into account. - /// Examples of value elements are Parameter, Input, and Output. + /// Examples of value elements are Parameter, Input, Output, and Token. ValueElementPtr getActiveValueElement(const string& name) const; /// Return a vector of all value elements that belong to this interface, /// taking inheritance into account. - /// Examples of value elements are Parameter, Input, and Output. + /// Examples of value elements are Parameter, Input, Output, and Token. vector getActiveValueElements() const; /// @} @@ -484,6 +526,25 @@ class InterfaceElement : public TypedElement /// otherwise, an empty shared pointer is returned. ValuePtr getInputValue(const string& name, const string& target = EMPTY_STRING) const; + /// Set the string value of a Token by its name, creating a child element + /// to hold the Token if needed. + TokenPtr setTokenValue(const string& name, const string& value) + { + TokenPtr token = getToken(name); + if (!token) + token = addToken(name); + token->setValue(value); + return token; + } + + /// Return the string value of a Token by its name, or an empty string if + /// the given Token is not present. + string getTokenValue(const string& name) + { + TokenPtr token = getToken(name); + return token ? token->getValueString() : EMPTY_STRING; + } + /// @} /// @name Utility /// @{ diff --git a/source/MaterialXTest/Geom.cpp b/source/MaterialXTest/Geom.cpp index 742695426a..961c69a88d 100644 --- a/source/MaterialXTest/Geom.cpp +++ b/source/MaterialXTest/Geom.cpp @@ -13,13 +13,13 @@ TEST_CASE("Geom", "[geom]") { mx::DocumentPtr doc = mx::createDocument(); - // Add geominfos and geomattrs + // Add geominfos and tokens mx::GeomInfoPtr geominfo1 = doc->addGeomInfo("geominfo1", "/robot1,/robot2"); - geominfo1->setGeomAttrValue("asset", std::string("robot")); + geominfo1->setTokenValue("asset", std::string("robot")); mx::GeomInfoPtr geominfo2 = doc->addGeomInfo("geominfo2", "/robot1"); - geominfo2->setGeomAttrValue("id", std::string("01")); + geominfo2->setTokenValue("id", std::string("01")); mx::GeomInfoPtr geominfo3 = doc->addGeomInfo("geominfo3", "/robot2"); - geominfo3->setGeomAttrValue("id", std::string("02")); + geominfo3->setTokenValue("id", std::string("02")); REQUIRE_THROWS_AS(doc->addGeomInfo("geominfo1"), mx::Exception&); // Create a node graph with a single image node. @@ -40,11 +40,10 @@ TEST_CASE("Geom", "[geom]") // Test geometry string substitutions. mx::CollectionPtr collection = doc->addCollection("collection1"); - mx::CollectionAddPtr collectionAdd = collection->addCollectionAdd("collectionAdd1"); - std::string geom = "|group1|sphere1"; - collectionAdd->setGeom(geom); - collectionAdd->setGeomPrefix("/geomPrefix1"); - mx::StringResolverPtr resolver3 = collectionAdd->createStringResolver(); - resolver3->setGeomNameSubstitution("|", "/"); - REQUIRE(resolver3->resolve(collectionAdd->getGeom(), mx::GEOMNAME_TYPE_STRING) == "/geomPrefix1/group1/sphere1"); + collection->setIncludeGeom("/group1/sphere1"); + collection->setGeomPrefix("/root"); + mx::StringResolverPtr resolver3 = collection->createStringResolver(); + resolver3->setGeomNameSubstitution("group1", "group2"); + std::string resolved = resolver3->resolve(collection->getIncludeGeom(), mx::GEOMNAME_TYPE_STRING); + REQUIRE(resolved == "/root/group2/sphere1"); } diff --git a/source/MaterialXTest/Look.cpp b/source/MaterialXTest/Look.cpp index 2f322ca475..9cf7487a8d 100644 --- a/source/MaterialXTest/Look.cpp +++ b/source/MaterialXTest/Look.cpp @@ -29,10 +29,8 @@ TEST_CASE("Look", "[look]") // Bind the material to a geometric collection. mx::MaterialAssignPtr matAssign2 = look->addMaterialAssign("matAssign2", material->getName()); mx::CollectionPtr collection = doc->addCollection(); - mx::CollectionAddPtr collectionAdd = collection->addCollectionAdd(); - collectionAdd->setGeom("/robot2"); - mx::CollectionRemovePtr collectionRemove = collection->addCollectionRemove(); - collectionRemove->setGeom("/robot2/left_arm"); + collection->setIncludeGeom("/robot2"); + collection->setExcludeGeom("/robot2/left_arm"); matAssign2->setCollection(collection); REQUIRE(material->getBoundGeomCollections()[0] == collection); diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index 16c858a0ee..d2d3466b77 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -107,8 +107,6 @@ void bindPyElement(py::module& mod) BIND_ELEMENT_FUNC_INSTANCE(BindParam) BIND_ELEMENT_FUNC_INSTANCE(BindInput) BIND_ELEMENT_FUNC_INSTANCE(Collection) - BIND_ELEMENT_FUNC_INSTANCE(CollectionAdd) - BIND_ELEMENT_FUNC_INSTANCE(CollectionRemove) BIND_ELEMENT_FUNC_INSTANCE(Document) BIND_ELEMENT_FUNC_INSTANCE(GeomAttr) BIND_ELEMENT_FUNC_INSTANCE(GeomInfo) @@ -124,6 +122,7 @@ void bindPyElement(py::module& mod) BIND_ELEMENT_FUNC_INSTANCE(PropertySet) BIND_ELEMENT_FUNC_INSTANCE(PropertySetAssign) BIND_ELEMENT_FUNC_INSTANCE(ShaderRef) + BIND_ELEMENT_FUNC_INSTANCE(Token) BIND_ELEMENT_FUNC_INSTANCE(TypeDef) BIND_ELEMENT_FUNC_INSTANCE(Visibility); @@ -160,7 +159,8 @@ void bindPyElement(py::module& mod) BIND_VALUE_ELEMENT_FUNC_INSTANCE(matrix44, mx::Matrix44) BIND_VALUE_ELEMENT_FUNC_INSTANCE(string, std::string); - py::class_(mod, "ElementPredicate"); + py::class_(mod, "Token") + .def_readonly_static("CATEGORY", &mx::Token::CATEGORY); py::class_(mod, "StringResolver") .def("setFilePrefix", &mx::StringResolver::setFilePrefix) @@ -175,6 +175,8 @@ void bindPyElement(py::module& mod) .def("getGeomNameSubstitutions", &mx::StringResolver::getGeomNameSubstitutions) .def("resolve", &mx::StringResolver::resolve); + py::class_(mod, "ElementPredicate"); + py::register_exception(mod, "ExceptionOrphanedElement"); mod.def("targetStringsMatch", &mx::targetStringsMatch); diff --git a/source/PyMaterialX/PyGeom.cpp b/source/PyMaterialX/PyGeom.cpp index 52a662ff93..324a96bfba 100644 --- a/source/PyMaterialX/PyGeom.cpp +++ b/source/PyMaterialX/PyGeom.cpp @@ -27,8 +27,15 @@ void bindPyGeom(py::module& mod) py::class_(mod, "GeomInfo") .def("_addGeomAttr", &mx::GeomInfo::addGeomAttr) + .def("getGeomAttr", &mx::GeomInfo::getGeomAttr) .def("getGeomAttrs", &mx::GeomInfo::getGeomAttrs) .def("removeGeomAttr", &mx::GeomInfo::removeGeomAttr) + .def("addToken", &mx::GeomInfo::addToken, + py::arg("name") = mx::DEFAULT_TYPE_STRING) + .def("getToken", &mx::GeomInfo::getToken) + .def("getTokens", &mx::GeomInfo::getTokens) + .def("removeToken", &mx::GeomInfo::removeToken) + .def("setTokenValue", &mx::GeomInfo::setTokenValue) BIND_GEOMINFO_FUNC_INSTANCE(integer, int) BIND_GEOMINFO_FUNC_INSTANCE(boolean, bool) BIND_GEOMINFO_FUNC_INSTANCE(float, float) @@ -47,23 +54,19 @@ void bindPyGeom(py::module& mod) .def_readonly_static("CATEGORY", &mx::GeomAttr::CATEGORY); py::class_(mod, "Collection") - .def("addCollectionAdd", &mx::Collection::addCollectionAdd, - py::arg("name") = mx::EMPTY_STRING) - .def("getCollectionAdd", &mx::Collection::getCollectionAdd) - .def("getCollectionAdds", &mx::Collection::getCollectionAdds) - .def("removeCollectionAdd", &mx::Collection::removeCollectionAdd) - .def("addCollectionRemove", &mx::Collection::addCollectionRemove, - py::arg("name") = mx::EMPTY_STRING) - .def("getCollectionRemove", &mx::Collection::getCollectionRemove) - .def("getCollectionRemoves", &mx::Collection::getCollectionRemoves) - .def("removeCollectionRemove", &mx::Collection::removeCollectionRemove) + .def("setIncludeGeom", &mx::Collection::setIncludeGeom) + .def("hasIncludeGeom", &mx::Collection::hasIncludeGeom) + .def("getIncludeGeom", &mx::Collection::getIncludeGeom) + .def("setIncludeCollection", &mx::Collection::setIncludeCollection) + .def("hasIncludeCollection", &mx::Collection::hasIncludeCollection) + .def("getIncludeCollection", &mx::Collection::getIncludeCollection) + .def("setExcludeGeom", &mx::Collection::setExcludeGeom) + .def("hasExcludeGeom", &mx::Collection::hasExcludeGeom) + .def("getExcludeGeom", &mx::Collection::getExcludeGeom) + .def("setExcludeCollection", &mx::Collection::setExcludeCollection) + .def("hasExcludeCollection", &mx::Collection::hasExcludeCollection) + .def("getExcludeCollection", &mx::Collection::getExcludeCollection) .def_readonly_static("CATEGORY", &mx::Collection::CATEGORY); - py::class_(mod, "CollectionAdd") - .def_readonly_static("CATEGORY", &mx::CollectionAdd::CATEGORY); - - py::class_(mod, "CollectionRemove") - .def_readonly_static("CATEGORY", &mx::CollectionRemove::CATEGORY); - mod.def("geomStringsMatch", &mx::geomStringsMatch); } diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index 4cc111033b..c7db01fc95 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -36,9 +36,9 @@ void bindPyInterface(py::module& mod) .def("hasUpstreamCycle", &mx::Output::hasUpstreamCycle) .def_readonly_static("CATEGORY", &mx::Output::CATEGORY); - py::class_, mx::TypedElement>(mod, "InterfaceElement") + py::class_(mod, "InterfaceElement") .def("addParameter", &mx::InterfaceElement::addParameter, - py::arg("name"), py::arg("type") = mx::DEFAULT_TYPE_STRING) + py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getParameter", &mx::InterfaceElement::getParameter) .def("getParameters", &mx::InterfaceElement::getParameters) .def("getParameterCount", &mx::InterfaceElement::getParameterCount) @@ -46,7 +46,7 @@ void bindPyInterface(py::module& mod) .def("getActiveParameter", &mx::InterfaceElement::getActiveParameter) .def("getActiveParameters", &mx::InterfaceElement::getActiveParameters) .def("addInput", &mx::InterfaceElement::addInput, - py::arg("name"), py::arg("type") = mx::DEFAULT_TYPE_STRING) + py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getInput", &mx::InterfaceElement::getInput) .def("getInputs", &mx::InterfaceElement::getInputs) .def("getInputCount", &mx::InterfaceElement::getInputCount) @@ -61,10 +61,19 @@ void bindPyInterface(py::module& mod) .def("removeOutput", &mx::InterfaceElement::removeOutput) .def("getActiveOutput", &mx::InterfaceElement::getActiveOutput) .def("getActiveOutputs", &mx::InterfaceElement::getActiveOutputs) + .def("addToken", &mx::InterfaceElement::addToken, + py::arg("name") = mx::DEFAULT_TYPE_STRING) + .def("getToken", &mx::InterfaceElement::getToken) + .def("getTokens", &mx::InterfaceElement::getTokens) + .def("removeToken", &mx::InterfaceElement::removeToken) + .def("getActiveToken", &mx::InterfaceElement::getActiveToken) + .def("getActiveTokens", &mx::InterfaceElement::getActiveTokens) .def("getActiveValueElement", &mx::InterfaceElement::getActiveValueElement) .def("getActiveValueElements", &mx::InterfaceElement::getActiveValueElements) .def("_getParameterValue", &mx::InterfaceElement::getParameterValue) .def("_getInputValue", &mx::InterfaceElement::getInputValue) + .def("setTokenValue", &mx::InterfaceElement::setTokenValue) + .def("getTokenValue", &mx::InterfaceElement::getTokenValue) .def("getDeclaration", &mx::InterfaceElement::getDeclaration, py::arg("target") = mx::EMPTY_STRING) .def("isTypeCompatible", &mx::InterfaceElement::isTypeCompatible) From a6571a798af345be82a8992e5cd69add2caca539 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 17 May 2018 12:28:04 -0700 Subject: [PATCH 05/27] Geometry name updates for MaterialX v1.36 - Update geometry name matching rules to match v1.36. - Remove an unsupported attribute from Collection. - Add helper class GeomPath. --- source/MaterialXCore/Element.h | 8 +-- source/MaterialXCore/Geom.cpp | 35 +++++----- source/MaterialXCore/Geom.h | 118 +++++++++++++++++++++++++-------- source/MaterialXTest/Geom.cpp | 13 +++- source/PyMaterialX/PyGeom.cpp | 3 - 5 files changed, 126 insertions(+), 51 deletions(-) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index eec4968c37..fb90d5b6b7 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -692,10 +692,10 @@ class Element : public std::enable_shared_from_this /// Construct a StringResolver at the scope of this element. The returned /// object may be used to apply substring modifiers to data values in the /// context of a specific element and geometry. - /// @param geom An optional geometry name, which will be used to the - /// applicable set of GeomAttr-based string substitutions. This name - /// may be the univeral geometry name "*", which requests that all - /// GeomAttr string substitutions be used. + /// @param geom An optional geometry name, which will be used to select the + /// applicable set of geometric string substitutions. By default, no + /// geometric string substitutions are applied. If the universal geometry + /// name "/" is given, then all geometric string substitutions are applied, /// @return A shared pointer to a StringResolver. /// @todo The StringResolver returned by this method doesn't yet take /// interface tokens into account. diff --git a/source/MaterialXCore/Geom.cpp b/source/MaterialXCore/Geom.cpp index 8a98cb0a68..df4448e721 100644 --- a/source/MaterialXCore/Geom.cpp +++ b/source/MaterialXCore/Geom.cpp @@ -10,7 +10,8 @@ namespace MaterialX { -const string UNIVERSAL_GEOM_NAME = "*"; +const string GEOM_PATH_SEPARATOR = "/"; +const string UNIVERSAL_GEOM_NAME = GEOM_PATH_SEPARATOR; const string UDIM_TOKEN = "%UDIM"; const string UV_TILE_TOKEN = "%UVTILE"; @@ -19,24 +20,26 @@ const string GeomElement::COLLECTION_ATTRIBUTE = "collection"; const string Collection::INCLUDE_GEOM_ATTRIBUTE = "includegeom"; const string Collection::INCLUDE_COLLECTION_ATTRIBUTE = "includecollection"; const string Collection::EXCLUDE_GEOM_ATTRIBUTE = "excludegeom"; -const string Collection::EXCLUDE_COLLECTION_ATTRIBUTE = "excludecollection"; bool geomStringsMatch(const string& geom1, const string& geom2) { - vector vec1 = splitString(geom1, ARRAY_VALID_SEPARATORS); - vector vec2 = splitString(geom2, ARRAY_VALID_SEPARATORS); - std::set set1(vec1.begin(), vec1.end()); - std::set set2(vec2.begin(), vec2.end()); - - if (set1.empty() || set2.empty()) - return false; - if (set1.count(UNIVERSAL_GEOM_NAME) || set2.count(UNIVERSAL_GEOM_NAME)) - return true; - - std::set matches; - std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), - std::inserter(matches, matches.end())); - return !matches.empty(); + vector paths1; + for (const string& name1 : splitString(geom1, ARRAY_VALID_SEPARATORS)) + { + paths1.push_back(GeomPath(name1)); + } + for (const string& name2 : splitString(geom2, ARRAY_VALID_SEPARATORS)) + { + GeomPath path2(name2); + for (const GeomPath& path1 : paths1) + { + if (path2.isMatching(path1)) + { + return true; + } + } + } + return false; } void GeomElement::setCollection(ConstCollectionPtr collection) diff --git a/source/MaterialXCore/Geom.h b/source/MaterialXCore/Geom.h index b4c854a878..44ca212107 100644 --- a/source/MaterialXCore/Geom.h +++ b/source/MaterialXCore/Geom.h @@ -16,6 +16,7 @@ namespace MaterialX { +extern const string GEOM_PATH_SEPARATOR; extern const string UNIVERSAL_GEOM_NAME; extern const string UDIM_TOKEN; extern const string UV_TILE_TOKEN; @@ -40,6 +41,91 @@ using CollectionPtr = shared_ptr; /// A shared pointer to a const Collection using ConstCollectionPtr = shared_ptr; +/// @class GeomPath +/// A MaterialX geometry path, representing the hierarchical location +/// expressed by a geometry name. +class GeomPath +{ + public: + GeomPath() : + _empty(true) + { + } + ~GeomPath() { } + + bool operator==(const GeomPath& rhs) const + { + return _vec == rhs._vec && + _empty == rhs._empty; + } + bool operator!=(const GeomPath& rhs) const + { + return !(*this == rhs); + } + + /// Construct a path from a geometry name string. + explicit GeomPath(const string& geom) + { + _vec = splitString(geom, GEOM_PATH_SEPARATOR); + _empty = geom.empty(); + } + + /// Convert a path to a geometry name string. + operator string() const + { + if (_vec.empty()) + { + return _empty ? EMPTY_STRING : UNIVERSAL_GEOM_NAME; + } + string geom; + for (size_t i = 0; i < _vec.size(); i++) + { + geom += _vec[i]; + if (i + 1 < _vec.size()) + { + geom += GEOM_PATH_SEPARATOR; + } + } + return geom; + } + + /// Return true if there is any geometry in common between the two paths. + bool isMatching(const GeomPath& rhs) const + { + if (_empty || rhs._empty) + { + return false; + } + size_t minSize = std::min(_vec.size(), rhs._vec.size()); + for (size_t i = 0; i < minSize; i++) + { + if (_vec[i] != rhs._vec[i]) + { + return false; + } + } + return true; + } + + /// Return true if this geometry path is empty. An empty path matches + /// no other geometry paths. + bool isEmpty() const + { + return _empty; + } + + /// Return true if this geometry path is universal. A universal path + /// matches all non-empty geometry paths. + bool isUniversal() const + { + return _vec.empty() && !_empty; + } + + private: + vector _vec; + bool _empty; +}; + /// @class GeomElement /// The base class for geometric elements, which support bindings to geometries /// and geometric collections. @@ -304,28 +390,6 @@ class Collection : public Element } /// @} - /// @name Exclude Collection - /// @{ - - /// Set the exclude collection string of this element. - void setExcludeCollection(const string& collection) - { - setAttribute(EXCLUDE_COLLECTION_ATTRIBUTE, collection); - } - - /// Return true if this element has an exclude collection string. - bool hasExcludeCollection() - { - return hasAttribute(EXCLUDE_COLLECTION_ATTRIBUTE); - } - - /// Return the exclude collection string of this element. - const string& getExcludeCollection() const - { - return getAttribute(EXCLUDE_COLLECTION_ATTRIBUTE); - } - - /// @} public: static const string CATEGORY; @@ -347,10 +411,12 @@ template GeomAttrPtr GeomInfo::setGeomAttrValue(const string& name, } /// Given two geometry strings, each containing an array of geom names, return -/// true if they have any geometries in common. The universal geom name "*" -/// matches all geometries. -/// @todo The full set of pattern matching rules in the specification is not -/// yet supported, and only the universal geom name is currently handled. +/// true if they have any geometries in common. +/// +/// An empty geometry string matches no geometries, while the universal geometry +/// string "/" matches all non-empty geometries. +/// +/// @todo Geometry name expressions are not yet supported. /// @relates GeomInfo bool geomStringsMatch(const string& geom1, const string& geom2); diff --git a/source/MaterialXTest/Geom.cpp b/source/MaterialXTest/Geom.cpp index 961c69a88d..168d648048 100644 --- a/source/MaterialXTest/Geom.cpp +++ b/source/MaterialXTest/Geom.cpp @@ -9,12 +9,21 @@ namespace mx = MaterialX; -TEST_CASE("Geom", "[geom]") +TEST_CASE("Geom strings", "[geom]") +{ + REQUIRE(mx::geomStringsMatch("/", "/robot1")); + REQUIRE(mx::geomStringsMatch("/robot1", "/robot1/left_arm")); + REQUIRE(mx::geomStringsMatch("/robot1, /robot2", "/robot2/left_arm")); + REQUIRE(!mx::geomStringsMatch("/robot1", "/robot2")); + REQUIRE(!mx::geomStringsMatch("/robot1, /robot2", "/robot3")); +} + +TEST_CASE("Geom elements", "[geom]") { mx::DocumentPtr doc = mx::createDocument(); // Add geominfos and tokens - mx::GeomInfoPtr geominfo1 = doc->addGeomInfo("geominfo1", "/robot1,/robot2"); + mx::GeomInfoPtr geominfo1 = doc->addGeomInfo("geominfo1", "/robot1, /robot2"); geominfo1->setTokenValue("asset", std::string("robot")); mx::GeomInfoPtr geominfo2 = doc->addGeomInfo("geominfo2", "/robot1"); geominfo2->setTokenValue("id", std::string("01")); diff --git a/source/PyMaterialX/PyGeom.cpp b/source/PyMaterialX/PyGeom.cpp index 324a96bfba..e1be7e0b0b 100644 --- a/source/PyMaterialX/PyGeom.cpp +++ b/source/PyMaterialX/PyGeom.cpp @@ -63,9 +63,6 @@ void bindPyGeom(py::module& mod) .def("setExcludeGeom", &mx::Collection::setExcludeGeom) .def("hasExcludeGeom", &mx::Collection::hasExcludeGeom) .def("getExcludeGeom", &mx::Collection::getExcludeGeom) - .def("setExcludeCollection", &mx::Collection::setExcludeCollection) - .def("hasExcludeCollection", &mx::Collection::hasExcludeCollection) - .def("getExcludeCollection", &mx::Collection::getExcludeCollection) .def_readonly_static("CATEGORY", &mx::Collection::CATEGORY); mod.def("geomStringsMatch", &mx::geomStringsMatch); From cd064fc927869a9a4ad2751c9d35c0445227a689 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 17 May 2018 15:40:59 -0700 Subject: [PATCH 06/27] Additional variant and geometry string updates for v1.36 - Add an initial VariantAssign class. - Update legacy references to the universal geometry string. --- python/MaterialX/main.py | 2 +- source/MaterialXCore/Document.cpp | 22 ++++++--- source/MaterialXCore/Element.cpp | 1 + source/MaterialXCore/Element.h | 4 +- source/MaterialXCore/Look.cpp | 11 +++++ source/MaterialXCore/Look.h | 37 ++++++++++++++++ source/MaterialXCore/Variant.cpp | 14 ++++++ source/MaterialXCore/Variant.h | 74 +++++++++++++++++++++++++++++-- source/MaterialXTest/Geom.cpp | 1 + source/PyMaterialX/PyLook.cpp | 7 +++ source/PyMaterialX/PyVariant.cpp | 9 ++++ 11 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 source/MaterialXCore/Variant.cpp diff --git a/python/MaterialX/main.py b/python/MaterialX/main.py index 3c356dd2ef..9368284400 100644 --- a/python/MaterialX/main.py +++ b/python/MaterialX/main.py @@ -240,7 +240,7 @@ def _setGeomAttrValue(self, name, value, typeString = ''): # Document # -def _applyStringSubstitutions(self, filename, geom = '*'): +def _applyStringSubstitutions(self, filename, geom = '/'): """(Deprecated) Given an input filename and geom string, apply any string substitutions that have been defined for the given geom to the filename, returning the modified filename.""" diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index a47485e9c1..db60f62c7f 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -489,10 +489,20 @@ void Document::upgradeVersion() { for (ElementPtr elem : traverseTree()) { + ValueElementPtr valueElem = elem->asA(); MaterialPtr material = elem->asA(); LookPtr look = elem->asA(); GeomInfoPtr geomInfo = elem->asA(); + if (valueElem) + { + if (valueElem->getType() == GEOMNAME_TYPE_STRING && + valueElem->getValueString() == "*") + { + valueElem->setValueString(UNIVERSAL_GEOM_NAME); + } + } + vector origChildren = elem->getChildren(); for (ElementPtr child : origChildren) { @@ -501,19 +511,19 @@ void Document::upgradeVersion() for (ShaderRefPtr shaderRef : material->getShaderRefs()) { NodeDefPtr nodeDef = shaderRef->getNodeDef(); - for (ValueElementPtr valueElem : nodeDef->getActiveValueElements()) + for (ValueElementPtr activeValue : nodeDef->getActiveValueElements()) { - if (valueElem->getAttribute("publicname") == child->getName() && + if (activeValue->getAttribute("publicname") == child->getName() && !shaderRef->getChild(child->getName())) { - if (valueElem->isA()) + if (activeValue->isA()) { - BindParamPtr bindParam = shaderRef->addBindParam(valueElem->getName(), valueElem->getType()); + BindParamPtr bindParam = shaderRef->addBindParam(activeValue->getName(), activeValue->getType()); bindParam->setValueString(child->getAttribute("value")); } - else if (valueElem->isA()) + else if (activeValue->isA()) { - BindInputPtr bindInput = shaderRef->addBindInput(valueElem->getName(), valueElem->getType()); + BindInputPtr bindInput = shaderRef->addBindInput(activeValue->getName(), activeValue->getType()); bindInput->setValueString(child->getAttribute("value")); } } diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 586e4d4b46..3e34476761 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -624,6 +624,7 @@ INSTANTIATE_CONCRETE_SUBCLASS(ShaderRef, "shaderref") INSTANTIATE_CONCRETE_SUBCLASS(Token, "token") INSTANTIATE_CONCRETE_SUBCLASS(TypeDef, "typedef") INSTANTIATE_CONCRETE_SUBCLASS(Variant, "variant") +INSTANTIATE_CONCRETE_SUBCLASS(VariantAssign, "variantassign") INSTANTIATE_CONCRETE_SUBCLASS(VariantSet, "variantset") INSTANTIATE_CONCRETE_SUBCLASS(Visibility, "visibility") diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index fb90d5b6b7..15e2447dd5 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -1054,7 +1054,7 @@ class StringResolver _filenameMap[key] = value; } - /// Get list of filename substring substitutions. + /// Return the map of filename substring substitutions. const StringMap& getFilenameSubstitutions() const { return _filenameMap; @@ -1070,7 +1070,7 @@ class StringResolver _geomNameMap[key] = value; } - /// Get list of geometry name substring substitutions. + /// Return the map of geometry name substring substitutions. const StringMap& getGeomNameSubstitutions() const { return _geomNameMap; diff --git a/source/MaterialXCore/Look.cpp b/source/MaterialXCore/Look.cpp index 8ccd124b21..635c029b41 100644 --- a/source/MaterialXCore/Look.cpp +++ b/source/MaterialXCore/Look.cpp @@ -63,6 +63,17 @@ vector Look::getActivePropertySetAssigns() const return activeAssigns; } +vector Look::getActiveVariantAssigns() const +{ + vector activeAssigns; + for (ConstElementPtr elem : traverseInheritance()) + { + vector assigns = elem->asA()->getVariantAssigns(); + activeAssigns.insert(activeAssigns.end(), assigns.begin(), assigns.end()); + } + return activeAssigns; +} + vector Look::getActiveVisibilities() const { vector activeVisibilities; diff --git a/source/MaterialXCore/Look.h b/source/MaterialXCore/Look.h index 88464c023e..9c7e5444af 100644 --- a/source/MaterialXCore/Look.h +++ b/source/MaterialXCore/Look.h @@ -13,6 +13,7 @@ #include #include +#include namespace MaterialX { @@ -151,6 +152,42 @@ class Look : public Element removeChildOfType(name); } + /// @} + /// @name VariantAssign Elements + /// @{ + + /// Add a VariantAssign to the look. + /// @param name The name of the new VariantAssign. + /// If no name is specified, then a unique name will automatically be + /// generated. + /// @return A shared pointer to the new VariantAssign. + VariantAssignPtr addVariantAssign(const string& name = EMPTY_STRING) + { + return addChild(name); + } + + /// Return the VariantAssign, if any, with the given name. + VariantAssignPtr getVariantAssign(const string& name) const + { + return getChildOfType(name); + } + + /// Return a vector of all VariantAssign elements in the look. + vector getVariantAssigns() const + { + return getChildrenOfType(); + } + + /// Return a vector of all VariantAssign elements that belong to this look, + /// taking look inheritance into account. + vector getActiveVariantAssigns() const; + + /// Remove the VariantAssign, if any, with the given name. + void removeVariantAssign(const string& name) + { + removeChildOfType(name); + } + /// @} /// @name Visibility Elements /// @{ diff --git a/source/MaterialXCore/Variant.cpp b/source/MaterialXCore/Variant.cpp new file mode 100644 index 0000000000..76a6047e46 --- /dev/null +++ b/source/MaterialXCore/Variant.cpp @@ -0,0 +1,14 @@ +// +// TM & (c) 2017 Lucasfilm Entertainment Company Ltd. and Lucasfilm Ltd. +// All rights reserved. See LICENSE.txt for license. +// + +#include + +namespace MaterialX +{ + +const string VariantAssign::VARIANT_SET_ATTRIBUTE = "variantset"; +const string VariantAssign::VARIANT_ATTRIBUTE = "variant"; + +} // namespace MaterialX diff --git a/source/MaterialXCore/Variant.h b/source/MaterialXCore/Variant.h index c5239b7da0..307548595c 100644 --- a/source/MaterialXCore/Variant.h +++ b/source/MaterialXCore/Variant.h @@ -26,6 +26,11 @@ using VariantSetPtr = shared_ptr; /// A shared pointer to a const VariantSet using ConstVariantSetPtr = shared_ptr; +/// A shared pointer to a VariantAssign +using VariantAssignPtr = shared_ptr; +/// A shared pointer to a const VariantAssign +using ConstVariantAssignPtr = shared_ptr; + /// @class Variant /// A variant element within a VariantSet class Variant : public InterfaceElement @@ -37,7 +42,7 @@ class Variant : public InterfaceElement } virtual ~Variant() { } -public: + public: static const string CATEGORY; }; @@ -52,8 +57,7 @@ class VariantSet : public Element } virtual ~VariantSet() { } - /// @} - /// @name Varient Elements + /// @name Variant Elements /// @{ /// Add a Variant to the variant set. @@ -90,6 +94,70 @@ class VariantSet : public Element static const string CATEGORY; }; +/// @class VariantAssign +/// A variant assignment element within a Look. +/// @todo Add support for variant assignments in graph traversal and +/// Element::getBoundValue. +class VariantAssign : public Element +{ + public: + VariantAssign(ElementPtr parent, const string& name) : + Element(parent, CATEGORY, name) + { + } + virtual ~VariantAssign() { } + + /// @name Variant Set String + /// @{ + + /// Set the element's variant set string. + void setVariantSetString(const string& variantSet) + { + setAttribute(VARIANT_SET_ATTRIBUTE, variantSet); + } + + /// Return true if the given element has a variant set string. + bool hasVariantSetString() const + { + return hasAttribute(VARIANT_SET_ATTRIBUTE); + } + + /// Return the element's variant set string. + const string& getVariantSetString() const + { + return getAttribute(VARIANT_SET_ATTRIBUTE); + } + + /// @} + /// @name Variant String + /// @{ + + /// Set the element's variant string. + void setVariantString(const string& variant) + { + setAttribute(VARIANT_ATTRIBUTE, variant); + } + + /// Return true if the given element has a variant string. + bool hasVariantString() const + { + return hasAttribute(VARIANT_ATTRIBUTE); + } + + /// Return the element's variant string. + const string& getVariantString() const + { + return getAttribute(VARIANT_ATTRIBUTE); + } + + /// @} + +public: + static const string CATEGORY; + static const string VARIANT_SET_ATTRIBUTE; + static const string VARIANT_ATTRIBUTE; +}; + } // namespace MaterialX #endif diff --git a/source/MaterialXTest/Geom.cpp b/source/MaterialXTest/Geom.cpp index 168d648048..6f2529ac51 100644 --- a/source/MaterialXTest/Geom.cpp +++ b/source/MaterialXTest/Geom.cpp @@ -14,6 +14,7 @@ TEST_CASE("Geom strings", "[geom]") REQUIRE(mx::geomStringsMatch("/", "/robot1")); REQUIRE(mx::geomStringsMatch("/robot1", "/robot1/left_arm")); REQUIRE(mx::geomStringsMatch("/robot1, /robot2", "/robot2/left_arm")); + REQUIRE(!mx::geomStringsMatch("", "/robot1")); REQUIRE(!mx::geomStringsMatch("/robot1", "/robot2")); REQUIRE(!mx::geomStringsMatch("/robot1, /robot2", "/robot3")); } diff --git a/source/PyMaterialX/PyLook.cpp b/source/PyMaterialX/PyLook.cpp index b0a1671d7e..f9ab4e7388 100644 --- a/source/PyMaterialX/PyLook.cpp +++ b/source/PyMaterialX/PyLook.cpp @@ -32,7 +32,14 @@ void bindPyLook(py::module& mod) py::arg("name") = mx::EMPTY_STRING) .def("getPropertySetAssign", &mx::Look::getPropertySetAssign) .def("getPropertySetAssigns", &mx::Look::getPropertySetAssigns) + .def("getActivePropertySetAssigns", &mx::Look::getActivePropertySetAssigns) .def("removePropertySetAssign", &mx::Look::removePropertySetAssign) + .def("addVariantAssign", &mx::Look::addVariantAssign, + py::arg("name") = mx::EMPTY_STRING) + .def("getVariantAssign", &mx::Look::getVariantAssign) + .def("getVariantAssigns", &mx::Look::getVariantAssigns) + .def("getActiveVariantAssigns", &mx::Look::getActiveVariantAssigns) + .def("removeVariantAssign", &mx::Look::removeVariantAssign) .def("addVisibility", &mx::Look::addVisibility, py::arg("name") = mx::EMPTY_STRING) .def("getVisibility", &mx::Look::getVisibility) diff --git a/source/PyMaterialX/PyVariant.cpp b/source/PyMaterialX/PyVariant.cpp index 307f6e05d8..3439298102 100644 --- a/source/PyMaterialX/PyVariant.cpp +++ b/source/PyMaterialX/PyVariant.cpp @@ -22,4 +22,13 @@ void bindPyVariant(py::module& mod) .def("getVariants", &mx::VariantSet::getVariants) .def("removeVariant", &mx::VariantSet::removeVariant) .def_readonly_static("CATEGORY", &mx::VariantSet::CATEGORY); + + py::class_(mod, "VariantAssign") + .def("setVariantSetString", &mx::VariantAssign::setVariantSetString) + .def("hasVariantSetString", &mx::VariantAssign::hasVariantSetString) + .def("getVariantSetString", &mx::VariantAssign::getVariantSetString) + .def("setVariantString", &mx::VariantAssign::setVariantString) + .def("hasVariantString", &mx::VariantAssign::hasVariantString) + .def("getVariantString", &mx::VariantAssign::getVariantString) + .def_readonly_static("CATEGORY", &mx::VariantAssign::CATEGORY); } From b0d7ae1db9d9dffe393b6e736b046db31bbf90cc Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 May 2018 12:17:13 -0700 Subject: [PATCH 07/27] Updates for geometry and collection matching - Add Collection::matchesGeomString, which returns true if the Collection and the given geometry string have any geometries in common. - Add Material::getGeometryBindings, which returns the vector of MaterialAssign elements that bind the material to the given geometry string. - Remove Material::getReferencingMaterialAssigns (deprecated in Python). - Remove Material::getBoundGeomStrings and Material::getBoundGeomCollections. - Additional minor fixes for const correctness and consistency. --- python/MaterialX/main.py | 6 ++ python/MaterialXTest/main.py | 9 ++- source/MaterialXCore/Element.cpp | 2 +- source/MaterialXCore/Geom.cpp | 94 +++++++++++++++++++++- source/MaterialXCore/Geom.h | 125 +++++++++++++++++++++++------- source/MaterialXCore/Material.cpp | 41 +++------- source/MaterialXCore/Material.h | 25 ++---- source/MaterialXCore/Property.h | 4 +- source/MaterialXFormat/File.cpp | 23 +++--- source/MaterialXTest/Geom.cpp | 34 ++++++-- source/MaterialXTest/Look.cpp | 7 +- source/PyMaterialX/PyGeom.cpp | 10 ++- source/PyMaterialX/PyMaterial.cpp | 5 +- 13 files changed, 272 insertions(+), 113 deletions(-) diff --git a/python/MaterialX/main.py b/python/MaterialX/main.py index 9368284400..abc7ec6454 100644 --- a/python/MaterialX/main.py +++ b/python/MaterialX/main.py @@ -180,10 +180,16 @@ def _getReferencedShaderDefs(self): warnings.warn("This function is deprecated; call Material.getShaderNodeDefs instead.", DeprecationWarning, stacklevel = 2) return self.getShaderNodeDefs() +def _getReferencingMaterialAssigns(self): + "(Deprecated) Return a list of all material assigns that reference this material." + warnings.warn("This function is deprecated; call Material.getGeometryBindings instead.", DeprecationWarning, stacklevel = 2) + return self.getGeometryBindings() + Material.addOverride = _addOverride Material.setOverrideValue = _setOverrideValue Material.addShaderRef = _addShaderRef Material.getReferencedShaderDefs = _getReferencedShaderDefs +Material.getReferencingMaterialAssigns = _getReferencingMaterialAssigns # diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index 9368086930..6c1c2e3de5 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -270,9 +270,10 @@ def test_BuildDocument(self): # Bind the material to a geometry string. matAssign1 = look.addMaterialAssign("matAssign1", material.getName()) - self.assertTrue(material.getReferencingMaterialAssigns()[0] == matAssign1) matAssign1.setGeom("/robot1") - self.assertTrue(material.getBoundGeomStrings()[0] == "/robot1") + self.assertTrue(matAssign1.getReferencedMaterial() == material) + self.assertTrue(len(material.getGeometryBindings("/robot1")) == 1) + self.assertTrue(len(material.getGeometryBindings("/robot2")) == 0) # Bind the material to a collection. matAssign2 = look.addMaterialAssign("matAssign2", material.getName()) @@ -280,7 +281,9 @@ def test_BuildDocument(self): collection.setIncludeGeom("/robot2") collection.setExcludeGeom("/robot2/left_arm") matAssign2.setCollection(collection) - self.assertTrue(material.getBoundGeomCollections()[0] == collection) + self.assertTrue(len(material.getGeometryBindings("/robot2")) == 1) + self.assertTrue(len(material.getGeometryBindings("/robot2/right_arm")) == 1) + self.assertTrue(len(material.getGeometryBindings("/robot2/left_arm")) == 0) # Create a property assignment. propertyAssign = look.addPropertyAssign("twosided") diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 3e34476761..6f366f5707 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -416,7 +416,7 @@ StringResolverPtr Element::createStringResolver(const string& geom) const ConstDocumentPtr doc = getDocument(); for (GeomInfoPtr geomInfo : doc->getGeomInfos()) { - if (!geomStringsMatch(geom, geomInfo->getGeom())) + if (!geomStringsMatch(geom, geomInfo->getActiveGeom())) continue; for (TokenPtr token : geomInfo->getTokens()) { diff --git a/source/MaterialXCore/Geom.cpp b/source/MaterialXCore/Geom.cpp index df4448e721..dd49dc2b2d 100644 --- a/source/MaterialXCore/Geom.cpp +++ b/source/MaterialXCore/Geom.cpp @@ -18,10 +18,10 @@ const string UV_TILE_TOKEN = "%UVTILE"; const string GeomElement::GEOM_ATTRIBUTE = "geom"; const string GeomElement::COLLECTION_ATTRIBUTE = "collection"; const string Collection::INCLUDE_GEOM_ATTRIBUTE = "includegeom"; -const string Collection::INCLUDE_COLLECTION_ATTRIBUTE = "includecollection"; const string Collection::EXCLUDE_GEOM_ATTRIBUTE = "excludegeom"; +const string Collection::INCLUDE_COLLECTION_ATTRIBUTE = "includecollection"; -bool geomStringsMatch(const string& geom1, const string& geom2) +bool geomStringsMatch(const string& geom1, const string& geom2, bool contains) { vector paths1; for (const string& name1 : splitString(geom1, ARRAY_VALID_SEPARATORS)) @@ -33,7 +33,7 @@ bool geomStringsMatch(const string& geom1, const string& geom2) GeomPath path2(name2); for (const GeomPath& path1 : paths1) { - if (path2.isMatching(path1)) + if (path1.isMatching(path2, contains)) { return true; } @@ -42,6 +42,10 @@ bool geomStringsMatch(const string& geom1, const string& geom2) return false; } +// +// GeomElement methods +// + void GeomElement::setCollection(ConstCollectionPtr collection) { if (collection) @@ -59,4 +63,88 @@ CollectionPtr GeomElement::getCollection() const return getDocument()->getCollection(getCollectionString()); } +bool GeomElement::validate(string* message) const +{ + bool res = true; + if (hasCollectionString()) + { + validateRequire(getCollection() != nullptr, res, message, "Invalid collection string"); + } + return Element::validate(message) && res; +} + +// +// Collection methods +// + +void Collection::setIncludeCollection(ConstCollectionPtr collection) +{ + if (collection) + { + setIncludeCollectionString(collection->getName()); + } + else + { + removeAttribute(INCLUDE_COLLECTION_ATTRIBUTE); + } +} + +CollectionPtr Collection::getIncludeCollection() const +{ + return getDocument()->getCollection(getIncludeCollectionString()); +} + +bool Collection::hasIncludeCycle() const +{ + try + { + matchesGeomString(UNIVERSAL_GEOM_NAME); + } + catch (ExceptionFoundCycle&) + { + return true; + } + return false; +} + +bool Collection::matchesGeomString(const string& geom) const +{ + if (geomStringsMatch(getActiveExcludeGeom(), geom, true)) + { + return false; + } + if (geomStringsMatch(getActiveIncludeGeom(), geom)) + { + return true; + } + + std::set includedSet; + ConstCollectionPtr included = getIncludeCollection(); + while (included) + { + if (includedSet.count(included)) + { + throw ExceptionFoundCycle("Encountered a cycle in collection: " + getName()); + } + includedSet.insert(included); + included = included->getIncludeCollection(); + } + for (ConstCollectionPtr collection : includedSet) + { + if (collection->matchesGeomString(geom)) + { + return true; + } + } + + return false; +} + +bool Collection::validate(string* message) const +{ + bool res = true; + validateRequire(!hasIncludeCycle(), res, message, "Cycle in collection include chain"); + return Element::validate(message) && res; +} + } // namespace MaterialX diff --git a/source/MaterialXCore/Geom.h b/source/MaterialXCore/Geom.h index 44ca212107..c31c432b5c 100644 --- a/source/MaterialXCore/Geom.h +++ b/source/MaterialXCore/Geom.h @@ -90,12 +90,19 @@ class GeomPath } /// Return true if there is any geometry in common between the two paths. - bool isMatching(const GeomPath& rhs) const + /// @param rhs A second geometry path to be compared with this one + /// @param contains If true, then we require that the first path completely + /// contains the second one. + bool isMatching(const GeomPath& rhs, bool contains = false) const { if (_empty || rhs._empty) { return false; } + if (contains && _vec.size() > rhs._vec.size()) + { + return false; + } size_t minSize = std::min(_vec.size(), rhs._vec.size()); for (size_t i = 0; i < minSize; i++) { @@ -149,7 +156,7 @@ class GeomElement : public Element } /// Return true if this element has a geometry string. - bool hasGeom() + bool hasGeom() const { return hasAttribute(GEOM_ATTRIBUTE); } @@ -160,6 +167,15 @@ class GeomElement : public Element return getAttribute(GEOM_ATTRIBUTE); } + /// Return the active geometry string of this element, taking all geometry + /// string substitutions at this scope into account. + string getActiveGeom() const + { + return hasGeom() ? + createStringResolver()->resolve(getGeom(), GEOMNAME_TYPE_STRING) : + EMPTY_STRING; + } + /// @} /// @name Collection /// @{ @@ -171,7 +187,7 @@ class GeomElement : public Element } /// Return true if this element has a collection string. - bool hasCollectionString() + bool hasCollectionString() const { return hasAttribute(COLLECTION_ATTRIBUTE); } @@ -189,6 +205,14 @@ class GeomElement : public Element CollectionPtr getCollection() const; /// @} + /// @name Validation + /// @{ + + /// Validate that the given element tree, including all descendants, is + /// consistent with the MaterialX specification. + bool validate(string* message = nullptr) const override; + + /// @} public: static const string GEOM_ATTRIBUTE; @@ -313,8 +337,6 @@ class GeomAttr : public ValueElement /// @class Collection /// A collection element within a Document. -/// @todo Add a Collection::containsGeom method that computes whether the -/// given Collection contains the specified geometry. class Collection : public Element { public: @@ -334,7 +356,7 @@ class Collection : public Element } /// Return true if this element has an include geometry string. - bool hasIncludeGeom() + bool hasIncludeGeom() const { return hasAttribute(INCLUDE_GEOM_ATTRIBUTE); } @@ -345,58 +367,101 @@ class Collection : public Element return getAttribute(INCLUDE_GEOM_ATTRIBUTE); } + /// Return the active include geometry string of this element, taking all + /// geometry string substitutions at this scope into account. + string getActiveIncludeGeom() const + { + return hasIncludeGeom() ? + createStringResolver()->resolve(getIncludeGeom(), GEOMNAME_TYPE_STRING) : + EMPTY_STRING; + } + + /// @} + /// @name Exclude Geometry + /// @{ + + /// Set the exclude geometry string of this element. + void setExcludeGeom(const string& geom) + { + setAttribute(EXCLUDE_GEOM_ATTRIBUTE, geom); + } + + /// Return true if this element has an exclude geometry string. + bool hasExcludeGeom() const + { + return hasAttribute(EXCLUDE_GEOM_ATTRIBUTE); + } + + /// Return the exclude geometry string of this element. + const string& getExcludeGeom() const + { + return getAttribute(EXCLUDE_GEOM_ATTRIBUTE); + } + + /// Return the active exclude geometry string of this element, taking all + /// geometry string substitutions at this scope into account. + string getActiveExcludeGeom() const + { + return hasExcludeGeom() ? + createStringResolver()->resolve(getExcludeGeom(), GEOMNAME_TYPE_STRING) : + EMPTY_STRING; + } + /// @} /// @name Include Collection /// @{ /// Set the include collection string of this element. - void setIncludeCollection(const string& collection) + void setIncludeCollectionString(const string& collection) { setAttribute(INCLUDE_COLLECTION_ATTRIBUTE, collection); } /// Return true if this element has an include collection string. - bool hasIncludeCollection() + bool hasIncludeCollectionString() const { return hasAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } /// Return the include collection string of this element. - const string& getIncludeCollection() const + const string& getIncludeCollectionString() const { return getAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } + /// Set the include collection for this element. + void setIncludeCollection(ConstCollectionPtr collection); + + /// Return the include collection for this element. + CollectionPtr getIncludeCollection() const; + + /// Return true if the include chain for this element contains a cycle. + bool hasIncludeCycle() const; + /// @} - /// @name Exclude Geometry + /// @name Geometry Matching /// @{ - /// Set the exclude geometry string of this element. - void setExcludeGeom(const string& geom) - { - setAttribute(EXCLUDE_GEOM_ATTRIBUTE, geom); - } + /// Return true if this collection and the given geometry string have any + /// geometries in common. + /// @throws ExceptionFoundCycle if a cycle is encountered. + bool matchesGeomString(const string& geom) const; - /// Return true if this element has an exclude geometry string. - bool hasExcludeGeom() - { - return hasAttribute(EXCLUDE_GEOM_ATTRIBUTE); - } + /// @} + /// @name Validation + /// @{ - /// Return the exclude geometry string of this element. - const string& getExcludeGeom() const - { - return getAttribute(EXCLUDE_GEOM_ATTRIBUTE); - } + /// Validate that the given element tree, including all descendants, is + /// consistent with the MaterialX specification. + bool validate(string* message = nullptr) const override; /// @} public: static const string CATEGORY; static const string INCLUDE_GEOM_ATTRIBUTE; - static const string INCLUDE_COLLECTION_ATTRIBUTE; static const string EXCLUDE_GEOM_ATTRIBUTE; - static const string EXCLUDE_COLLECTION_ATTRIBUTE; + static const string INCLUDE_COLLECTION_ATTRIBUTE; }; template GeomAttrPtr GeomInfo::setGeomAttrValue(const string& name, @@ -416,9 +481,11 @@ template GeomAttrPtr GeomInfo::setGeomAttrValue(const string& name, /// An empty geometry string matches no geometries, while the universal geometry /// string "/" matches all non-empty geometries. /// +/// If the contains argument is set to true, then we require that a geom path +/// in the first string completely contains a geom path in the second string. +/// /// @todo Geometry name expressions are not yet supported. -/// @relates GeomInfo -bool geomStringsMatch(const string& geom1, const string& geom2); +bool geomStringsMatch(const string& geom1, const string& geom2, bool contains = false); } // namespace MaterialX diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index 1410e178dd..5c1060c09d 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -60,7 +60,7 @@ vector Material::getShaderNodeDefs(const string& target, const strin return nodeDefs; } -vector Material::getReferencingMaterialAssigns() const +vector Material::getGeometryBindings(const string& geom) const { vector matAssigns; for (LookPtr look : getDocument()->getLooks()) @@ -69,7 +69,17 @@ vector Material::getReferencingMaterialAssigns() const { if (matAssign->getReferencedMaterial() == getSelf()) { - matAssigns.push_back(matAssign); + if (geomStringsMatch(geom, matAssign->getActiveGeom())) + { + matAssigns.push_back(matAssign); + continue; + } + CollectionPtr coll = matAssign->getCollection(); + if (coll && coll->matchesGeomString(geom)) + { + matAssigns.push_back(matAssign); + continue; + } } } } @@ -108,33 +118,6 @@ vector Material::getPrimaryShaderInputs(const string& target, const st return res; } -vector Material::getBoundGeomStrings() const -{ - vector geomStrings; - for (MaterialAssignPtr matAssign : getReferencingMaterialAssigns()) - { - if (matAssign->hasGeom()) - { - geomStrings.push_back(matAssign->getGeom()); - } - } - return geomStrings; -} - -vector Material::getBoundGeomCollections() const -{ - vector collections; - for (MaterialAssignPtr matAssign : getReferencingMaterialAssigns()) - { - CollectionPtr collection = matAssign->getCollection(); - if (collection) - { - collections.push_back(collection); - } - } - return collections; -} - bool Material::validate(string* message) const { bool res = true; diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index 213f7b4dac..3e6d65a5dd 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -11,6 +11,7 @@ #include +#include #include #include @@ -105,13 +106,6 @@ class Material : public Element vector getShaderNodeDefs(const string& target = EMPTY_STRING, const string& type = EMPTY_STRING) const; - /// @} - /// @name MaterialAssign References - /// @{ - - /// Return all MaterialAssign elements that reference this material. - vector getReferencingMaterialAssigns() const; - /// @} /// @name Primary Shader /// @{ @@ -172,17 +166,12 @@ class Material : public Element /// @name Geometry Bindings /// @{ - /// Return all geometry strings that are bound to this material by Look - /// elements. Note that this method only considers geometry strings, - /// not geometric collections. - /// @return A vector of geometry strings, each containing an array of - /// geom names. - vector getBoundGeomStrings() const; - - /// Return all geometry collections that are bound to this material by - /// Look elements. - /// @return A vector of shared pointers to Collection elements. - vector getBoundGeomCollections() const; + /// Return a vector of all MaterialAssign elements that bind this material + /// to the given geometry string. + /// @param geom The geometry for which material bindings should be returned. + /// By default, this argument is the universal geometry string "/", and + /// all material bindings are returned. + vector getGeometryBindings(const string& geom = UNIVERSAL_GEOM_NAME) const; /// @} /// @name Validation diff --git a/source/MaterialXCore/Property.h b/source/MaterialXCore/Property.h index b95cfea49c..8f65564ed7 100644 --- a/source/MaterialXCore/Property.h +++ b/source/MaterialXCore/Property.h @@ -72,7 +72,7 @@ class PropertyAssign : public ValueElement } /// Return true if this element has a geometry string. - bool hasGeom() + bool hasGeom() const { return hasAttribute(GEOM_ATTRIBUTE); } @@ -94,7 +94,7 @@ class PropertyAssign : public ValueElement } /// Return true if this element has a collection string. - bool hasCollectionString() + bool hasCollectionString() const { return hasAttribute(COLLECTION_ATTRIBUTE); } diff --git a/source/MaterialXFormat/File.cpp b/source/MaterialXFormat/File.cpp index b74c63adcb..5b07af6fd5 100644 --- a/source/MaterialXFormat/File.cpp +++ b/source/MaterialXFormat/File.cpp @@ -9,17 +9,14 @@ #define WIN32_LEAN_AND_MEAN #include #else -#include #include #include #endif -#if defined(__linux) -#include -#endif - #include -#include +#include +#include +#include namespace MaterialX { @@ -65,34 +62,34 @@ void FilePath::assign(const string& str, Format format) string FilePath::asString(Format format) const { - std::ostringstream stream; + string str; if (format == FormatPosix && isAbsolute()) { - stream << "/"; + str += "/"; } else if (format == FormatWindows && _type == TypeNetwork) { - stream << "\\\\"; + str += "\\\\"; } for (size_t i = 0; i < _vec.size(); i++) { - stream << _vec[i]; + str += _vec[i]; if (i + 1 < _vec.size()) { if (format == FormatPosix) { - stream << PREFERRED_SEPARATOR_POSIX; + str += PREFERRED_SEPARATOR_POSIX; } else { - stream << PREFERRED_SEPARATOR_WINDOWS; + str += PREFERRED_SEPARATOR_WINDOWS; } } } - return stream.str(); + return str; } FilePath FilePath::operator/(const FilePath& rhs) const diff --git a/source/MaterialXTest/Geom.cpp b/source/MaterialXTest/Geom.cpp index 6f2529ac51..2f76878cdb 100644 --- a/source/MaterialXTest/Geom.cpp +++ b/source/MaterialXTest/Geom.cpp @@ -11,12 +11,17 @@ namespace mx = MaterialX; TEST_CASE("Geom strings", "[geom]") { + // Test for overlapping paths. REQUIRE(mx::geomStringsMatch("/", "/robot1")); REQUIRE(mx::geomStringsMatch("/robot1", "/robot1/left_arm")); REQUIRE(mx::geomStringsMatch("/robot1, /robot2", "/robot2/left_arm")); REQUIRE(!mx::geomStringsMatch("", "/robot1")); REQUIRE(!mx::geomStringsMatch("/robot1", "/robot2")); REQUIRE(!mx::geomStringsMatch("/robot1, /robot2", "/robot3")); + + // Test that one path contains another. + REQUIRE(mx::geomStringsMatch("/", "/robot1", true)); + REQUIRE(!mx::geomStringsMatch("/robot1", "/", true)); } TEST_CASE("Geom elements", "[geom]") @@ -48,12 +53,27 @@ TEST_CASE("Geom elements", "[geom]") REQUIRE(fileParam->getResolvedValueString(resolver1) == "folder/robot01_diffuse_1001.tif"); REQUIRE(fileParam->getResolvedValueString(resolver2) == "folder/robot02_diffuse_1002.tif"); + // Create a base collection. + mx::CollectionPtr collection1 = doc->addCollection("collection1"); + collection1->setIncludeGeom("/scene1"); + collection1->setExcludeGeom("/scene1/sphere2"); + REQUIRE(collection1->matchesGeomString("/scene1/sphere1")); + REQUIRE(!collection1->matchesGeomString("/scene1/sphere2")); + + // Create a derived collection. + mx::CollectionPtr collection2 = doc->addCollection("collection2"); + collection2->setIncludeCollection(collection1); + REQUIRE(collection2->matchesGeomString("/scene1/sphere1")); + REQUIRE(!collection2->matchesGeomString("/scene1/sphere2")); + + // Create and test an include cycle. + collection1->setIncludeCollection(collection2); + REQUIRE(!doc->validate()); + collection1->setIncludeCollection(nullptr); + REQUIRE(doc->validate()); + // Test geometry string substitutions. - mx::CollectionPtr collection = doc->addCollection("collection1"); - collection->setIncludeGeom("/group1/sphere1"); - collection->setGeomPrefix("/root"); - mx::StringResolverPtr resolver3 = collection->createStringResolver(); - resolver3->setGeomNameSubstitution("group1", "group2"); - std::string resolved = resolver3->resolve(collection->getIncludeGeom(), mx::GEOMNAME_TYPE_STRING); - REQUIRE(resolved == "/root/group2/sphere1"); + collection1->setGeomPrefix("/root"); + REQUIRE(collection1->matchesGeomString("/root/scene1")); + REQUIRE(!collection1->matchesGeomString("/root/scene2")); } diff --git a/source/MaterialXTest/Look.cpp b/source/MaterialXTest/Look.cpp index 9cf7487a8d..c65d9d2ab3 100644 --- a/source/MaterialXTest/Look.cpp +++ b/source/MaterialXTest/Look.cpp @@ -24,7 +24,8 @@ TEST_CASE("Look", "[look]") mx::MaterialAssignPtr matAssign1 = look->addMaterialAssign("matAssign1", material->getName()); matAssign1->setGeom("/robot1"); REQUIRE(matAssign1->getReferencedMaterial() == material); - REQUIRE(material->getBoundGeomStrings()[0] == "/robot1"); + REQUIRE(material->getGeometryBindings("/robot1").size() == 1); + REQUIRE(material->getGeometryBindings("/robot2").size() == 0); // Bind the material to a geometric collection. mx::MaterialAssignPtr matAssign2 = look->addMaterialAssign("matAssign2", material->getName()); @@ -32,7 +33,9 @@ TEST_CASE("Look", "[look]") collection->setIncludeGeom("/robot2"); collection->setExcludeGeom("/robot2/left_arm"); matAssign2->setCollection(collection); - REQUIRE(material->getBoundGeomCollections()[0] == collection); + REQUIRE(material->getGeometryBindings("/robot2").size() == 1); + REQUIRE(material->getGeometryBindings("/robot2/right_arm").size() == 1); + REQUIRE(material->getGeometryBindings("/robot2/left_arm").size() == 0); // Create a property assignment. mx::PropertyAssignPtr propertyAssign = look->addPropertyAssign("twosided"); diff --git a/source/PyMaterialX/PyGeom.cpp b/source/PyMaterialX/PyGeom.cpp index e1be7e0b0b..38ebbe0751 100644 --- a/source/PyMaterialX/PyGeom.cpp +++ b/source/PyMaterialX/PyGeom.cpp @@ -57,12 +57,16 @@ void bindPyGeom(py::module& mod) .def("setIncludeGeom", &mx::Collection::setIncludeGeom) .def("hasIncludeGeom", &mx::Collection::hasIncludeGeom) .def("getIncludeGeom", &mx::Collection::getIncludeGeom) - .def("setIncludeCollection", &mx::Collection::setIncludeCollection) - .def("hasIncludeCollection", &mx::Collection::hasIncludeCollection) - .def("getIncludeCollection", &mx::Collection::getIncludeCollection) .def("setExcludeGeom", &mx::Collection::setExcludeGeom) .def("hasExcludeGeom", &mx::Collection::hasExcludeGeom) .def("getExcludeGeom", &mx::Collection::getExcludeGeom) + .def("setIncludeCollectionString", &mx::Collection::setIncludeCollectionString) + .def("hasIncludeCollectionString", &mx::Collection::hasIncludeCollectionString) + .def("getIncludeCollectionString", &mx::Collection::getIncludeCollectionString) + .def("setIncludeCollection", &mx::Collection::setIncludeCollection) + .def("getIncludeCollection", &mx::Collection::getIncludeCollection) + .def("hasIncludeCycle", &mx::Collection::hasIncludeCycle) + .def("matchesGeomString", &mx::Collection::matchesGeomString) .def_readonly_static("CATEGORY", &mx::Collection::CATEGORY); mod.def("geomStringsMatch", &mx::geomStringsMatch); diff --git a/source/PyMaterialX/PyMaterial.cpp b/source/PyMaterialX/PyMaterial.cpp index 471b88bfa6..826d76d6b4 100644 --- a/source/PyMaterialX/PyMaterial.cpp +++ b/source/PyMaterialX/PyMaterial.cpp @@ -23,7 +23,6 @@ void bindPyMaterial(py::module& mod) .def("removeShaderRef", &mx::Material::removeShaderRef) .def("getShaderNodeDefs", &mx::Material::getShaderNodeDefs, py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) - .def("getReferencingMaterialAssigns", &mx::Material::getReferencingMaterialAssigns) .def("getPrimaryShaderNodeDef", &mx::Material::getPrimaryShaderNodeDef, py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) .def("getPrimaryShaderName", &mx::Material::getPrimaryShaderName, @@ -32,8 +31,8 @@ void bindPyMaterial(py::module& mod) py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) .def("getPrimaryShaderInputs", &mx::Material::getPrimaryShaderInputs, py::arg("target") = mx::EMPTY_STRING, py::arg("type") = mx::EMPTY_STRING) - .def("getBoundGeomStrings", &mx::Material::getBoundGeomStrings) - .def("getBoundGeomCollections", &mx::Material::getBoundGeomCollections) + .def("getGeometryBindings", &mx::Material::getGeometryBindings, + py::arg("geom") = mx::UNIVERSAL_GEOM_NAME) .def_readonly_static("CATEGORY", &mx::Material::CATEGORY); py::class_(mod, "BindParam") From bd174836c320ceab0b230c67e20a2c32dab63a50 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 18 May 2018 13:02:57 -0700 Subject: [PATCH 08/27] Update changelog for work in progress on v1.36 --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b82de46c3d..91bcf7d522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Change Log +## [1.36.0] - Development + +Updating the MaterialX library to the v1.36 specification. + +### Added +- Added support for inheritance attributes on MaterialX\:\:Material and MaterialX\:\:Look. +- Added support for include and exclude attributes on MaterialX\:\:Collection. +- Added support for MaterialX\:\:NodeDef inheritance. +- Added the MaterialX\:\:Variant, MaterialX\:\:VariantSet, and MaterialX\:\:VariantAssign classes. +- Added the MaterialX\:\:Token class for string substitutions. +- Added the MaterialX\:\:GeomPath class for geometry name comparisons. +- Added the Collection\:\:matchesGeomString method, for testing matches between collections and geometries. +- Added the Material\:\:getGeometryBindings method, for finding the bindings of a material to specific geometries. + +### Changed +- Removed the MaterialX\:\:MaterialInherit and MaterialX\:\:LookInherit classes. +- Removed the MaterialX\:\:CollectionAdd and MaterialX\:\:CollectionRemove classes. +- Removed the MaterialX\:\:Override class and support for public names. +- Removed the Material::getReferencingMaterialAssigns method (deprecated in Python). + ## [1.35.5] - 2018-05-07 ### Added From 9a1fb7b1cd95c583dfaf8064f57d677a5ca98b47 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 19 May 2018 16:10:49 -0700 Subject: [PATCH 09/27] Initial support for namespaces in MaterialX v1.36 - Add Element methods setNamespace, hasNamespace, getNamespace, getQualifiedName, and resolveRootNameReference. - Add NodeGraph method addNodeInstance --- source/MaterialXCore/Definition.cpp | 7 ++- source/MaterialXCore/Document.cpp | 18 +++++--- source/MaterialXCore/Element.cpp | 3 +- source/MaterialXCore/Element.h | 51 ++++++++++++++++++++-- source/MaterialXCore/Geom.cpp | 4 +- source/MaterialXCore/Look.cpp | 2 +- source/MaterialXCore/Material.cpp | 10 +++-- source/MaterialXCore/Node.cpp | 7 ++- source/MaterialXCore/Node.h | 6 +++ source/MaterialXCore/Property.cpp | 2 +- source/MaterialXCore/Types.cpp | 1 + source/MaterialXCore/Types.h | 1 + source/MaterialXCore/Util.cpp | 2 +- source/MaterialXTest/Node.cpp | 14 +++--- source/MaterialXTest/XmlIo.cpp | 68 ++++++++++++----------------- source/PyMaterialX/PyElement.cpp | 4 ++ source/PyMaterialX/PyNode.cpp | 2 + 17 files changed, 131 insertions(+), 71 deletions(-) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 08f3f06777..97635b4c23 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -34,7 +34,10 @@ const string Implementation::LANGUAGE_ATTRIBUTE = "language"; InterfaceElementPtr NodeDef::getImplementation(const string& target, const string& language) const { - for (InterfaceElementPtr interface : getDocument()->getMatchingImplementations(getName())) + vector interfaces = getDocument()->getMatchingImplementations(getQualifiedName(getName())); + vector secondary = getDocument()->getMatchingImplementations(getName()); + interfaces.insert(interfaces.end(), secondary.begin(), secondary.end()); + for (InterfaceElementPtr interface : interfaces) { if (!targetStringsMatch(interface->getTarget(), target)) { @@ -93,7 +96,7 @@ bool NodeDef::validate(string* message) const NodeDefPtr Implementation::getNodeDef() const { - return getDocument()->getNodeDef(getNodeDefString()); + return resolveRootNameReference(getNodeDefString()); } } // namespace MaterialX diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index db60f62c7f..bf6ef25ade 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -76,7 +76,6 @@ class Document::Cache for (ElementPtr elem : doc.lock()->traverseTree()) { PortElementPtr portElem = elem->asA(); - ValueElementPtr valueElem = elem->asA(); NodeDefPtr nodeDef = elem->asA(); NodeGraphPtr nodeGraph = elem->asA(); ImplementationPtr implementation = elem->asA(); @@ -84,25 +83,25 @@ class Document::Cache if (portElem && portElem->hasNodeName()) { portElementMap.insert(std::pair( - portElem->getNodeName(), + portElem->getQualifiedName(portElem->getNodeName()), portElem)); } if (nodeDef && nodeDef->hasNodeString()) { nodeDefMap.insert(std::pair( - nodeDef->getNodeString(), + nodeDef->getQualifiedName(nodeDef->getNodeString()), nodeDef)); } if (nodeGraph && nodeGraph->hasNodeDefString()) { implementationMap.insert(std::pair( - nodeGraph->getNodeDefString(), + nodeGraph->getQualifiedName(nodeGraph->getNodeDefString()), nodeGraph)); } if (implementation && implementation->hasNodeDefString()) { implementationMap.insert(std::pair( - implementation->getNodeDefString(), + implementation->getQualifiedName(implementation->getNodeDefString()), implementation)); } } @@ -151,6 +150,9 @@ void Document::initialize() void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOptions) { + string libraryPrefix = library->hasNamespace() ? + library->getNamespace() + NAME_PREFIX_SEPARATOR : + EMPTY_STRING; bool skipDuplicateElements = copyOptions && copyOptions->skipDuplicateElements; bool copySourceUris = copyOptions && copyOptions->copySourceUris; for (ElementPtr child : library->getChildren()) @@ -160,8 +162,12 @@ void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOp { continue; } - ElementPtr childCopy = addChildOfCategory(child->getCategory(), childName); + ElementPtr childCopy = addChildOfCategory(child->getCategory(), libraryPrefix + childName); childCopy->copyContentFrom(child, copyOptions); + if (!childCopy->hasNamespace() && library->hasNamespace()) + { + childCopy->setNamespace(library->getNamespace()); + } if (copySourceUris && !childCopy->hasSourceUri()) { childCopy->setSourceUri(library->getSourceUri()); diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 6f366f5707..029587d191 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -17,8 +17,9 @@ const string Element::TYPE_ATTRIBUTE = "type"; const string Element::FILE_PREFIX_ATTRIBUTE = "fileprefix"; const string Element::GEOM_PREFIX_ATTRIBUTE = "geomprefix"; const string Element::COLOR_SPACE_ATTRIBUTE = "colorspace"; -const string Element::INHERIT_ATTRIBUTE = "inherit"; const string Element::TARGET_ATTRIBUTE = "target"; +const string Element::INHERIT_ATTRIBUTE = "inherit"; +const string Element::NAMESPACE_ATTRIBUTE = "namespace"; const string ValueElement::VALUE_ATTRIBUTE = "value"; const string ValueElement::INTERFACE_NAME_ATTRIBUTE = "interfacename"; const string ValueElement::IMPLEMENTATION_NAME_ATTRIBUTE = "implname"; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 15e2447dd5..cfc16382ad 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -109,7 +109,6 @@ class Element : public std::enable_shared_from_this void setName(const string& name); /// Return the element's name string. - /// @todo The MaterialX notion of namespaces is not yet supported. const string& getName() const { return _name; @@ -298,7 +297,7 @@ class Element : public std::enable_shared_from_this /// Return the element, if any, that this one directly inherits from. ElementPtr getInheritsFrom() const { - return getRoot()->getChild(getInheritString()); + return resolveRootNameReference(getInheritString()); } /// Return true if this element has the given element as an inherited base, @@ -308,6 +307,51 @@ class Element : public std::enable_shared_from_this /// Return true if the inheritance chain for this element contains a cycle. bool hasInheritanceCycle() const; + /// @} + /// @name Namespace + /// @{ + + /// Set the namespace of this element. + void setNamespace(const string& inherit) + { + setAttribute(NAMESPACE_ATTRIBUTE, inherit); + } + + /// Return true if this element has a namespace. + bool hasNamespace() const + { + return hasAttribute(NAMESPACE_ATTRIBUTE); + } + + /// Return the namespace of this element. + const string& getNamespace() const + { + return getAttribute(NAMESPACE_ATTRIBUTE); + } + + /// Return a qualified version of the given name, taking the namespace at the + /// scope of this element into account. + string getQualifiedName(const string& name) const + { + for (ConstElementPtr elem : traverseAncestors()) + { + if (elem->getRoot() != elem && elem->hasNamespace()) + { + return elem->getNamespace() + NAME_PREFIX_SEPARATOR + name; + } + } + return name; + } + + /// Resolve a reference to a named element at the root scope of this document, + /// taking the namespace at the scope of this element into account. + template shared_ptr resolveRootNameReference(const string& name) const + { + ConstElementPtr root = getRoot(); + shared_ptr child = root->getChildOfType(getQualifiedName(name)); + return child ? child : root->getChildOfType(name); + } + /// @} /// @name Subclass /// @{ @@ -718,8 +762,9 @@ class Element : public std::enable_shared_from_this static const string FILE_PREFIX_ATTRIBUTE; static const string GEOM_PREFIX_ATTRIBUTE; static const string COLOR_SPACE_ATTRIBUTE; - static const string INHERIT_ATTRIBUTE; static const string TARGET_ATTRIBUTE; + static const string INHERIT_ATTRIBUTE; + static const string NAMESPACE_ATTRIBUTE; protected: virtual void registerChildElement(ElementPtr child); diff --git a/source/MaterialXCore/Geom.cpp b/source/MaterialXCore/Geom.cpp index dd49dc2b2d..c444e9ed33 100644 --- a/source/MaterialXCore/Geom.cpp +++ b/source/MaterialXCore/Geom.cpp @@ -60,7 +60,7 @@ void GeomElement::setCollection(ConstCollectionPtr collection) CollectionPtr GeomElement::getCollection() const { - return getDocument()->getCollection(getCollectionString()); + return resolveRootNameReference(getCollectionString()); } bool GeomElement::validate(string* message) const @@ -91,7 +91,7 @@ void Collection::setIncludeCollection(ConstCollectionPtr collection) CollectionPtr Collection::getIncludeCollection() const { - return getDocument()->getCollection(getIncludeCollectionString()); + return resolveRootNameReference(getIncludeCollectionString()); } bool Collection::hasIncludeCycle() const diff --git a/source/MaterialXCore/Look.cpp b/source/MaterialXCore/Look.cpp index 635c029b41..3389831b68 100644 --- a/source/MaterialXCore/Look.cpp +++ b/source/MaterialXCore/Look.cpp @@ -91,7 +91,7 @@ vector Look::getActiveVisibilities() const MaterialPtr MaterialAssign::getReferencedMaterial() const { - return getRoot()->getChildOfType(getMaterial()); + return resolveRootNameReference(getMaterial()); } } // namespace MaterialX diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index 5c1060c09d..b5c2626f16 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -148,7 +148,7 @@ void BindInput::setConnectedOutput(ConstOutputPtr output) OutputPtr BindInput::getConnectedOutput() const { - NodeGraphPtr nodeGraph = getRoot()->getChildOfType(getNodeGraphString()); + NodeGraphPtr nodeGraph = resolveRootNameReference(getNodeGraphString()); if (nodeGraph) { OutputPtr output = nodeGraph->getOutput(getOutputString()); @@ -168,11 +168,13 @@ NodeDefPtr ShaderRef::getNodeDef() const { if (hasNodeDefString()) { - return getDocument()->getNodeDef(getNodeDefString()); + return resolveRootNameReference(getNodeDefString()); } if (hasNodeString()) { - vector nodeDefs = getDocument()->getMatchingNodeDefs(getNodeString()); + vector nodeDefs = getDocument()->getMatchingNodeDefs(getQualifiedName(getNodeString())); + vector secondary = getDocument()->getMatchingNodeDefs(getNodeString()); + nodeDefs.insert(nodeDefs.end(), secondary.begin(), secondary.end()); return nodeDefs.empty() ? NodeDefPtr() : nodeDefs[0]; } return NodeDefPtr(); @@ -182,7 +184,7 @@ bool ShaderRef::validate(string* message) const { bool res = true; NodeDefPtr nodeDef = getNodeDef(); - TypeDefPtr typeDef = nodeDef ? getDocument()->getTypeDef(nodeDef->getType()) : TypeDefPtr(); + TypeDefPtr typeDef = nodeDef ? resolveRootNameReference(nodeDef->getType()) : TypeDefPtr(); if (!nodeDef) { validateRequire(!hasNodeString() && !hasNodeDefString(), res, message, "Shader reference to a non-existent nodedef"); diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index f9e9390059..62d768f559 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -70,7 +70,10 @@ string Node::getConnectedNodeName(const string& inputName) const NodeDefPtr Node::getNodeDef(const string& target) const { - for (NodeDefPtr nodeDef : getDocument()->getMatchingNodeDefs(getCategory())) + vector nodeDefs = getDocument()->getMatchingNodeDefs(getQualifiedName(getCategory())); + vector secondary = getDocument()->getMatchingNodeDefs(getCategory()); + nodeDefs.insert(nodeDefs.end(), secondary.begin(), secondary.end()); + for (NodeDefPtr nodeDef : nodeDefs) { if (targetStringsMatch(target, nodeDef->getTarget()) && isTypeCompatible(nodeDef)) @@ -122,7 +125,7 @@ bool Node::validate(string* message) const NodeDefPtr NodeGraph::getNodeDef() const { - return getDocument()->getNodeDef(getNodeDefString()); + return resolveRootNameReference(getNodeDefString()); } void NodeGraph::flattenSubgraphs(const string& target) diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index 228894b92f..295d9be485 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -193,6 +193,12 @@ class NodeGraph : public InterfaceElement return node; } + /// Add a Node that is an instance of the given NodeDef. + NodePtr addNodeInstance(ConstNodeDefPtr nodeDef, const string& name = EMPTY_STRING) + { + return addNode(nodeDef->getNodeString(), name, nodeDef->getType()); + } + /// Return the Node, if any, with the given name. NodePtr getNode(const string& name) const { diff --git a/source/MaterialXCore/Property.cpp b/source/MaterialXCore/Property.cpp index eb3dc30937..d6040d6fa5 100644 --- a/source/MaterialXCore/Property.cpp +++ b/source/MaterialXCore/Property.cpp @@ -27,7 +27,7 @@ void PropertyAssign::setCollection(ConstCollectionPtr collection) CollectionPtr PropertyAssign::getCollection() const { - return getDocument()->getCollection(getCollectionString()); + return resolveRootNameReference(getCollectionString()); } } // namespace MaterialX diff --git a/source/MaterialXCore/Types.cpp b/source/MaterialXCore/Types.cpp index 5201b75e43..95e28d30c3 100644 --- a/source/MaterialXCore/Types.cpp +++ b/source/MaterialXCore/Types.cpp @@ -19,6 +19,7 @@ const string MULTI_OUTPUT_TYPE_STRING = "multioutput"; const string NONE_TYPE_STRING = "none"; const string VALUE_STRING_TRUE = "true"; const string VALUE_STRING_FALSE = "false"; +const string NAME_PREFIX_SEPARATOR = ":"; const string NAME_PATH_SEPARATOR = "/"; const string ARRAY_VALID_SEPARATORS = ", "; const string ARRAY_PREFERRED_SEPARATOR = ", "; diff --git a/source/MaterialXCore/Types.h b/source/MaterialXCore/Types.h index ba6e2792e4..06b7120840 100644 --- a/source/MaterialXCore/Types.h +++ b/source/MaterialXCore/Types.h @@ -25,6 +25,7 @@ extern const string MULTI_OUTPUT_TYPE_STRING; extern const string NONE_TYPE_STRING; extern const string VALUE_STRING_TRUE; extern const string VALUE_STRING_FALSE; +extern const string NAME_PREFIX_SEPARATOR; extern const string NAME_PATH_SEPARATOR; extern const string ARRAY_VALID_SEPARATORS; extern const string ARRAY_PREFERRED_SEPARATOR; diff --git a/source/MaterialXCore/Util.cpp b/source/MaterialXCore/Util.cpp index 9487fb78b4..edb87857f2 100644 --- a/source/MaterialXCore/Util.cpp +++ b/source/MaterialXCore/Util.cpp @@ -24,7 +24,7 @@ const std::tuple LIBRARY_VERSION_TUPLE(MATERIALX_MAJOR_VERSION, bool invalidNameChar(char c) { - return !isalnum(c) && c != '_'; + return !isalnum(c) && c != '_' && c != ':'; } } // anonymous namespace diff --git a/source/MaterialXTest/Node.cpp b/source/MaterialXTest/Node.cpp index 0a9b2b15f4..9c19d4a395 100644 --- a/source/MaterialXTest/Node.cpp +++ b/source/MaterialXTest/Node.cpp @@ -67,14 +67,14 @@ TEST_CASE("Node", "[node]") REQUIRE(image->getDownstreamPorts()[0] == output2); // Create a custom nodedef. - mx::NodeDefPtr nodeDef = doc->addNodeDef("nodeDef1", "float", "turbulence3d"); - nodeDef->setNodeCategory(mx::PROCEDURAL_NODE_CATEGORY); - nodeDef->setParameterValue("octaves", 3); - nodeDef->setParameterValue("lacunarity", 2.0f); - nodeDef->setParameterValue("gain", 0.5f); + mx::NodeDefPtr customNodeDef = doc->addNodeDef("nodeDef1", "float", "turbulence3d"); + customNodeDef->setNodeCategory(mx::PROCEDURAL_NODE_CATEGORY); + customNodeDef->setParameterValue("octaves", 3); + customNodeDef->setParameterValue("lacunarity", 2.0f); + customNodeDef->setParameterValue("gain", 0.5f); // Reference the custom nodedef. - mx::NodePtr custom = nodeGraph->addNode("turbulence3d", "turbulence1", "float"); + mx::NodePtr custom = nodeGraph->addNodeInstance(customNodeDef); REQUIRE(custom->getNodeDef()->getNodeCategory() == mx::PROCEDURAL_NODE_CATEGORY); REQUIRE(custom->getParameterValue("octaves")->isA()); REQUIRE(custom->getParameterValue("octaves")->asA() == 3); @@ -130,7 +130,7 @@ TEST_CASE("Flatten", "[nodegraph]") mx::readFromXmlFile(doc, "SubGraphs.mtlx", "documents/Examples;documents/Libraries"); // Find the example graph. - mx::NodeGraphPtr graph = doc->getChildOfType("subgraph_ex1"); + mx::NodeGraphPtr graph = doc->getNodeGraph("subgraph_ex1"); REQUIRE(graph); // Traverse the graph and count nodes. diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index c832709847..412ad251be 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -40,34 +40,6 @@ TEST_CASE("Load content", "[xmlio]") libs.push_back(lib); } - // Check that there is one implementation per nodedef. - mx::DocumentPtr implCheckDocument = mx::createDocument(); - for (mx::DocumentPtr lib : libs) - { - implCheckDocument->importLibrary(lib); - } - const std::string target; - const std::string language("osl"); - std::vector nodeDefs = implCheckDocument->getNodeDefs(); - std::set nodeDefsFound; - for (mx::NodeDefPtr nodeDef : nodeDefs) - { - const std::string typeAttribute = nodeDef->getAttribute(mx::Element::TYPE_ATTRIBUTE); - // Nodedefs which do not have a type do not reqiure an implementation - if (typeAttribute != mx::NONE_TYPE_STRING) - { - if (nodeDef->getImplementation(target, language)) - { - nodeDefsFound.insert(nodeDef->getName()); - } - } - else - { - nodeDefsFound.insert(nodeDef->getName()); - } - } - REQUIRE(nodeDefsFound.size() == nodeDefs.size()); - // Read and validate each example document. for (std::string filename : exampleFilenames) { @@ -159,19 +131,33 @@ TEST_CASE("Load content", "[xmlio]") mx::NodePtr node = elem->asA(); if (node) { - mx::NodeDefPtr nodeDef = node->getNodeDef(); - REQUIRE(nodeDef); - // Check that implementations exist for any nodedefs added by example files - if (nodeDefsFound.find(nodeDef->getName()) == nodeDefsFound.end()) - { - REQUIRE(nodeDef->getImplementation(target, language)); - nodeDefsFound.insert(nodeDef->getName()); - } + REQUIRE(node->getNodeDef()); + REQUIRE(node->getImplementation()); } } + // Create a namespaced custom library. + mx::DocumentPtr customLibrary = mx::createDocument(); + customLibrary->setNamespace("custom"); + mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("nodegraph1"); + mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("shader1", "surfaceshader", "simpleSrf"); + mx::ImplementationPtr customImpl = customLibrary->addImplementation("impl1"); + mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "node1"); + customImpl->setNodeDef(customNodeDef); + REQUIRE(customLibrary->validate()); + + // Import the custom library. + doc2->importLibrary(customLibrary); + mx::NodeGraphPtr importedNodeGraph = doc2->getNodeGraph("custom:nodegraph1"); + mx::NodeDefPtr importedNodeDef = doc2->getNodeDef("custom:shader1"); + mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:impl1"); + mx::NodePtr importedNode = importedNodeGraph->getNode("node1"); + REQUIRE(importedNodeDef != nullptr); + REQUIRE(importedNode->getNodeDef() == importedNodeDef); + REQUIRE(importedImpl->getNodeDef() == importedNodeDef); + REQUIRE(doc2->validate()); + // Flatten subgraph references. - doc2 = doc->copy(); for (mx::NodeGraphPtr nodeGraph : doc2->getNodeGraphs()) { nodeGraph->flattenSubgraphs(); @@ -179,16 +165,16 @@ TEST_CASE("Load content", "[xmlio]") REQUIRE(doc2->validate()); // Read document without XIncludes. - doc2 = mx::createDocument(); + mx::DocumentPtr doc3 = mx::createDocument(); mx::XmlReadOptions readOptions; readOptions.readXIncludes = false; - mx::readFromXmlFile(doc2, filename, searchPath, &readOptions); - if (*doc2 != *doc) + mx::readFromXmlFile(doc3, filename, searchPath, &readOptions); + if (*doc3 != *doc) { writtenDoc = mx::createDocument(); xmlString = mx::writeToXmlString(doc); mx::readFromXmlString(writtenDoc, xmlString, &readOptions); - REQUIRE(*doc2 == *writtenDoc); + REQUIRE(*doc3 == *writtenDoc); } } diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index d2d3466b77..c1127522d8 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -62,6 +62,10 @@ void bindPyElement(py::module& mod) .def("getInheritsFrom", &mx::Element::getInheritsFrom) .def("hasInheritedBase", &mx::Element::hasInheritedBase) .def("hasInheritanceCycle", &mx::Element::hasInheritanceCycle) + .def("setNamespace", &mx::Element::setNamespace) + .def("hasNamespace", &mx::Element::hasNamespace) + .def("getNamespace", &mx::Element::getNamespace) + .def("getQualifiedName", &mx::Element::getQualifiedName) .def("addChildOfCategory", &mx::Element::addChildOfCategory) .def("_getChild", &mx::Element::getChild) .def("getChildren", &mx::Element::getChildren) diff --git a/source/PyMaterialX/PyNode.cpp b/source/PyMaterialX/PyNode.cpp index 508562a9f8..f2d4456282 100644 --- a/source/PyMaterialX/PyNode.cpp +++ b/source/PyMaterialX/PyNode.cpp @@ -33,6 +33,8 @@ void bindPyNode(py::module& mod) .def("getNodeDef", &mx::NodeGraph::getNodeDef) .def("_addNode", &mx::NodeGraph::addNode, py::arg("category"), py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) + .def("addNodeInstance", &mx::NodeGraph::addNodeInstance, + py::arg("nodeDef"), py::arg("name") = mx::EMPTY_STRING) .def("getNode", &mx::NodeGraph::getNode) .def("getNodes", &mx::NodeGraph::getNodes, py::arg("category") = mx::EMPTY_STRING) From 24d79e30ac9cbafb59e272dc5fd39527b6c6da5f Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 19 May 2018 17:30:16 -0700 Subject: [PATCH 10/27] Improvements to namespace support - Generalize Element::getQualifiedName to root namespaces. - Remove extra steps from ShaderRef::getNodeDef. --- source/MaterialXCore/Document.cpp | 7 ++----- source/MaterialXCore/Element.h | 2 +- source/MaterialXCore/Material.cpp | 6 ++++-- source/MaterialXTest/XmlIo.cpp | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index bf6ef25ade..ed8a185019 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -150,19 +150,16 @@ void Document::initialize() void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOptions) { - string libraryPrefix = library->hasNamespace() ? - library->getNamespace() + NAME_PREFIX_SEPARATOR : - EMPTY_STRING; bool skipDuplicateElements = copyOptions && copyOptions->skipDuplicateElements; bool copySourceUris = copyOptions && copyOptions->copySourceUris; for (ElementPtr child : library->getChildren()) { - std::string childName = child->getName(); + std::string childName = child->getQualifiedName(child->getName()); if (skipDuplicateElements && getChild(childName)) { continue; } - ElementPtr childCopy = addChildOfCategory(child->getCategory(), libraryPrefix + childName); + ElementPtr childCopy = addChildOfCategory(child->getCategory(), childName); childCopy->copyContentFrom(child, copyOptions); if (!childCopy->hasNamespace() && library->hasNamespace()) { diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index cfc16382ad..1bdf85dd30 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -335,7 +335,7 @@ class Element : public std::enable_shared_from_this { for (ConstElementPtr elem : traverseAncestors()) { - if (elem->getRoot() != elem && elem->hasNamespace()) + if (elem->hasNamespace()) { return elem->getNamespace() + NAME_PREFIX_SEPARATOR + name; } diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index b5c2626f16..96fe55430b 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -173,8 +173,10 @@ NodeDefPtr ShaderRef::getNodeDef() const if (hasNodeString()) { vector nodeDefs = getDocument()->getMatchingNodeDefs(getQualifiedName(getNodeString())); - vector secondary = getDocument()->getMatchingNodeDefs(getNodeString()); - nodeDefs.insert(nodeDefs.end(), secondary.begin(), secondary.end()); + if (nodeDefs.empty()) + { + nodeDefs = getDocument()->getMatchingNodeDefs(getNodeString()); + } return nodeDefs.empty() ? NodeDefPtr() : nodeDefs[0]; } return NodeDefPtr(); diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index 412ad251be..8efe4b17ae 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -141,8 +141,8 @@ TEST_CASE("Load content", "[xmlio]") customLibrary->setNamespace("custom"); mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("nodegraph1"); mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("shader1", "surfaceshader", "simpleSrf"); - mx::ImplementationPtr customImpl = customLibrary->addImplementation("impl1"); mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "node1"); + mx::ImplementationPtr customImpl = customLibrary->addImplementation("impl1"); customImpl->setNodeDef(customNodeDef); REQUIRE(customLibrary->validate()); @@ -150,8 +150,8 @@ TEST_CASE("Load content", "[xmlio]") doc2->importLibrary(customLibrary); mx::NodeGraphPtr importedNodeGraph = doc2->getNodeGraph("custom:nodegraph1"); mx::NodeDefPtr importedNodeDef = doc2->getNodeDef("custom:shader1"); - mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:impl1"); mx::NodePtr importedNode = importedNodeGraph->getNode("node1"); + mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:impl1"); REQUIRE(importedNodeDef != nullptr); REQUIRE(importedNode->getNodeDef() == importedNodeDef); REQUIRE(importedImpl->getNodeDef() == importedNodeDef); From bbfa3ed8e0a6fb53342e4e959113f69ed64ec687 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 19 May 2018 17:50:44 -0700 Subject: [PATCH 11/27] Update changelog for latest work --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bcf7d522..65a41e65fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ Updating the MaterialX library to the v1.36 specification. ### Added +- Added support for Element namespaces. +- Added support for NodeDef inheritance. - Added support for inheritance attributes on MaterialX\:\:Material and MaterialX\:\:Look. - Added support for include and exclude attributes on MaterialX\:\:Collection. -- Added support for MaterialX\:\:NodeDef inheritance. -- Added the MaterialX\:\:Variant, MaterialX\:\:VariantSet, and MaterialX\:\:VariantAssign classes. - Added the MaterialX\:\:Token class for string substitutions. +- Added the MaterialX\:\:Variant, MaterialX\:\:VariantSet, and MaterialX\:\:VariantAssign classes. - Added the MaterialX\:\:GeomPath class for geometry name comparisons. - Added the Collection\:\:matchesGeomString method, for testing matches between collections and geometries. - Added the Material\:\:getGeometryBindings method, for finding the bindings of a material to specific geometries. From ccdb5b82a51bf79b322670506f9faf2cd0089f1d Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 20 May 2018 16:54:39 -0700 Subject: [PATCH 12/27] Unify XInclude processing with library import --- source/MaterialXCore/Document.cpp | 2 +- source/MaterialXCore/Element.h | 28 ++++++++++++++-------------- source/MaterialXFormat/XmlIo.cpp | 22 +++++++++------------- source/MaterialXFormat/XmlIo.h | 7 +------ source/PyMaterialX/PyXmlIo.cpp | 5 ++--- 5 files changed, 27 insertions(+), 37 deletions(-) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index ed8a185019..c5e36b3e32 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -154,7 +154,7 @@ void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOp bool copySourceUris = copyOptions && copyOptions->copySourceUris; for (ElementPtr child : library->getChildren()) { - std::string childName = child->getQualifiedName(child->getName()); + string childName = child->getQualifiedName(child->getName()); if (skipDuplicateElements && getChild(childName)) { continue; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 1bdf85dd30..49f6ef1005 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -311,19 +311,19 @@ class Element : public std::enable_shared_from_this /// @name Namespace /// @{ - /// Set the namespace of this element. - void setNamespace(const string& inherit) + /// Set the namespace string of this element. + void setNamespace(const string& space) { - setAttribute(NAMESPACE_ATTRIBUTE, inherit); + setAttribute(NAMESPACE_ATTRIBUTE, space); } - /// Return true if this element has a namespace. + /// Return true if this element has a namespace string. bool hasNamespace() const { return hasAttribute(NAMESPACE_ATTRIBUTE); } - /// Return the namespace of this element. + /// Return the namespace string of this element. const string& getNamespace() const { return getAttribute(NAMESPACE_ATTRIBUTE); @@ -343,15 +343,6 @@ class Element : public std::enable_shared_from_this return name; } - /// Resolve a reference to a named element at the root scope of this document, - /// taking the namespace at the scope of this element into account. - template shared_ptr resolveRootNameReference(const string& name) const - { - ConstElementPtr root = getRoot(); - shared_ptr child = root->getChildOfType(getQualifiedName(name)); - return child ? child : root->getChildOfType(name); - } - /// @} /// @name Subclass /// @{ @@ -752,6 +743,15 @@ class Element : public std::enable_shared_from_this /// @} protected: + // Resolve a reference to a named element at the root scope of this document, + // taking the namespace at the scope of this element into account. + template shared_ptr resolveRootNameReference(const string& name) const + { + ConstElementPtr root = getRoot(); + shared_ptr child = root->getChildOfType(getQualifiedName(name)); + return child ? child : root->getChildOfType(name); + } + // Enforce a requirement within a validate method, updating the validation // state and optional output text if the requirement is not met. void validateRequire(bool expression, bool& res, string* message, string errorDesc) const; diff --git a/source/MaterialXFormat/XmlIo.cpp b/source/MaterialXFormat/XmlIo.cpp index 8d7722dcbe..89ba69b466 100644 --- a/source/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXFormat/XmlIo.cpp @@ -130,7 +130,7 @@ void xmlDocumentFromFile(xml_document& xmlDoc, string filename, const string& se } } -void processXIncludes(xml_node& xmlNode, const string& searchPath, const XmlReadOptions* readOptions) +void processXIncludes(DocumentPtr doc, xml_node& xmlNode, const string& searchPath, const XmlReadOptions* readOptions) { xml_node xmlChild = xmlNode.first_child(); while (xmlChild) @@ -139,19 +139,15 @@ void processXIncludes(xml_node& xmlNode, const string& searchPath, const XmlRead { if (!readOptions || readOptions->readXIncludes) { + // Read the included file into a library document. xml_attribute fileAttr = xmlChild.attribute("href"); - string filename = fileAttr.value(); + DocumentPtr library = createDocument(); + readFromXmlFile(library, fileAttr.value(), searchPath, readOptions); - xml_document xmlDoc; - xmlDocumentFromFile(xmlDoc, filename, searchPath); - - xml_node xmlRoot = xmlDoc.child("materialx"); - for (const xml_node& sourceChild : xmlRoot.children()) - { - xml_node destChild = xmlNode.insert_copy_before(sourceChild, xmlChild); - xml_attribute xmlAttr = destChild.append_attribute(SOURCE_URI_ATTRIBUTE.c_str()); - xmlAttr.set_value(filename.c_str()); - } + // Import the library. + CopyOptions copyOptions = readOptions ? (CopyOptions) *readOptions : CopyOptions(); + copyOptions.copySourceUris = true; + doc->importLibrary(library, ©Options); } // Remove include directive. @@ -177,7 +173,7 @@ void documentFromXml(DocumentPtr doc, xml_node xmlRoot = xmlDoc.child(Document::CATEGORY.c_str()); if (xmlRoot) { - processXIncludes(xmlRoot, searchPath, readOptions); + processXIncludes(doc, xmlRoot, searchPath, readOptions); elementFromXml(xmlRoot, doc, readOptions); } diff --git a/source/MaterialXFormat/XmlIo.h b/source/MaterialXFormat/XmlIo.h index 862473e653..881f40f555 100644 --- a/source/MaterialXFormat/XmlIo.h +++ b/source/MaterialXFormat/XmlIo.h @@ -18,20 +18,15 @@ namespace MaterialX /// @class XmlReadOptions /// A set of options for controlling the behavior of XML read functions. -class XmlReadOptions +class XmlReadOptions : public CopyOptions { public: XmlReadOptions() : - skipDuplicateElements(false), readXIncludes(true) { } ~XmlReadOptions() { } - /// If true, elements at the same scope with duplicate names will be skipped; - /// otherwise, they will trigger an exception. Defaults to false. - bool skipDuplicateElements; - /// If true, XInclude references will be read from disk and included in the /// document. Defaults to true. bool readXIncludes; diff --git a/source/PyMaterialX/PyXmlIo.cpp b/source/PyMaterialX/PyXmlIo.cpp index b46bd920bc..956d743f7d 100644 --- a/source/PyMaterialX/PyXmlIo.cpp +++ b/source/PyMaterialX/PyXmlIo.cpp @@ -13,10 +13,9 @@ namespace mx = MaterialX; void bindPyXmlIo(py::module& mod) { - py::class_(mod, "XmlReadOptions") + py::class_(mod, "XmlReadOptions") .def(py::init()) - .def_readwrite("readXIncludes", &mx::XmlReadOptions::readXIncludes) - .def_readwrite("skipDuplicateElements", &mx::XmlReadOptions::skipDuplicateElements); + .def_readwrite("readXIncludes", &mx::XmlReadOptions::readXIncludes); mod.def("readFromXmlFileBase", &mx::readFromXmlFile, py::arg("doc"), py::arg("filename"), py::arg("searchPath") = mx::EMPTY_STRING, py::arg("readOptions") = (mx::XmlReadOptions*) nullptr); From 00c4e4fcd760ddc123123f058d880e3408ee38eb Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 21 May 2018 14:41:44 -0700 Subject: [PATCH 13/27] Remove require string attributes in MaterialX v1.36 --- python/MaterialX/main.py | 6 ++++++ python/MaterialXTest/main.py | 4 ---- source/MaterialXCore/Document.cpp | 29 ----------------------------- source/MaterialXCore/Document.h | 31 ------------------------------- source/MaterialXTest/Document.cpp | 4 ---- source/PyMaterialX/PyDocument.cpp | 4 ---- 6 files changed, 6 insertions(+), 72 deletions(-) diff --git a/python/MaterialX/main.py b/python/MaterialX/main.py index abc7ec6454..0d83ae78e4 100644 --- a/python/MaterialX/main.py +++ b/python/MaterialX/main.py @@ -253,7 +253,13 @@ def _applyStringSubstitutions(self, filename, geom = '/'): warnings.warn("This function is deprecated; call Element.createStringResolver() instead.", DeprecationWarning, stacklevel = 2) return self.createStringResolver(geom).resolve(filename, 'filename') +def _generateRequireString(self): + """(Deprecated) Generate the require string for a document.""" + warnings.warn("Require strings are no longer supported in MaterialX.", DeprecationWarning, stacklevel = 2) + pass + Document.applyStringSubstitutions = _applyStringSubstitutions +Document.generateRequireString = _generateRequireString # diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index 6c1c2e3de5..ab56f45b96 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -306,10 +306,6 @@ def test_BuildDocument(self): damaged = variantSet.addVariant("damaged") self.assertTrue(len(variantSet.getVariants()) == 2) - # Generate and verify require string. - doc.generateRequireString() - self.assertTrue('matnodegraph' in doc.getRequireString()) - # Disconnect outputs from sources. output1.setConnectedNode(None) output2.setConnectedNode(None) diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index c5e36b3e32..d4d48c0d7e 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -13,12 +13,8 @@ namespace MaterialX { const string Document::VERSION_ATTRIBUTE = "version"; -const string Document::REQUIRE_ATTRIBUTE = "require"; const string Document::CMS_ATTRIBUTE = "cms"; const string Document::CMS_CONFIG_ATTRIBUTE = "cmsconfig"; -const string Document::REQUIRE_STRING_MATINHERIT = "matinherit"; -const string Document::REQUIRE_STRING_MATNODEGRAPH = "matnodegraph"; -const string Document::REQUIRE_STRING_OVERRIDE = "override"; namespace { @@ -242,31 +238,6 @@ vector Document::getMatchingImplementations(const string& n return implementations; } -void Document::generateRequireString() -{ - std::set requireSet; - for (ElementPtr elem : traverseTree()) - { - if (elem->isA()) - { - ShaderRefPtr shaderRef = elem->asA(); - if (!shaderRef->getReferencedOutputs().empty()) - { - requireSet.insert(REQUIRE_STRING_MATNODEGRAPH); - } - } - } - - string requireStr; - for (string str : requireSet) - { - if (!requireStr.empty()) - requireStr += ","; - requireStr += str; - } - setRequireString(requireStr); -} - bool Document::validate(string* message) const { bool res = true; diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 0eb9f8f424..87a328d334 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -439,33 +439,6 @@ class Document : public Element /// Implementation element or NodeGraph element. vector getMatchingImplementations(const string& nodeDef) const; - /// @} - /// @name Require String - /// @{ - - /// Set the require string of the document. - /// @todo Require strings are not yet automatically generated or validated - /// by the MaterialX library. - void setRequireString(const string& require) - { - setAttribute(REQUIRE_ATTRIBUTE, require); - } - - /// Return true if the document has a require string. - bool hasRequireString() const - { - return hasAttribute(REQUIRE_ATTRIBUTE); - } - - /// Return the require string of the document. - const string& getRequireString() const - { - return getAttribute(REQUIRE_ATTRIBUTE); - } - - /// Check the content of this document and store the appropriate require string. - void generateRequireString(); - /// @} /// @name Color Management System /// @{ @@ -563,12 +536,8 @@ class Document : public Element public: static const string CATEGORY; static const string VERSION_ATTRIBUTE; - static const string REQUIRE_ATTRIBUTE; static const string CMS_ATTRIBUTE; static const string CMS_CONFIG_ATTRIBUTE; - static const string REQUIRE_STRING_MATINHERIT; - static const string REQUIRE_STRING_MATNODEGRAPH; - static const string REQUIRE_STRING_OVERRIDE; private: class Cache; diff --git a/source/MaterialXTest/Document.cpp b/source/MaterialXTest/Document.cpp index 7f9118e3f6..48e2fa5608 100644 --- a/source/MaterialXTest/Document.cpp +++ b/source/MaterialXTest/Document.cpp @@ -71,10 +71,6 @@ TEST_CASE("Document", "[document]") doc->removePropertySet(propertySet->getName()); REQUIRE(doc->getPropertySets().size() == 0); - // Generate and verify require string. - doc->generateRequireString(); - REQUIRE(doc->getRequireString().find(mx::Document::REQUIRE_STRING_MATNODEGRAPH) != std::string::npos); - // Validate the document. REQUIRE(doc->validate()); } diff --git a/source/PyMaterialX/PyDocument.cpp b/source/PyMaterialX/PyDocument.cpp index 6c33ca4873..eed428fdc6 100644 --- a/source/PyMaterialX/PyDocument.cpp +++ b/source/PyMaterialX/PyDocument.cpp @@ -76,10 +76,6 @@ void bindPyDocument(py::module& mod) .def("getImplementation", &mx::Document::getImplementation) .def("getImplementations", &mx::Document::getImplementations) .def("removeImplementation", &mx::Document::removeImplementation) - .def("setRequireString", &mx::Document::setRequireString) - .def("hasRequireString", &mx::Document::hasRequireString) - .def("getRequireString", &mx::Document::getRequireString) - .def("generateRequireString", &mx::Document::generateRequireString) .def("setColorManagementSystem", &mx::Document::setColorManagementSystem) .def("hasColorManagementSystem", &mx::Document::hasColorManagementSystem) .def("getColorManagementSystem", &mx::Document::getColorManagementSystem) From d76469ad8a65942833c9b7f6a82b346c2449440b Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 6 Jun 2018 18:21:33 -0700 Subject: [PATCH 14/27] Additional updates for v1.36 - Add support for root-level nodes, and move graph functionality into a new GraphElement class. - Add support for array-type values in 'includecollection'. - Propagate root-level prefixes and color spaces to child elements in importLibrary. - Use the StringVec alias consistently across the MaterialX library. - Remove the 'channels' attribute from InterfaceElement. --- CHANGELOG.md | 4 +- python/MaterialX/main.py | 4 +- source/MaterialXCore/Document.cpp | 26 ++++--- source/MaterialXCore/Document.h | 2 +- source/MaterialXCore/Element.cpp | 9 +-- source/MaterialXCore/Element.h | 4 +- source/MaterialXCore/Geom.cpp | 44 +++++++++--- source/MaterialXCore/Geom.h | 13 ++-- source/MaterialXCore/Interface.cpp | 7 +- source/MaterialXCore/Interface.h | 24 ------- source/MaterialXCore/Material.cpp | 24 ++++--- source/MaterialXCore/Material.h | 20 ++++-- source/MaterialXCore/Node.cpp | 24 ++++--- source/MaterialXCore/Node.h | 111 +++++++++++++++++------------ source/MaterialXCore/Util.cpp | 4 +- source/MaterialXCore/Util.h | 2 +- source/MaterialXCore/Value.cpp | 4 +- source/MaterialXFormat/File.h | 2 +- source/MaterialXTest/Node.cpp | 37 +++++----- source/PyMaterialX/PyDocument.cpp | 2 +- source/PyMaterialX/PyGeom.cpp | 3 +- source/PyMaterialX/PyInterface.cpp | 2 - source/PyMaterialX/PyMaterial.cpp | 2 + source/PyMaterialX/PyNode.cpp | 16 +++-- 24 files changed, 221 insertions(+), 169 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65a41e65fe..0c8dffd0d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,16 +9,18 @@ Updating the MaterialX library to the v1.36 specification. - Added support for NodeDef inheritance. - Added support for inheritance attributes on MaterialX\:\:Material and MaterialX\:\:Look. - Added support for include and exclude attributes on MaterialX\:\:Collection. +- Added support for root-level node elements. - Added the MaterialX\:\:Token class for string substitutions. - Added the MaterialX\:\:Variant, MaterialX\:\:VariantSet, and MaterialX\:\:VariantAssign classes. - Added the MaterialX\:\:GeomPath class for geometry name comparisons. - Added the Collection\:\:matchesGeomString method, for testing matches between collections and geometries. - Added the Material\:\:getGeometryBindings method, for finding the bindings of a material to specific geometries. -### Changed +### Removed - Removed the MaterialX\:\:MaterialInherit and MaterialX\:\:LookInherit classes. - Removed the MaterialX\:\:CollectionAdd and MaterialX\:\:CollectionRemove classes. - Removed the MaterialX\:\:Override class and support for public names. +- Removed the 'channels' attribute from MaterialX\:\:InterfaceElement. - Removed the Material::getReferencingMaterialAssigns method (deprecated in Python). ## [1.35.5] - 2018-05-07 diff --git a/python/MaterialX/main.py b/python/MaterialX/main.py index 0d83ae78e4..c084a80df0 100644 --- a/python/MaterialX/main.py +++ b/python/MaterialX/main.py @@ -147,14 +147,14 @@ def _getReferencedNodeDef(self): # -# NodeGraph +# GraphElement # def _addNode(self, category, name = '', typeString = 'color3'): "Add an opgraph node." return self._addNode(category, name, typeString) -NodeGraph.addNode = _addNode +GraphElement.addNode = _addNode # diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index d4d48c0d7e..04c45b3148 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -120,7 +120,7 @@ class Document::Cache // Document::Document(ElementPtr parent, const string& name) : - Element(parent, CATEGORY, name), + GraphElement(parent, CATEGORY, name), _cache(std::unique_ptr(new Cache)) { } @@ -155,8 +155,21 @@ void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOp { continue; } + ElementPtr childCopy = addChildOfCategory(child->getCategory(), childName); childCopy->copyContentFrom(child, copyOptions); + if (!childCopy->hasFilePrefix() && library->hasFilePrefix()) + { + childCopy->setFilePrefix(library->getFilePrefix()); + } + if (!childCopy->hasGeomPrefix() && library->hasGeomPrefix()) + { + childCopy->setGeomPrefix(library->getGeomPrefix()); + } + if (!childCopy->hasColorSpace() && library->hasColorSpace()) + { + childCopy->setColorSpace(library->getColorSpace()); + } if (!childCopy->hasNamespace() && library->hasNamespace()) { childCopy->setNamespace(library->getNamespace()); @@ -177,7 +190,7 @@ std::pair Document::getVersionIntegers() MATERIALX_MINOR_VERSION); } - vector splitVersion = splitString(versionString, "."); + StringVec splitVersion = splitString(versionString, "."); if (splitVersion.size() == 2) { return std::pair(std::stoi(splitVersion[0]), @@ -515,15 +528,6 @@ void Document::upgradeVersion() elem->setInheritString(child->getAttribute("look")); elem->removeChild(child->getName()); } - else if (geomInfo && child->isA()) - { - GeomAttrPtr geomAttr = child->asA(); - if (geomAttr->getType() == "string") - { - geomInfo->removeChild(geomAttr->getName()); - geomInfo->setTokenValue(geomAttr->getName(), geomAttr->getValueString()); - } - } } } minorVersion = 36; diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 87a328d334..7e5618b236 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -29,7 +29,7 @@ using ConstDocumentPtr = shared_ptr; /// MaterialX ownership hierarchy. /// /// Use the factory function createDocument() to create a Document instance. -class Document : public Element +class Document : public GraphElement { public: Document(ElementPtr parent, const string& name); diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 029587d191..f3428ffb30 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -107,7 +107,7 @@ string Element::getNamePath(ConstElementPtr relativeTo) const ElementPtr Element::getDescendant(const string& path) { - const vector elementNames = splitString(path, NAME_PATH_SEPARATOR); + const StringVec elementNames = splitString(path, NAME_PATH_SEPARATOR); ElementPtr currentElement = getSelf(); for (const string& elementName : elementNames) { @@ -369,7 +369,7 @@ void Element::copyContentFrom(ConstElementPtr source, const CopyOptions* copyOpt void Element::clearContent() { _sourceUri = EMPTY_STRING; - vector attributeNames = getAttributeNames(); + StringVec attributeNames = getAttributeNames(); vector children = getChildren(); for (const string& attr : attributeNames) { @@ -554,8 +554,8 @@ bool targetStringsMatch(const string& target1, const string& target2) if (target1.empty() || target2.empty()) return true; - vector vec1 = splitString(target1, ARRAY_VALID_SEPARATORS); - vector vec2 = splitString(target2, ARRAY_VALID_SEPARATORS); + StringVec vec1 = splitString(target1, ARRAY_VALID_SEPARATORS); + StringVec vec2 = splitString(target2, ARRAY_VALID_SEPARATORS); std::set set1(vec1.begin(), vec1.end()); std::set set2(vec2.begin(), vec2.end()); @@ -589,6 +589,7 @@ template shared_ptr Element::asA() const; INSTANTIATE_SUBCLASS(Element) INSTANTIATE_SUBCLASS(GeomElement) +INSTANTIATE_SUBCLASS(GraphElement) INSTANTIATE_SUBCLASS(InterfaceElement) INSTANTIATE_SUBCLASS(PortElement) INSTANTIATE_SUBCLASS(TypedElement) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 49f6ef1005..07c863585e 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -480,7 +480,7 @@ class Element : public std::enable_shared_from_this } /// Return a vector of stored attribute names, in the order they were set. - const vector& getAttributeNames() const + const StringVec& getAttributeNames() const { return _attributeOrder; } @@ -786,7 +786,7 @@ class Element : public std::enable_shared_from_this vector _childOrder; StringMap _attributeMap; - vector _attributeOrder; + StringVec _attributeOrder; weak_ptr _parent; weak_ptr _root; diff --git a/source/MaterialXCore/Geom.cpp b/source/MaterialXCore/Geom.cpp index c444e9ed33..ac03244993 100644 --- a/source/MaterialXCore/Geom.cpp +++ b/source/MaterialXCore/Geom.cpp @@ -89,9 +89,35 @@ void Collection::setIncludeCollection(ConstCollectionPtr collection) } } -CollectionPtr Collection::getIncludeCollection() const +void Collection::setIncludeCollections(vector collections) { - return resolveRootNameReference(getIncludeCollectionString()); + if (!collections.empty()) + { + StringVec stringVec; + for (ConstCollectionPtr collection : collections) + { + stringVec.push_back(collection->getName()); + } + setTypedAttribute(INCLUDE_COLLECTION_ATTRIBUTE, stringVec); + } + else + { + removeAttribute(INCLUDE_COLLECTION_ATTRIBUTE); + } +} + +vector Collection::getIncludeCollections() const +{ + vector vec; + for (const string& str : getTypedAttribute(INCLUDE_COLLECTION_ATTRIBUTE)) + { + CollectionPtr collection = resolveRootNameReference(str); + if (collection) + { + vec.push_back(collection); + } + } + return vec; } bool Collection::hasIncludeCycle() const @@ -118,16 +144,18 @@ bool Collection::matchesGeomString(const string& geom) const return true; } - std::set includedSet; - ConstCollectionPtr included = getIncludeCollection(); - while (included) + std::set includedSet; + vector includedVec = getIncludeCollections(); + for (size_t i = 0; i < includedVec.size(); i++) { - if (includedSet.count(included)) + CollectionPtr collection = includedVec[i]; + if (includedSet.count(collection)) { throw ExceptionFoundCycle("Encountered a cycle in collection: " + getName()); } - includedSet.insert(included); - included = included->getIncludeCollection(); + includedSet.insert(collection); + vector appendVec = collection->getIncludeCollections(); + includedVec.insert(includedVec.end(), appendVec.begin(), appendVec.end()); } for (ConstCollectionPtr collection : includedSet) { diff --git a/source/MaterialXCore/Geom.h b/source/MaterialXCore/Geom.h index c31c432b5c..94bc1396a3 100644 --- a/source/MaterialXCore/Geom.h +++ b/source/MaterialXCore/Geom.h @@ -129,7 +129,7 @@ class GeomPath } private: - vector _vec; + StringVec _vec; bool _empty; }; @@ -429,11 +429,16 @@ class Collection : public Element return getAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } - /// Set the include collection for this element. + /// Set the collection that is directly included by this element. void setIncludeCollection(ConstCollectionPtr collection); - /// Return the include collection for this element. - CollectionPtr getIncludeCollection() const; + /// Set the vector of collections that are directly included by + /// this element. + void setIncludeCollections(vector collections); + + /// Return the vector of collections that are directly included by + /// this element. + vector getIncludeCollections() const; /// Return true if the include chain for this element contains a cycle. bool hasIncludeCycle() const; diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index f718408f0a..e984970e80 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -13,7 +13,6 @@ namespace MaterialX const string PortElement::NODE_NAME_ATTRIBUTE = "nodename"; const string PortElement::OUTPUT_ATTRIBUTE = "output"; -const string PortElement::CHANNELS_ATTRIBUTE = "channels"; // // PortElement methods @@ -35,7 +34,7 @@ NodePtr PortElement::getConnectedNode() const { for (ConstElementPtr elem : traverseAncestors()) { - ConstNodeGraphPtr graph = elem->asA(); + ConstGraphElementPtr graph = elem->asA(); if (graph) { return graph->getNode(getNodeName()); @@ -61,13 +60,13 @@ bool PortElement::validate(string* message) const { OutputPtr output = connectedNodeDef->getOutput(getOutputString()); validateRequire(output != nullptr, res, message, "Invalid output in port connection"); - if (output && !hasChannels()) + if (output) { validateRequire(getType() == output->getType(), res, message, "Mismatched output type in port connection"); } } } - else if (!hasChannels()) + else { validateRequire(getType() == getConnectedNode()->getType(), res, message, "Mismatched types in port connection"); } diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 0537f68554..c17f3345e6 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -137,29 +137,6 @@ class PortElement : public ValueElement return getAttribute(OUTPUT_ATTRIBUTE); } - /// @} - /// @name Channels - /// @{ - - /// Set the channels string of this element, defining a channel swizzle - /// that will be applied to this port. - void setChannels(const string& channels) - { - setAttribute(CHANNELS_ATTRIBUTE, channels); - } - - /// Return true if this element has a channels string. - bool hasChannels() const - { - return hasAttribute(CHANNELS_ATTRIBUTE); - } - - /// Return the channels string of this element. - const string& getChannels() const - { - return getAttribute(CHANNELS_ATTRIBUTE); - } - /// @} /// @name Connections /// @{ @@ -184,7 +161,6 @@ class PortElement : public ValueElement public: static const string NODE_NAME_ATTRIBUTE; static const string OUTPUT_ATTRIBUTE; - static const string CHANNELS_ATTRIBUTE; }; /// @class Input diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index 96fe55430b..d05abffe69 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -136,28 +136,32 @@ void BindInput::setConnectedOutput(ConstOutputPtr output) { if (output) { - setNodeGraphString(output->getParent()->getName()); setOutputString(output->getName()); + ConstElementPtr parent = output->getParent(); + if (parent->isA()) + { + setNodeGraphString(parent->getName()); + } + else + { + removeAttribute(NODE_GRAPH_ATTRIBUTE); + } } else { - removeAttribute(NODE_GRAPH_ATTRIBUTE); removeAttribute(OUTPUT_ATTRIBUTE); + removeAttribute(NODE_GRAPH_ATTRIBUTE); } } OutputPtr BindInput::getConnectedOutput() const { - NodeGraphPtr nodeGraph = resolveRootNameReference(getNodeGraphString()); - if (nodeGraph) + if (hasNodeGraphString()) { - OutputPtr output = nodeGraph->getOutput(getOutputString()); - if (output) - { - return output; - } + NodeGraphPtr nodeGraph = resolveRootNameReference(getNodeGraphString()); + return nodeGraph ? nodeGraph->getOutput(getOutputString()) : OutputPtr(); } - return OutputPtr(); + return getDocument()->getOutput(getOutputString()); } // diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index 3e6d65a5dd..302a87be5d 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -223,13 +223,19 @@ class BindInput : public ValueElement /// @name NodeGraph String /// @{ - /// Set the node graph string of the BindInput. + /// Set the node graph string of this element. void setNodeGraphString(const string& graph) { setAttribute(NODE_GRAPH_ATTRIBUTE, graph); } - /// Return the node graph string of the BindInput. + /// Return true if this element has a node graph string. + bool hasNodeGraphString() const + { + return hasAttribute(NODE_GRAPH_ATTRIBUTE); + } + + /// Return the node graph string of this element. const string& getNodeGraphString() const { return getAttribute(NODE_GRAPH_ATTRIBUTE); @@ -239,13 +245,19 @@ class BindInput : public ValueElement /// @name Output String /// @{ - /// Set the output string of the BindInput. + /// Set the output string of this element. void setOutputString(const string& output) { setAttribute(OUTPUT_ATTRIBUTE, output); } - /// Return the output string of the BindInput. + /// Return true if this element has an output string. + bool hasOutputString() const + { + return hasAttribute(OUTPUT_ATTRIBUTE); + } + + /// Return the output string of this element. const string& getOutputString() const { return getAttribute(OUTPUT_ATTRIBUTE); diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 62d768f559..1de9f55d50 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -120,15 +120,10 @@ bool Node::validate(string* message) const } // -// NodeGraph methods +// GraphElement methods // -NodeDefPtr NodeGraph::getNodeDef() const -{ - return resolveRootNameReference(getNodeDefString()); -} - -void NodeGraph::flattenSubgraphs(const string& target) +void GraphElement::flattenSubgraphs(const string& target) { vector initialNodes = getNodes(); std::deque nodeQueue(initialNodes.begin(), initialNodes.end()); @@ -144,7 +139,7 @@ void NodeGraph::flattenSubgraphs(const string& target) continue; } - NodeGraphPtr origSubGraph = implement->asA(); + GraphElementPtr origSubGraph = implement->asA(); std::unordered_map subNodeMap; // Create a new instance of each original subnode. @@ -226,7 +221,7 @@ void NodeGraph::flattenSubgraphs(const string& target) } } -vector NodeGraph::topologicalSort() const +vector GraphElement::topologicalSort() const { // Calculate a topological order of the children, using Kahn's algorithm // to avoid recursion. @@ -299,7 +294,7 @@ vector NodeGraph::topologicalSort() const return result; } -string NodeGraph::asStringDot() const +string GraphElement::asStringDot() const { string dot = "digraph {\n"; @@ -345,4 +340,13 @@ string NodeGraph::asStringDot() const return dot; } +// +// NodeGraph methods +// + +NodeDefPtr NodeGraph::getNodeDef() const +{ + return resolveRootNameReference(getNodeDefString()); +} + } // namespace MaterialX diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index 295d9be485..96f6a627ed 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -21,13 +21,18 @@ using NodePtr = shared_ptr; /// A shared pointer to a const Node using ConstNodePtr = shared_ptr; +/// A shared pointer to a GraphElement +using GraphElementPtr = shared_ptr; +/// A shared pointer to a const GraphElement +using ConstGraphElementPtr = shared_ptr; + /// A shared pointer to a NodeGraph using NodeGraphPtr = shared_ptr; /// A shared pointer to a const NodeGraph using ConstNodeGraphPtr = shared_ptr; /// @class Node -/// A node element within a NodeGraph. +/// A node element within a NodeGraph or Document. /// /// A Node represents an instance of a NodeDef within a graph, and its Parameter /// and Input elements apply specific values and connections to that instance. @@ -124,55 +129,18 @@ class Node : public InterfaceElement static const string CATEGORY; }; -/// @class NodeGraph -/// A node graph element within a Document. -class NodeGraph : public InterfaceElement +/// @class GraphElement +/// The base class for graph elements such as NodeGraph and Document. +class GraphElement : public InterfaceElement { - public: - NodeGraph(ElementPtr parent, const string& name) : - InterfaceElement(parent, CATEGORY, name) - { - } - virtual ~NodeGraph() { } - - /// @name NodeDef - /// @{ - - /// Set the NodeDef string for the graph. - void setNodeDefString(const string& nodeDef) - { - setAttribute(NODE_DEF_ATTRIBUTE, nodeDef); - } - - /// Return true if the given graph has a NodeDef string. - bool hasNodeDefString() const - { - return hasAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Return the NodeDef string for the graph. - const string& getNodeDefString() const - { - return getAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Set the NodeDef element for the graph. - void setNodeDef(ConstNodeDefPtr nodeDef) + protected: + GraphElement(ElementPtr parent, const string& category, const string& name) : + InterfaceElement(parent, category, name) { - if (nodeDef) - { - setNodeDefString(nodeDef->getName()); - } - else - { - removeAttribute(NODE_DEF_ATTRIBUTE); - } } + public: + virtual ~GraphElement() { } - /// Return the NodeDef element for the graph. - NodeDefPtr getNodeDef() const; - - /// @} /// @name Node Elements /// @{ @@ -239,6 +207,57 @@ class NodeGraph : public InterfaceElement /// formatting details. string asStringDot() const; + /// @} +}; + +/// @class NodeGraph +/// A node graph element within a Document. +class NodeGraph : public GraphElement +{ + public: + NodeGraph(ElementPtr parent, const string& name) : + GraphElement(parent, CATEGORY, name) + { + } + virtual ~NodeGraph() { } + + /// @name NodeDef + /// @{ + + /// Set the NodeDef string for the graph. + void setNodeDefString(const string& nodeDef) + { + setAttribute(NODE_DEF_ATTRIBUTE, nodeDef); + } + + /// Return true if the given graph has a NodeDef string. + bool hasNodeDefString() const + { + return hasAttribute(NODE_DEF_ATTRIBUTE); + } + + /// Return the NodeDef string for the graph. + const string& getNodeDefString() const + { + return getAttribute(NODE_DEF_ATTRIBUTE); + } + + /// Set the NodeDef element for the graph. + void setNodeDef(ConstNodeDefPtr nodeDef) + { + if (nodeDef) + { + setNodeDefString(nodeDef->getName()); + } + else + { + removeAttribute(NODE_DEF_ATTRIBUTE); + } + } + + /// Return the NodeDef element for the graph. + NodeDefPtr getNodeDef() const; + /// @} public: diff --git a/source/MaterialXCore/Util.cpp b/source/MaterialXCore/Util.cpp index edb87857f2..4a4181a7e4 100644 --- a/source/MaterialXCore/Util.cpp +++ b/source/MaterialXCore/Util.cpp @@ -74,9 +74,9 @@ string incrementName(const string& name) return name + "2"; } -vector splitString(const string& str, const string& sep) +StringVec splitString(const string& str, const string& sep) { - vector split; + StringVec split; string::size_type lastPos = str.find_first_not_of(sep, 0); string::size_type pos = str.find_first_of(sep, lastPos); diff --git a/source/MaterialXCore/Util.h b/source/MaterialXCore/Util.h index aaf1611ca2..b2823b8002 100644 --- a/source/MaterialXCore/Util.h +++ b/source/MaterialXCore/Util.h @@ -36,7 +36,7 @@ string incrementName(const string& name); /// Split a string into a vector of substrings using the given set of /// separator characters. -vector splitString(const string& str, const string& sep); +StringVec splitString(const string& str, const string& sep); /// Apply the given substring substitutions to the input string. string replaceSubstrings(string str, const StringMap& stringMap); diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index e5477b71c4..e99a790e81 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -53,7 +53,7 @@ template <> void stringToData(const string& str, string& data) template void stringToData(const string& str, enable_if_mx_vector_t& data) { - vector tokens = splitString(str, ARRAY_VALID_SEPARATORS); + StringVec tokens = splitString(str, ARRAY_VALID_SEPARATORS); if (tokens.size() != data.numElements()) { throw ExceptionTypeError("Type mismatch in vector stringToData: " + str); @@ -66,7 +66,7 @@ template void stringToData(const string& str, enable_if_mx_vector_t template void stringToData(const string& str, enable_if_mx_matrix_t& data) { - vector tokens = splitString(str, ARRAY_VALID_SEPARATORS); + StringVec tokens = splitString(str, ARRAY_VALID_SEPARATORS); if (tokens.size() != data.numRows() * data.numColumns()) { throw ExceptionTypeError("Type mismatch in matrix stringToData: " + str); diff --git a/source/MaterialXFormat/File.h b/source/MaterialXFormat/File.h index db660e6ebc..3db2190fb8 100644 --- a/source/MaterialXFormat/File.h +++ b/source/MaterialXFormat/File.h @@ -117,7 +117,7 @@ class FilePath static FilePath getCurrentPath(); private: - vector _vec; + StringVec _vec; Type _type; Format _format; }; diff --git a/source/MaterialXTest/Node.cpp b/source/MaterialXTest/Node.cpp index 9c19d4a395..5616b252ea 100644 --- a/source/MaterialXTest/Node.cpp +++ b/source/MaterialXTest/Node.cpp @@ -35,14 +35,12 @@ TEST_CASE("Node", "[node]") // Create a document. mx::DocumentPtr doc = mx::createDocument(); - // Create a node graph with two source nodes. - mx::NodeGraphPtr nodeGraph = doc->addNodeGraph(); - REQUIRE_THROWS_AS(doc->addNodeGraph(nodeGraph->getName()), mx::Exception&); - mx::NodePtr constant = nodeGraph->addNode("constant"); - mx::NodePtr image = nodeGraph->addNode("image"); - REQUIRE(nodeGraph->getNodes().size() == 2); - REQUIRE(nodeGraph->getNodes("constant").size() == 1); - REQUIRE(nodeGraph->getNodes("image").size() == 1); + // Create a graph with two source nodes. + mx::NodePtr constant = doc->addNode("constant"); + mx::NodePtr image = doc->addNode("image"); + REQUIRE(doc->getNodes().size() == 2); + REQUIRE(doc->getNodes("constant").size() == 1); + REQUIRE(doc->getNodes("image").size() == 1); // Set constant node color. mx::Color3 color(0.1f, 0.2f, 0.3f); @@ -57,8 +55,8 @@ TEST_CASE("Node", "[node]") REQUIRE(image->getParameterValue("file")->asA() == file); // Create connected outputs. - mx::OutputPtr output1 = nodeGraph->addOutput(); - mx::OutputPtr output2 = nodeGraph->addOutput(); + mx::OutputPtr output1 = doc->addOutput(); + mx::OutputPtr output2 = doc->addOutput(); output1->setConnectedNode(constant); output2->setConnectedNode(image); REQUIRE(output1->getUpstreamElement() == constant); @@ -74,7 +72,7 @@ TEST_CASE("Node", "[node]") customNodeDef->setParameterValue("gain", 0.5f); // Reference the custom nodedef. - mx::NodePtr custom = nodeGraph->addNodeInstance(customNodeDef); + mx::NodePtr custom = doc->addNodeInstance(customNodeDef); REQUIRE(custom->getNodeDef()->getNodeCategory() == mx::PROCEDURAL_NODE_CATEGORY); REQUIRE(custom->getParameterValue("octaves")->isA()); REQUIRE(custom->getParameterValue("octaves")->asA() == 3); @@ -111,16 +109,13 @@ TEST_CASE("Node", "[node]") REQUIRE(image->getDownstreamPorts().empty()); // Remove nodes and outputs. - nodeGraph->removeNode(image->getName()); - nodeGraph->removeNode(constant->getName()); - nodeGraph->removeNode(custom->getName()); - nodeGraph->removeOutput(output1->getName()); - nodeGraph->removeOutput(output2->getName()); - REQUIRE(nodeGraph->getChildren().empty()); - - // Remove node graph. - doc->removeNodeGraph(nodeGraph->getName()); - REQUIRE(doc->getNodeGraphs().empty()); + doc->removeNode(image->getName()); + doc->removeNode(constant->getName()); + doc->removeNode(custom->getName()); + doc->removeOutput(output1->getName()); + doc->removeOutput(output2->getName()); + REQUIRE(doc->getNodes().empty()); + REQUIRE(doc->getOutputs().empty()); } TEST_CASE("Flatten", "[nodegraph]") diff --git a/source/PyMaterialX/PyDocument.cpp b/source/PyMaterialX/PyDocument.cpp index eed428fdc6..d378750be9 100644 --- a/source/PyMaterialX/PyDocument.cpp +++ b/source/PyMaterialX/PyDocument.cpp @@ -14,7 +14,7 @@ void bindPyDocument(py::module& mod) { mod.def("createDocument", &mx::createDocument); - py::class_(mod, "Document") + py::class_(mod, "Document") .def("initialize", &mx::Document::initialize) .def("copy", &mx::Document::copy) .def("importLibrary", &mx::Document::importLibrary, diff --git a/source/PyMaterialX/PyGeom.cpp b/source/PyMaterialX/PyGeom.cpp index 38ebbe0751..59476d46df 100644 --- a/source/PyMaterialX/PyGeom.cpp +++ b/source/PyMaterialX/PyGeom.cpp @@ -64,7 +64,8 @@ void bindPyGeom(py::module& mod) .def("hasIncludeCollectionString", &mx::Collection::hasIncludeCollectionString) .def("getIncludeCollectionString", &mx::Collection::getIncludeCollectionString) .def("setIncludeCollection", &mx::Collection::setIncludeCollection) - .def("getIncludeCollection", &mx::Collection::getIncludeCollection) + .def("setIncludeCollections", &mx::Collection::setIncludeCollections) + .def("getIncludeCollections", &mx::Collection::getIncludeCollections) .def("hasIncludeCycle", &mx::Collection::hasIncludeCycle) .def("matchesGeomString", &mx::Collection::matchesGeomString) .def_readonly_static("CATEGORY", &mx::Collection::CATEGORY); diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index c7db01fc95..673d7bc301 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -24,8 +24,6 @@ void bindPyInterface(py::module& mod) py::class_(mod, "PortElement") .def("setNodeName", &mx::PortElement::setNodeName) .def("getNodeName", &mx::PortElement::getNodeName) - .def("setChannels", &mx::PortElement::setChannels) - .def("getChannels", &mx::PortElement::getChannels) .def("setConnectedNode", &mx::PortElement::setConnectedNode) .def("getConnectedNode", &mx::PortElement::getConnectedNode); diff --git a/source/PyMaterialX/PyMaterial.cpp b/source/PyMaterialX/PyMaterial.cpp index 826d76d6b4..f528921b9f 100644 --- a/source/PyMaterialX/PyMaterial.cpp +++ b/source/PyMaterialX/PyMaterial.cpp @@ -40,8 +40,10 @@ void bindPyMaterial(py::module& mod) py::class_(mod, "BindInput") .def("setNodeGraphString", &mx::BindInput::setNodeGraphString) + .def("hasNodeGraphString", &mx::BindInput::hasNodeGraphString) .def("getNodeGraphString", &mx::BindInput::getNodeGraphString) .def("setOutputString", &mx::BindInput::setOutputString) + .def("hasOutputString", &mx::BindInput::hasOutputString) .def("getOutputString", &mx::BindInput::getOutputString) .def("setConnectedOutput", &mx::BindInput::setConnectedOutput) .def("getConnectedOutput", &mx::BindInput::getConnectedOutput) diff --git a/source/PyMaterialX/PyNode.cpp b/source/PyMaterialX/PyNode.cpp index f2d4456282..39b512a9ca 100644 --- a/source/PyMaterialX/PyNode.cpp +++ b/source/PyMaterialX/PyNode.cpp @@ -25,12 +25,7 @@ void bindPyNode(py::module& mod) .def("getDownstreamPorts", &mx::Node::getDownstreamPorts) .def_readonly_static("CATEGORY", &mx::Node::CATEGORY); - py::class_(mod, "NodeGraph") - .def("setNodeDefString", &mx::NodeGraph::setNodeDefString) - .def("hasNodeDefString", &mx::NodeGraph::hasNodeDefString) - .def("getNodeDefString", &mx::NodeGraph::getNodeDefString) - .def("setNodeDef", &mx::NodeGraph::setNodeDef) - .def("getNodeDef", &mx::NodeGraph::getNodeDef) + py::class_(mod, "GraphElement") .def("_addNode", &mx::NodeGraph::addNode, py::arg("category"), py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("addNodeInstance", &mx::NodeGraph::addNodeInstance, @@ -42,6 +37,13 @@ void bindPyNode(py::module& mod) .def("flattenSubgraphs", &mx::NodeGraph::flattenSubgraphs, py::arg("target") = mx::EMPTY_STRING) .def("topologicalSort", &mx::NodeGraph::topologicalSort) - .def("asStringDot", &mx::NodeGraph::asStringDot) + .def("asStringDot", &mx::NodeGraph::asStringDot); + + py::class_(mod, "NodeGraph") + .def("setNodeDefString", &mx::NodeGraph::setNodeDefString) + .def("hasNodeDefString", &mx::NodeGraph::hasNodeDefString) + .def("getNodeDefString", &mx::NodeGraph::getNodeDefString) + .def("setNodeDef", &mx::NodeGraph::setNodeDef) + .def("getNodeDef", &mx::NodeGraph::getNodeDef) .def_readonly_static("CATEGORY", &mx::NodeGraph::CATEGORY); } From 453bacf1eeda460a32358eb10842701c661137b5 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 11 Jun 2018 10:55:35 -0700 Subject: [PATCH 15/27] Add support for interface versions in v1.36 This changelist adds support for Node, NodeDef, and Implementation versions, matching the behavior described in the v1.36 specification. --- source/MaterialXCore/Definition.cpp | 3 +- source/MaterialXCore/Document.cpp | 19 +++-------- source/MaterialXCore/Document.h | 40 ++++++---------------- source/MaterialXCore/Interface.cpp | 42 ++++++++++++++++++++++- source/MaterialXCore/Interface.h | 53 ++++++++++++++++++++++++++++- source/MaterialXCore/Material.h | 6 ++-- source/MaterialXCore/Node.cpp | 1 + source/MaterialXTest/Node.cpp | 10 ++++++ source/PyMaterialX/PyDocument.cpp | 5 +-- source/PyMaterialX/PyInterface.cpp | 7 ++++ 10 files changed, 132 insertions(+), 54 deletions(-) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 97635b4c23..ac8f6640fe 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -39,7 +39,8 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target, const strin interfaces.insert(interfaces.end(), secondary.begin(), secondary.end()); for (InterfaceElementPtr interface : interfaces) { - if (!targetStringsMatch(interface->getTarget(), target)) + if (!targetStringsMatch(interface->getTarget(), target) || + !interface->isVersionCompatible(getSelf()->asA())) { continue; } diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 04c45b3148..a984807302 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -12,7 +12,6 @@ namespace MaterialX { -const string Document::VERSION_ATTRIBUTE = "version"; const string Document::CMS_ATTRIBUTE = "cms"; const string Document::CMS_CONFIG_ATTRIBUTE = "cmsconfig"; @@ -181,23 +180,13 @@ void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOp } } -std::pair Document::getVersionIntegers() +std::pair Document::getVersionIntegers() const { - string versionString = getVersionString(); - if (versionString.empty()) + if (!hasVersionString()) { - return std::pair(MATERIALX_MAJOR_VERSION, - MATERIALX_MINOR_VERSION); + return {MATERIALX_MAJOR_VERSION, MATERIALX_MINOR_VERSION}; } - - StringVec splitVersion = splitString(versionString, "."); - if (splitVersion.size() == 2) - { - return std::pair(std::stoi(splitVersion[0]), - std::stoi(splitVersion[1])); - } - - return std::pair(0, 0); + return InterfaceElement::getVersionIntegers(); } vector Document::getMatchingPorts(const string& nodeName) const diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 7e5618b236..5d73722b67 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -65,34 +65,6 @@ class Document : public GraphElement /// import function. Defaults to a null pointer. void importLibrary(ConstDocumentPtr library, const class CopyOptions* copyOptions = nullptr); - /// @name Document Versions - /// @{ - - /// Set the version string of the document. - void setVersionString(const string& version) - { - setAttribute(VERSION_ATTRIBUTE, version); - } - - /// Return true if the given element has a version string. - bool hasVersionString() const - { - return hasAttribute(VERSION_ATTRIBUTE); - } - - /// Return the version string of the document. - const string& getVersionString() const - { - return getAttribute(VERSION_ATTRIBUTE); - } - - /// Return the major and minor versions as an integer pair. - std::pair getVersionIntegers(); - - /// Upgrade the content of this document from earlier supported versions to - /// the library version. Documents from future versions are left unmodified. - void upgradeVersion(); - /// @} /// @name NodeGraph Elements /// @{ @@ -439,6 +411,17 @@ class Document : public GraphElement /// Implementation element or NodeGraph element. vector getMatchingImplementations(const string& nodeDef) const; + /// @} + /// @name Version + /// @{ + + /// Return the major and minor versions as an integer pair. + std::pair getVersionIntegers() const override; + + /// Upgrade the content of this document from earlier supported versions to + /// the library version. Documents from future versions are left unmodified. + void upgradeVersion(); + /// @} /// @name Color Management System /// @{ @@ -535,7 +518,6 @@ class Document : public GraphElement public: static const string CATEGORY; - static const string VERSION_ATTRIBUTE; static const string CMS_ATTRIBUTE; static const string CMS_CONFIG_ATTRIBUTE; diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index e984970e80..0a7aed4db6 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -13,6 +14,8 @@ namespace MaterialX const string PortElement::NODE_NAME_ATTRIBUTE = "nodename"; const string PortElement::OUTPUT_ATTRIBUTE = "output"; +const string InterfaceElement::VERSION_ATTRIBUTE = "version"; +const string InterfaceElement::DEFAULT_VERSION_ATTRIBUTE = "isdefaultversion"; // // PortElement methods @@ -286,6 +289,30 @@ vector InterfaceElement::getActiveTokens() const return activeTokens; } +std::pair InterfaceElement::getVersionIntegers() const +{ + string versionString = getVersionString(); + StringVec splitVersion = splitString(versionString, "."); + try + { + if (splitVersion.size() == 2) + { + return {std::stoi(splitVersion[0]), std::stoi(splitVersion[1])}; + } + else if (splitVersion.size() == 1) + { + return {std::stoi(splitVersion[0]), 0}; + } + } + catch (std::invalid_argument&) + { + } + catch (std::out_of_range&) + { + } + return {0, 0}; +} + ValueElementPtr InterfaceElement::getActiveValueElement(const string& name) const { for (ConstElementPtr elem : traverseInheritance()) @@ -406,7 +433,7 @@ NodeDefPtr InterfaceElement::getDeclaration(const string& target) const return NodeDefPtr(); } -bool InterfaceElement::isTypeCompatible(InterfaceElementPtr rhs) const +bool InterfaceElement::isTypeCompatible(ConstInterfaceElementPtr rhs) const { if (getType() != rhs->getType()) { @@ -431,4 +458,17 @@ bool InterfaceElement::isTypeCompatible(InterfaceElementPtr rhs) const return true; } +bool InterfaceElement::isVersionCompatible(ConstNodeDefPtr nodeDef) const +{ + if (getVersionIntegers() == nodeDef->getVersionIntegers()) + { + return true; + } + if (!hasVersionString() && nodeDef->getDefaultVersion()) + { + return true; + } + return false; +} + } // namespace MaterialX diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index c17f3345e6..968f8cf7e0 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -261,8 +261,50 @@ class InterfaceElement : public TypedElement protected: using NodeDefPtr = shared_ptr; + using ConstNodeDefPtr = shared_ptr; public: + /// @name Version + /// @{ + + /// Set the version string of the interface. + void setVersionString(const string& version) + { + setAttribute(VERSION_ATTRIBUTE, version); + } + + /// Return true if the given interface has a version string. + bool hasVersionString() const + { + return hasAttribute(VERSION_ATTRIBUTE); + } + + /// Return the version string of the interface. + const string& getVersionString() const + { + return getAttribute(VERSION_ATTRIBUTE); + } + + /// Return the major and minor versions as an integer pair. + virtual std::pair getVersionIntegers() const; + + /// @} + /// @name Default Version + /// @{ + + /// Set the default version flag of the interface. + void setDefaultVersion(bool defaultVersion) + { + setTypedAttribute(DEFAULT_VERSION_ATTRIBUTE, defaultVersion); + } + + /// Return the default version flag of the interface. + bool getDefaultVersion() const + { + return getTypedAttribute(DEFAULT_VERSION_ATTRIBUTE); + } + + /// @} /// @name Parameters /// @{ @@ -544,10 +586,19 @@ class InterfaceElement : public TypedElement /// with identical names but different types, then false is returned. Note /// that a Parameter or Input that is present in only one of the two /// interfaces does not affect their type compatibility. - bool isTypeCompatible(InterfaceElementPtr rhs) const; + bool isTypeCompatible(ConstInterfaceElementPtr rhs) const; + + /// Return true if the given NodeDef is version compatible with this + /// interface element. This may be used to test, for example, whether + /// a NodeDef and Implementation may be used together. + bool isVersionCompatible(ConstNodeDefPtr nodeDef) const; /// @} + public: + static const string VERSION_ATTRIBUTE; + static const string DEFAULT_VERSION_ATTRIBUTE; + protected: void registerChildElement(ElementPtr child) override; void unregisterChildElement(ElementPtr child) override; diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index 302a87be5d..ec11cabda9 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -421,8 +421,8 @@ class ShaderRef : public Element /// @name Output References /// @{ - /// Return the set of outputs that this element references. - std::set getReferencedOutputs() const + /// Return a vector of all outputs that this element references. + vector getReferencedOutputs() const { std::set outputs; for (BindInputPtr bindInput : getBindInputs()) @@ -433,7 +433,7 @@ class ShaderRef : public Element outputs.insert(output); } } - return outputs; + return vector(outputs.begin(), outputs.end()); } /// @} diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 1de9f55d50..99fb697e9b 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -76,6 +76,7 @@ NodeDefPtr Node::getNodeDef(const string& target) const for (NodeDefPtr nodeDef : nodeDefs) { if (targetStringsMatch(target, nodeDef->getTarget()) && + isVersionCompatible(nodeDef) && isTypeCompatible(nodeDef)) { return nodeDef; diff --git a/source/MaterialXTest/Node.cpp b/source/MaterialXTest/Node.cpp index 5616b252ea..ae52f6de95 100644 --- a/source/MaterialXTest/Node.cpp +++ b/source/MaterialXTest/Node.cpp @@ -79,6 +79,16 @@ TEST_CASE("Node", "[node]") custom->setParameterValue("octaves", 5); REQUIRE(custom->getParameterValue("octaves")->asA() == 5); + // Set nodedef and node version strings. + customNodeDef->setVersionString("2.0"); + REQUIRE(custom->getNodeDef() == nullptr); + customNodeDef->setDefaultVersion(true); + REQUIRE(custom->getNodeDef() == customNodeDef); + custom->setVersionString("1"); + REQUIRE(custom->getNodeDef() == nullptr); + custom->setVersionString("2"); + REQUIRE(custom->getNodeDef() == customNodeDef); + // Define a custom type. mx::TypeDefPtr typeDef = doc->addTypeDef("spectrum"); const int scalarCount = 10; diff --git a/source/PyMaterialX/PyDocument.cpp b/source/PyMaterialX/PyDocument.cpp index d378750be9..d5d81dabd7 100644 --- a/source/PyMaterialX/PyDocument.cpp +++ b/source/PyMaterialX/PyDocument.cpp @@ -19,10 +19,6 @@ void bindPyDocument(py::module& mod) .def("copy", &mx::Document::copy) .def("importLibrary", &mx::Document::importLibrary, py::arg("library"), py::arg("copyOptions") = (const mx::CopyOptions*) nullptr) - .def("setVersionString", &mx::Document::setVersionString) - .def("hasVersionString", &mx::Document::hasVersionString) - .def("getVersionString", &mx::Document::getVersionString) - .def("getVersionIntegers", &mx::Document::getVersionIntegers) .def("addNodeGraph", &mx::Document::addNodeGraph, py::arg("name") = mx::EMPTY_STRING) .def("getNodeGraph", &mx::Document::getNodeGraph) @@ -76,6 +72,7 @@ void bindPyDocument(py::module& mod) .def("getImplementation", &mx::Document::getImplementation) .def("getImplementations", &mx::Document::getImplementations) .def("removeImplementation", &mx::Document::removeImplementation) + .def("upgradeVersion", &mx::Document::upgradeVersion) .def("setColorManagementSystem", &mx::Document::setColorManagementSystem) .def("hasColorManagementSystem", &mx::Document::hasColorManagementSystem) .def("getColorManagementSystem", &mx::Document::getColorManagementSystem) diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index 673d7bc301..2feb159c0c 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -35,6 +35,12 @@ void bindPyInterface(py::module& mod) .def_readonly_static("CATEGORY", &mx::Output::CATEGORY); py::class_(mod, "InterfaceElement") + .def("setVersionString", &mx::InterfaceElement::setVersionString) + .def("hasVersionString", &mx::InterfaceElement::hasVersionString) + .def("getVersionString", &mx::InterfaceElement::getVersionString) + .def("getVersionIntegers", &mx::InterfaceElement::getVersionIntegers) + .def("setDefaultVersion", &mx::InterfaceElement::setDefaultVersion) + .def("getDefaultVersion", &mx::InterfaceElement::getDefaultVersion) .def("addParameter", &mx::InterfaceElement::addParameter, py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getParameter", &mx::InterfaceElement::getParameter) @@ -75,6 +81,7 @@ void bindPyInterface(py::module& mod) .def("getDeclaration", &mx::InterfaceElement::getDeclaration, py::arg("target") = mx::EMPTY_STRING) .def("isTypeCompatible", &mx::InterfaceElement::isTypeCompatible) + .def("isVersionCompatible", &mx::InterfaceElement::isVersionCompatible) BIND_INTERFACE_TYPE_INSTANCE(integer, int) BIND_INTERFACE_TYPE_INSTANCE(boolean, bool) BIND_INTERFACE_TYPE_INSTANCE(float, float) From df9526bcc18f6b89c7fd46c619088267f6a8f543 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 13 Jun 2018 13:19:57 -0700 Subject: [PATCH 16/27] Add standard library documents to CMake installation --- CMakeLists.txt | 5 +---- documents/CMakeLists.txt | 41 ++++++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fdee162372..faa7f0e42e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,12 +68,9 @@ endif() add_subdirectory(source/MaterialXCore) add_subdirectory(source/MaterialXFormat) add_subdirectory(source/MaterialXTest) +add_subdirectory(documents) if(MATERIALX_BUILD_PYTHON) add_subdirectory(source/PyMaterialX) add_subdirectory(python) endif(MATERIALX_BUILD_PYTHON) - -if(MATERIALX_BUILD_DOCS) - add_subdirectory(documents) -endif(MATERIALX_BUILD_DOCS) diff --git a/documents/CMakeLists.txt b/documents/CMakeLists.txt index 6681d89913..56bd7fec45 100644 --- a/documents/CMakeLists.txt +++ b/documents/CMakeLists.txt @@ -1,20 +1,25 @@ -set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(DOXYGEN_HTML_OUTPUT_DIR ${DOXYGEN_OUTPUT_DIR}/MaterialXDocs) -set(DOXYGEN_INPUT_LIST ${CMAKE_SOURCE_DIR}/documents/DeveloperGuide - ${CMAKE_SOURCE_DIR}/source/MaterialXCore - ${CMAKE_SOURCE_DIR}/source/MaterialXFormat) -string (REPLACE ";" " " DOXYGEN_INPUT_STR "${DOXYGEN_INPUT_LIST}") +install(DIRECTORY ${CMAKE_SOURCE_DIR}/documents/Libraries/ + DESTINATION "${CMAKE_INSTALL_PREFIX}/documents/Libraries") -find_package(Doxygen) +if(MATERIALX_BUILD_DOCS) + set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) + set(DOXYGEN_HTML_OUTPUT_DIR ${DOXYGEN_OUTPUT_DIR}/MaterialXDocs) + set(DOXYGEN_INPUT_LIST ${CMAKE_SOURCE_DIR}/documents/DeveloperGuide + ${CMAKE_SOURCE_DIR}/source/MaterialXCore + ${CMAKE_SOURCE_DIR}/source/MaterialXFormat) + string (REPLACE ";" " " DOXYGEN_INPUT_STR "${DOXYGEN_INPUT_LIST}") -if(DOXYGEN_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - add_custom_target(MaterialXDocs ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") - add_custom_command(TARGET MaterialXDocs PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/documents/Images ${CMAKE_CURRENT_BINARY_DIR}) - install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} - DESTINATION "${CMAKE_INSTALL_PREFIX}/documents") -endif(DOXYGEN_FOUND) + find_package(Doxygen) + + if(DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + add_custom_target(MaterialXDocs ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") + add_custom_command(TARGET MaterialXDocs PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/documents/Images ${CMAKE_CURRENT_BINARY_DIR}) + install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} + DESTINATION "${CMAKE_INSTALL_PREFIX}/documents") + endif(DOXYGEN_FOUND) +endif(MATERIALX_BUILD_DOCS) From 447615ac34a588eade9b1b9ea57a404e877bd467 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 15 Jun 2018 16:33:09 -0700 Subject: [PATCH 17/27] Improvements to type handling for v1.36 - Validate type attributes of example documents in unit tests, and fix related typos in shader examples. - Add helper methods TypedElement::getTypeDef and TypedElement::isMultiOutputType. Also: - Minor clarifications to Element::getDescendant. --- documents/Examples/BxDF/Disney_BSDF_2015.mtlx | 2 +- documents/Examples/BxDF/alSurface.mtlx | 4 +- source/MaterialXCore/Definition.cpp | 2 +- source/MaterialXCore/Element.cpp | 24 ++++++++---- source/MaterialXCore/Element.h | 38 +++++++++++++++---- source/MaterialXTest/XmlIo.cpp | 8 +++- source/PyMaterialX/PyElement.cpp | 4 +- 7 files changed, 61 insertions(+), 21 deletions(-) diff --git a/documents/Examples/BxDF/Disney_BSDF_2015.mtlx b/documents/Examples/BxDF/Disney_BSDF_2015.mtlx index c39f51ac27..a9d39d09c4 100644 --- a/documents/Examples/BxDF/Disney_BSDF_2015.mtlx +++ b/documents/Examples/BxDF/Disney_BSDF_2015.mtlx @@ -15,7 +15,7 @@ - + diff --git a/documents/Examples/BxDF/alSurface.mtlx b/documents/Examples/BxDF/alSurface.mtlx index b9c35738d9..d308e16efd 100644 --- a/documents/Examples/BxDF/alSurface.mtlx +++ b/documents/Examples/BxDF/alSurface.mtlx @@ -49,7 +49,7 @@ helptext="Controls how much the specular highlight is stretched along its axis. The default value of 0.5 produces a round highlight. Higher values will stretch the highlight along the V axis, lower values stretch along the U axis. The axis of the highlight is controlled by the UVs of the object. For best results, give your object a single UV shell with as few seams as possible." /> - @@ -71,7 +71,7 @@ helptext="Controls how much the specular highlight is stretched along its axis. The default value of 0.5 produces a round highlight. Higher values will stretch the highlight along the V axis, lower values stretch along the U axis. The axis of the highlight is controlled by the UVs of the object. For best results, give your object a single UV shell with as few seams as possible." /> - diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index ac8f6640fe..343f9c775d 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -80,7 +80,7 @@ bool NodeDef::validate(string* message) const { bool res = true; validateRequire(hasType(), res, message, "Missing type"); - if (getType() == MULTI_OUTPUT_TYPE_STRING) + if (isMultiOutputType()) { validateRequire(getOutputCount() >= 2, res, message, "Multioutput nodedefs must have two or more output ports"); } diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index f3428ffb30..640d89f65e 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -13,13 +13,13 @@ namespace MaterialX { const string Element::NAME_ATTRIBUTE = "name"; -const string Element::TYPE_ATTRIBUTE = "type"; const string Element::FILE_PREFIX_ATTRIBUTE = "fileprefix"; const string Element::GEOM_PREFIX_ATTRIBUTE = "geomprefix"; const string Element::COLOR_SPACE_ATTRIBUTE = "colorspace"; const string Element::TARGET_ATTRIBUTE = "target"; const string Element::INHERIT_ATTRIBUTE = "inherit"; const string Element::NAMESPACE_ATTRIBUTE = "namespace"; +const string TypedElement::TYPE_ATTRIBUTE = "type"; const string ValueElement::VALUE_ATTRIBUTE = "value"; const string ValueElement::INTERFACE_NAME_ATTRIBUTE = "interfacename"; const string ValueElement::IMPLEMENTATION_NAME_ATTRIBUTE = "implname"; @@ -105,18 +105,19 @@ string Element::getNamePath(ConstElementPtr relativeTo) const return res; } -ElementPtr Element::getDescendant(const string& path) +ElementPtr Element::getDescendant(const string& namePath) { - const StringVec elementNames = splitString(path, NAME_PATH_SEPARATOR); - ElementPtr currentElement = getSelf(); - for (const string& elementName : elementNames) + const StringVec nameVec = splitString(namePath, NAME_PATH_SEPARATOR); + ElementPtr elem = getSelf(); + for (const string& name : nameVec) { - if (!(currentElement = currentElement->getChild(elementName))) + elem = elem->getChild(name); + if (!elem) { return ElementPtr(); } } - return currentElement; + return elem; } void Element::registerChildElement(ElementPtr child) @@ -458,6 +459,15 @@ void Element::validateRequire(bool expression, bool& res, string* message, strin } } +// +// TypedElement methods +// + +TypeDefPtr TypedElement::getTypeDef() const +{ + return resolveRootNameReference(getType()); +} + // // ValueElement methods // diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 07c863585e..096b5a3533 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -121,13 +121,12 @@ class Element : public std::enable_shared_from_this /// the returned path will be relative to this ancestor. string getNamePath(ConstElementPtr relativeTo = nullptr) const; - /// Return the descendant referred to by the hierarchical path relative - /// to the current element. If an empty string is provided as the path - /// then a shared pointer to the current element is returned. If the - /// path cannot be found then an empty shared pointer is returned. - /// @param path The hierarchical path to use to find a descendant - /// relative to the current element. - ElementPtr getDescendant(const string& path); + /// Return the element specified by the given hierarchical name path, + /// relative to the current element. If the name path is empty then the + /// current element is returned. If no element is found at the given path, + /// then an empty shared pointer is returned. + /// @param namePath The relative name path of the specified element. + ElementPtr getDescendant(const string& namePath); /// @} /// @name File Prefix @@ -758,7 +757,6 @@ class Element : public std::enable_shared_from_this public: static const string NAME_ATTRIBUTE; - static const string TYPE_ATTRIBUTE; static const string FILE_PREFIX_ATTRIBUTE; static const string GEOM_PREFIX_ATTRIBUTE; static const string COLOR_SPACE_ATTRIBUTE; @@ -819,6 +817,13 @@ class TypedElement : public Element public: virtual ~TypedElement() { } + protected: + using TypeDefPtr = shared_ptr; + + public: + /// @} + /// @name Type String + /// Set the element's type string. void setType(const string& type) { @@ -836,6 +841,23 @@ class TypedElement : public Element { return getAttribute(TYPE_ATTRIBUTE); } + + /// Return true if the element is of multi-output type. + bool isMultiOutputType() const + { + return getType() == MULTI_OUTPUT_TYPE_STRING; + } + + /// @} + /// @name TypeDef References + /// @{ + + /// Return the TypeDef declaring the type string of this element. If no + /// matching TypeDef is found, then an empty shared pointer is returned. + TypeDefPtr getTypeDef() const; + + public: + static const string TYPE_ATTRIBUTE; }; /// @class ValueElement diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index 8efe4b17ae..3901dd8d0a 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -125,10 +125,16 @@ TEST_CASE("Load content", "[xmlio]") } REQUIRE(doc2->validate()); - // Verify that all referenced nodes are declared and implemented. + // Verify that all referenced types and nodes are declared, and that + // referenced node declarations are implemented. for (mx::ElementPtr elem : doc2->traverseTree()) { + mx::TypedElementPtr typedElem = elem->asA(); mx::NodePtr node = elem->asA(); + if (typedElem && typedElem->hasType() && !typedElem->isMultiOutputType()) + { + REQUIRE(typedElem->getTypeDef()); + } if (node) { REQUIRE(node->getNodeDef()); diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index c1127522d8..f2c3bfb64f 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -133,7 +133,9 @@ void bindPyElement(py::module& mod) py::class_(mod, "TypedElement") .def("setType", &mx::TypedElement::setType) .def("hasType", &mx::TypedElement::hasType) - .def("getType", &mx::TypedElement::getType); + .def("getType", &mx::TypedElement::getType) + .def("isMultiOutputType", &mx::TypedElement::isMultiOutputType) + .def("getTypeDef", &mx::TypedElement::getTypeDef); py::class_(mod, "ValueElement") .def("setValueString", &mx::ValueElement::setValueString) From 644359795ba0e9e14306eab22f6091b6aba0e1ce Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 17 Jun 2018 13:34:44 -0700 Subject: [PATCH 18/27] Add support for ShaderRef qualifiers in v1.36 - Add support for type and version strings on ShaderRef elements. - Update ShaderRef::getNodeDef to support new qualifiers. - Update naming conventions for NodeDef, NodeGraph, and ShaderRef elements in unit tests. --- source/MaterialXCore/Definition.cpp | 15 ++++++++- source/MaterialXCore/Definition.h | 9 +++++ source/MaterialXCore/Document.cpp | 4 +-- source/MaterialXCore/Element.cpp | 26 +++++++++++++++ source/MaterialXCore/Element.h | 47 +++++++++++++++++++++++++- source/MaterialXCore/Interface.cpp | 39 ---------------------- source/MaterialXCore/Interface.h | 51 +---------------------------- source/MaterialXCore/Material.cpp | 14 +++++--- source/MaterialXCore/Material.h | 4 +-- source/MaterialXCore/Node.cpp | 4 +-- source/MaterialXTest/Material.cpp | 20 ++++++++--- source/MaterialXTest/Node.cpp | 2 +- source/MaterialXTest/Observer.cpp | 2 +- source/MaterialXTest/XmlIo.cpp | 16 ++++----- source/PyMaterialX/PyDefinition.cpp | 1 + source/PyMaterialX/PyElement.cpp | 6 ++++ source/PyMaterialX/PyInterface.cpp | 7 ---- source/PyMaterialX/PyMaterial.cpp | 2 +- 18 files changed, 145 insertions(+), 124 deletions(-) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 343f9c775d..95af518ef4 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -40,7 +40,7 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target, const strin for (InterfaceElementPtr interface : interfaces) { if (!targetStringsMatch(interface->getTarget(), target) || - !interface->isVersionCompatible(getSelf()->asA())) + !isVersionCompatible(interface)) { continue; } @@ -91,6 +91,19 @@ bool NodeDef::validate(string* message) const return InterfaceElement::validate(message) && res; } +bool NodeDef::isVersionCompatible(ConstElementPtr elem) const +{ + if (getVersionIntegers() == elem->getVersionIntegers()) + { + return true; + } + if (getDefaultVersion() && !elem->hasVersionString()) + { + return true; + } + return false; +} + // // Implementation methods // diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index ad727e096d..acc0636dbe 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -136,6 +136,15 @@ class NodeDef : public InterfaceElement bool validate(string* message = nullptr) const override; /// @} + /// @name Utility + /// @{ + + /// Return true if the given element is version compatible with this + /// NodeDef. This may be used to test, for example, whether a NodeDef + /// and Node may be used together. + bool isVersionCompatible(ConstElementPtr elem) const; + + /// @} public: static const string CATEGORY; diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index a984807302..bbdbeface5 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -186,7 +186,7 @@ std::pair Document::getVersionIntegers() const { return {MATERIALX_MAJOR_VERSION, MATERIALX_MINOR_VERSION}; } - return InterfaceElement::getVersionIntegers(); + return Element::getVersionIntegers(); } vector Document::getMatchingPorts(const string& nodeName) const @@ -244,7 +244,7 @@ bool Document::validate(string* message) const { bool res = true; validateRequire(hasVersionString(), res, message, "Missing version string"); - return Element::validate(message) && res; + return GraphElement::validate(message) && res; } void Document::upgradeVersion() diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 640d89f65e..a6db9b9dfb 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -17,6 +17,8 @@ const string Element::FILE_PREFIX_ATTRIBUTE = "fileprefix"; const string Element::GEOM_PREFIX_ATTRIBUTE = "geomprefix"; const string Element::COLOR_SPACE_ATTRIBUTE = "colorspace"; const string Element::TARGET_ATTRIBUTE = "target"; +const string Element::VERSION_ATTRIBUTE = "version"; +const string Element::DEFAULT_VERSION_ATTRIBUTE = "isdefaultversion"; const string Element::INHERIT_ATTRIBUTE = "inherit"; const string Element::NAMESPACE_ATTRIBUTE = "namespace"; const string TypedElement::TYPE_ATTRIBUTE = "type"; @@ -120,6 +122,30 @@ ElementPtr Element::getDescendant(const string& namePath) return elem; } +std::pair Element::getVersionIntegers() const +{ + string versionString = getVersionString(); + StringVec splitVersion = splitString(versionString, "."); + try + { + if (splitVersion.size() == 2) + { + return {std::stoi(splitVersion[0]), std::stoi(splitVersion[1])}; + } + else if (splitVersion.size() == 1) + { + return {std::stoi(splitVersion[0]), 0}; + } + } + catch (std::invalid_argument&) + { + } + catch (std::out_of_range&) + { + } + return {0, 0}; +} + void Element::registerChildElement(ElementPtr child) { DocumentPtr doc = getDocument(); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 096b5a3533..18382d39e3 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -342,6 +342,47 @@ class Element : public std::enable_shared_from_this return name; } + /// @} + /// @name Version + /// @{ + + /// Set the version string of this element. + void setVersionString(const string& version) + { + setAttribute(VERSION_ATTRIBUTE, version); + } + + /// Return true if this element has a version string. + bool hasVersionString() const + { + return hasAttribute(VERSION_ATTRIBUTE); + } + + /// Return the version string of this element. + const string& getVersionString() const + { + return getAttribute(VERSION_ATTRIBUTE); + } + + /// Return the major and minor versions as an integer pair. + virtual std::pair getVersionIntegers() const; + + /// @} + /// @name Default Version + /// @{ + + /// Set the default version flag of this element. + void setDefaultVersion(bool defaultVersion) + { + setTypedAttribute(DEFAULT_VERSION_ATTRIBUTE, defaultVersion); + } + + /// Return the default version flag of this element. + bool getDefaultVersion() const + { + return getTypedAttribute(DEFAULT_VERSION_ATTRIBUTE); + } + /// @} /// @name Subclass /// @{ @@ -761,6 +802,8 @@ class Element : public std::enable_shared_from_this static const string GEOM_PREFIX_ATTRIBUTE; static const string COLOR_SPACE_ATTRIBUTE; static const string TARGET_ATTRIBUTE; + static const string VERSION_ATTRIBUTE; + static const string DEFAULT_VERSION_ATTRIBUTE; static const string INHERIT_ATTRIBUTE; static const string NAMESPACE_ATTRIBUTE; @@ -856,7 +899,9 @@ class TypedElement : public Element /// matching TypeDef is found, then an empty shared pointer is returned. TypeDefPtr getTypeDef() const; - public: + /// @} + +public: static const string TYPE_ATTRIBUTE; }; diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 0a7aed4db6..004f017d57 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -14,8 +14,6 @@ namespace MaterialX const string PortElement::NODE_NAME_ATTRIBUTE = "nodename"; const string PortElement::OUTPUT_ATTRIBUTE = "output"; -const string InterfaceElement::VERSION_ATTRIBUTE = "version"; -const string InterfaceElement::DEFAULT_VERSION_ATTRIBUTE = "isdefaultversion"; // // PortElement methods @@ -289,30 +287,6 @@ vector InterfaceElement::getActiveTokens() const return activeTokens; } -std::pair InterfaceElement::getVersionIntegers() const -{ - string versionString = getVersionString(); - StringVec splitVersion = splitString(versionString, "."); - try - { - if (splitVersion.size() == 2) - { - return {std::stoi(splitVersion[0]), std::stoi(splitVersion[1])}; - } - else if (splitVersion.size() == 1) - { - return {std::stoi(splitVersion[0]), 0}; - } - } - catch (std::invalid_argument&) - { - } - catch (std::out_of_range&) - { - } - return {0, 0}; -} - ValueElementPtr InterfaceElement::getActiveValueElement(const string& name) const { for (ConstElementPtr elem : traverseInheritance()) @@ -458,17 +432,4 @@ bool InterfaceElement::isTypeCompatible(ConstInterfaceElementPtr rhs) const return true; } -bool InterfaceElement::isVersionCompatible(ConstNodeDefPtr nodeDef) const -{ - if (getVersionIntegers() == nodeDef->getVersionIntegers()) - { - return true; - } - if (!hasVersionString() && nodeDef->getDefaultVersion()) - { - return true; - } - return false; -} - } // namespace MaterialX diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 968f8cf7e0..32d3408bd3 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -264,46 +264,6 @@ class InterfaceElement : public TypedElement using ConstNodeDefPtr = shared_ptr; public: - /// @name Version - /// @{ - - /// Set the version string of the interface. - void setVersionString(const string& version) - { - setAttribute(VERSION_ATTRIBUTE, version); - } - - /// Return true if the given interface has a version string. - bool hasVersionString() const - { - return hasAttribute(VERSION_ATTRIBUTE); - } - - /// Return the version string of the interface. - const string& getVersionString() const - { - return getAttribute(VERSION_ATTRIBUTE); - } - - /// Return the major and minor versions as an integer pair. - virtual std::pair getVersionIntegers() const; - - /// @} - /// @name Default Version - /// @{ - - /// Set the default version flag of the interface. - void setDefaultVersion(bool defaultVersion) - { - setTypedAttribute(DEFAULT_VERSION_ATTRIBUTE, defaultVersion); - } - - /// Return the default version flag of the interface. - bool getDefaultVersion() const - { - return getTypedAttribute(DEFAULT_VERSION_ATTRIBUTE); - } - /// @} /// @name Parameters /// @{ @@ -577,7 +537,7 @@ class InterfaceElement : public TypedElement /// Return true if the given interface element is type compatible with /// this one. This may be used to test, for example, whether a NodeDef - /// and Implementation may be used together. + /// and Node may be used together. /// /// If the type string of the given interface element differs from this /// one, then false is returned. @@ -588,17 +548,8 @@ class InterfaceElement : public TypedElement /// interfaces does not affect their type compatibility. bool isTypeCompatible(ConstInterfaceElementPtr rhs) const; - /// Return true if the given NodeDef is version compatible with this - /// interface element. This may be used to test, for example, whether - /// a NodeDef and Implementation may be used together. - bool isVersionCompatible(ConstNodeDefPtr nodeDef) const; - /// @} - public: - static const string VERSION_ATTRIBUTE; - static const string DEFAULT_VERSION_ATTRIBUTE; - protected: void registerChildElement(ElementPtr child) override; void unregisterChildElement(ElementPtr child) override; diff --git a/source/MaterialXCore/Material.cpp b/source/MaterialXCore/Material.cpp index d05abffe69..8a2f3d50f8 100644 --- a/source/MaterialXCore/Material.cpp +++ b/source/MaterialXCore/Material.cpp @@ -177,11 +177,17 @@ NodeDefPtr ShaderRef::getNodeDef() const if (hasNodeString()) { vector nodeDefs = getDocument()->getMatchingNodeDefs(getQualifiedName(getNodeString())); - if (nodeDefs.empty()) + vector secondary = getDocument()->getMatchingNodeDefs(getNodeString()); + nodeDefs.insert(nodeDefs.end(), secondary.begin(), secondary.end()); + for (NodeDefPtr nodeDef : nodeDefs) { - nodeDefs = getDocument()->getMatchingNodeDefs(getNodeString()); + if (targetStringsMatch(nodeDef->getTarget(), getTarget()) && + nodeDef->isVersionCompatible(getSelf()) && + (!hasType() || nodeDef->getType() == getType())) + { + return nodeDef; + } } - return nodeDefs.empty() ? NodeDefPtr() : nodeDefs[0]; } return NodeDefPtr(); } @@ -199,7 +205,7 @@ bool ShaderRef::validate(string* message) const { validateRequire(typeDef->getSemantic() == SHADER_SEMANTIC, res, message, "Shader reference to a non-shader nodedef"); } - return Element::validate(message) && res; + return TypedElement::validate(message) && res; } Edge ShaderRef::getUpstreamEdge(ConstMaterialPtr material, size_t index) const diff --git a/source/MaterialXCore/Material.h b/source/MaterialXCore/Material.h index ec11cabda9..00fb12bd37 100644 --- a/source/MaterialXCore/Material.h +++ b/source/MaterialXCore/Material.h @@ -285,11 +285,11 @@ class BindInput : public ValueElement /// A shader reference element within a Material. /// /// A ShaderRef instantiates a shader NodeDef within the context of a Material. -class ShaderRef : public Element +class ShaderRef : public TypedElement { public: ShaderRef(ElementPtr parent, const string& name) : - Element(parent, CATEGORY, name) + TypedElement(parent, CATEGORY, name) { } virtual ~ShaderRef() { } diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 99fb697e9b..36fd1615a8 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -75,8 +75,8 @@ NodeDefPtr Node::getNodeDef(const string& target) const nodeDefs.insert(nodeDefs.end(), secondary.begin(), secondary.end()); for (NodeDefPtr nodeDef : nodeDefs) { - if (targetStringsMatch(target, nodeDef->getTarget()) && - isVersionCompatible(nodeDef) && + if (targetStringsMatch(nodeDef->getTarget(), target) && + nodeDef->isVersionCompatible(getSelf()) && isTypeCompatible(nodeDef)) { return nodeDef; diff --git a/source/MaterialXTest/Material.cpp b/source/MaterialXTest/Material.cpp index 92c87787bc..d0973d1405 100644 --- a/source/MaterialXTest/Material.cpp +++ b/source/MaterialXTest/Material.cpp @@ -15,7 +15,7 @@ TEST_CASE("Material", "[material]") mx::DocumentPtr doc = mx::createDocument(); // Create a base shader nodedef. - mx::NodeDefPtr simpleSrf = doc->addNodeDef("nd_simpleSrf", "surfaceshader", "simpleSrf"); + mx::NodeDefPtr simpleSrf = doc->addNodeDef("ND_simpleSrf", "surfaceshader", "simpleSrf"); mx::InputPtr diffColor = simpleSrf->setInputValue("diffColor", mx::Color3(1.0f)); mx::InputPtr specColor = simpleSrf->setInputValue("specColor", mx::Color3(0.0f)); mx::ParameterPtr roughness = simpleSrf->setParameterValue("roughness", 0.25f); @@ -24,7 +24,7 @@ TEST_CASE("Material", "[material]") REQUIRE(simpleSrf->getParameterValue("roughness")->asA() == 0.25f); // Create an inherited shader nodedef. - mx::NodeDefPtr anisoSrf = doc->addNodeDef("nd_anisoSrf", "surfaceshader", "anisoSrf"); + mx::NodeDefPtr anisoSrf = doc->addNodeDef("ND_anisoSrf", "surfaceshader", "anisoSrf"); anisoSrf->setInheritsFrom(simpleSrf); mx::ParameterPtr anisotropy = anisoSrf->setParameterValue("anisotropy", 0.0f); REQUIRE(anisoSrf->getInheritsFrom() == simpleSrf); @@ -34,13 +34,23 @@ TEST_CASE("Material", "[material]") REQUIRE(material->getPrimaryShaderName().empty()); // Add a shader reference. - mx::ShaderRefPtr refAnisoSrf = material->addShaderRef("sr_anisoSrf", "anisoSrf"); + mx::ShaderRefPtr refAnisoSrf = material->addShaderRef("SR_anisoSrf", "anisoSrf"); REQUIRE(anisoSrf->getInstantiatingShaderRefs()[0] == refAnisoSrf); REQUIRE(refAnisoSrf->getNodeDef() == anisoSrf); REQUIRE(material->getPrimaryShaderName() == refAnisoSrf->getNodeString()); REQUIRE(material->getPrimaryShaderParameters().size() == 2); REQUIRE(material->getPrimaryShaderInputs().size() == 2); + // Set nodedef and shader reference qualifiers. + refAnisoSrf->setVersionString("2.0"); + REQUIRE(refAnisoSrf->getNodeDef() == nullptr); + anisoSrf->setVersionString("2"); + REQUIRE(refAnisoSrf->getNodeDef() == anisoSrf); + refAnisoSrf->setType("volumeshader"); + REQUIRE(refAnisoSrf->getNodeDef() == nullptr); + refAnisoSrf->setType("surfaceshader"); + REQUIRE(refAnisoSrf->getNodeDef() == anisoSrf); + // Bind a shader input to a value. mx::BindInputPtr bindInput = refAnisoSrf->addBindInput("specColor"); bindInput->setValue(mx::Color3(0.5f)); @@ -54,9 +64,9 @@ TEST_CASE("Material", "[material]") REQUIRE(roughness->getDefaultValue()->asA() == 0.25f); // Add an invalid shader reference. - mx::ShaderRefPtr refInvalid = material->addShaderRef("sr_invalidSrf", "invalidSrf"); + mx::ShaderRefPtr refInvalid = material->addShaderRef("SR_invalidSrf", "invalidSrf"); REQUIRE(!doc->validate()); - material->removeShaderRef("sr_invalidSrf"); + material->removeShaderRef("SR_invalidSrf"); REQUIRE(doc->validate()); // Create an inherited material. diff --git a/source/MaterialXTest/Node.cpp b/source/MaterialXTest/Node.cpp index ae52f6de95..6df9c14b9c 100644 --- a/source/MaterialXTest/Node.cpp +++ b/source/MaterialXTest/Node.cpp @@ -65,7 +65,7 @@ TEST_CASE("Node", "[node]") REQUIRE(image->getDownstreamPorts()[0] == output2); // Create a custom nodedef. - mx::NodeDefPtr customNodeDef = doc->addNodeDef("nodeDef1", "float", "turbulence3d"); + mx::NodeDefPtr customNodeDef = doc->addNodeDef("ND_turbulence3d", "float", "turbulence3d"); customNodeDef->setNodeCategory(mx::PROCEDURAL_NODE_CATEGORY); customNodeDef->setParameterValue("octaves", 3); customNodeDef->setParameterValue("lacunarity", 2.0f); diff --git a/source/MaterialXTest/Observer.cpp b/source/MaterialXTest/Observer.cpp index 4b46d72a90..2212968334 100644 --- a/source/MaterialXTest/Observer.cpp +++ b/source/MaterialXTest/Observer.cpp @@ -118,7 +118,7 @@ TEST_CASE("Observer", "[observer]") output->setConnectedNode(constant); // Create a simple shader interface. - mx::NodeDefPtr shader = doc->addNodeDef("shader1", "surfaceshader", "simpleSrf"); + mx::NodeDefPtr shader = doc->addNodeDef("ND_simpleSrf", "surfaceshader", "simpleSrf"); shader->addInput("diffColor", "color3"); shader->addInput("specColor", "color3"); shader->addParameter("roughness", "float"); diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index 3901dd8d0a..ed79b6aac9 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -145,19 +145,19 @@ TEST_CASE("Load content", "[xmlio]") // Create a namespaced custom library. mx::DocumentPtr customLibrary = mx::createDocument(); customLibrary->setNamespace("custom"); - mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("nodegraph1"); - mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("shader1", "surfaceshader", "simpleSrf"); - mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "node1"); - mx::ImplementationPtr customImpl = customLibrary->addImplementation("impl1"); + mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("NG_custom"); + mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("ND_simpleSrf", "surfaceshader", "simpleSrf"); + mx::ImplementationPtr customImpl = customLibrary->addImplementation("IM_custom"); + mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "custom1"); customImpl->setNodeDef(customNodeDef); REQUIRE(customLibrary->validate()); // Import the custom library. doc2->importLibrary(customLibrary); - mx::NodeGraphPtr importedNodeGraph = doc2->getNodeGraph("custom:nodegraph1"); - mx::NodeDefPtr importedNodeDef = doc2->getNodeDef("custom:shader1"); - mx::NodePtr importedNode = importedNodeGraph->getNode("node1"); - mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:impl1"); + mx::NodeGraphPtr importedNodeGraph = doc2->getNodeGraph("custom:NG_custom"); + mx::NodeDefPtr importedNodeDef = doc2->getNodeDef("custom:ND_simpleSrf"); + mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:IM_custom"); + mx::NodePtr importedNode = importedNodeGraph->getNode("custom1"); REQUIRE(importedNodeDef != nullptr); REQUIRE(importedNode->getNodeDef() == importedNodeDef); REQUIRE(importedImpl->getNodeDef() == importedNodeDef); diff --git a/source/PyMaterialX/PyDefinition.cpp b/source/PyMaterialX/PyDefinition.cpp index b5ac07d2f4..dd836711f7 100644 --- a/source/PyMaterialX/PyDefinition.cpp +++ b/source/PyMaterialX/PyDefinition.cpp @@ -26,6 +26,7 @@ void bindPyDefinition(py::module& mod) py::arg("target") = mx::EMPTY_STRING, py::arg("language") = mx::EMPTY_STRING) .def("getInstantiatingShaderRefs", &mx::NodeDef::getInstantiatingShaderRefs) + .def("isVersionCompatible", &mx::NodeDef::isVersionCompatible) .def_readonly_static("CATEGORY", &mx::NodeDef::CATEGORY) .def_readonly_static("NODE_ATTRIBUTE", &mx::NodeDef::NODE_ATTRIBUTE); diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index f2c3bfb64f..b8d4f91488 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -66,6 +66,12 @@ void bindPyElement(py::module& mod) .def("hasNamespace", &mx::Element::hasNamespace) .def("getNamespace", &mx::Element::getNamespace) .def("getQualifiedName", &mx::Element::getQualifiedName) + .def("setVersionString", &mx::Element::setVersionString) + .def("hasVersionString", &mx::Element::hasVersionString) + .def("getVersionString", &mx::Element::getVersionString) + .def("getVersionIntegers", &mx::Element::getVersionIntegers) + .def("setDefaultVersion", &mx::Element::setDefaultVersion) + .def("getDefaultVersion", &mx::Element::getDefaultVersion) .def("addChildOfCategory", &mx::Element::addChildOfCategory) .def("_getChild", &mx::Element::getChild) .def("getChildren", &mx::Element::getChildren) diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index 2feb159c0c..673d7bc301 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -35,12 +35,6 @@ void bindPyInterface(py::module& mod) .def_readonly_static("CATEGORY", &mx::Output::CATEGORY); py::class_(mod, "InterfaceElement") - .def("setVersionString", &mx::InterfaceElement::setVersionString) - .def("hasVersionString", &mx::InterfaceElement::hasVersionString) - .def("getVersionString", &mx::InterfaceElement::getVersionString) - .def("getVersionIntegers", &mx::InterfaceElement::getVersionIntegers) - .def("setDefaultVersion", &mx::InterfaceElement::setDefaultVersion) - .def("getDefaultVersion", &mx::InterfaceElement::getDefaultVersion) .def("addParameter", &mx::InterfaceElement::addParameter, py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getParameter", &mx::InterfaceElement::getParameter) @@ -81,7 +75,6 @@ void bindPyInterface(py::module& mod) .def("getDeclaration", &mx::InterfaceElement::getDeclaration, py::arg("target") = mx::EMPTY_STRING) .def("isTypeCompatible", &mx::InterfaceElement::isTypeCompatible) - .def("isVersionCompatible", &mx::InterfaceElement::isVersionCompatible) BIND_INTERFACE_TYPE_INSTANCE(integer, int) BIND_INTERFACE_TYPE_INSTANCE(boolean, bool) BIND_INTERFACE_TYPE_INSTANCE(float, float) diff --git a/source/PyMaterialX/PyMaterial.cpp b/source/PyMaterialX/PyMaterial.cpp index f528921b9f..2b2004befa 100644 --- a/source/PyMaterialX/PyMaterial.cpp +++ b/source/PyMaterialX/PyMaterial.cpp @@ -49,7 +49,7 @@ void bindPyMaterial(py::module& mod) .def("getConnectedOutput", &mx::BindInput::getConnectedOutput) .def_readonly_static("CATEGORY", &mx::BindInput::CATEGORY); - py::class_(mod, "ShaderRef") + py::class_(mod, "ShaderRef") .def("setNodeString", &mx::ShaderRef::setNodeString) .def("hasNodeString", &mx::ShaderRef::hasNodeString) .def("getNodeString", &mx::ShaderRef::getNodeString) From daf01e296f7591217c2555548ddde70d25fc969b Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 20 Jun 2018 11:55:26 -0700 Subject: [PATCH 19/27] Update addChildOfCategory for root-level node elements in v1.36 --- source/MaterialXCore/Element.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index a6db9b9dfb..c33a710046 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -277,7 +277,7 @@ ElementPtr Element::addChildOfCategory(const string& category, } // Check for a node within a graph. - if (!child && getCategory() == NodeGraph::CATEGORY) + if (!child && isA()) { child = createElement(getSelf(), childName); child->setCategory(category); From 85144bac229cc758b84397e1be4a809eb28a88c0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Thu, 12 Jul 2018 15:27:40 -0700 Subject: [PATCH 20/27] Update example documents for v1.36 --- documents/Examples/BxDF/Disney_BRDF_2012.mtlx | 7 +- documents/Examples/BxDF/Disney_BSDF_2015.mtlx | 7 +- documents/Examples/BxDF/alSurface.mtlx | 236 +++++++++--------- documents/Examples/CustomNode.mtlx | 6 +- documents/Examples/GeomInfos.mtlx | 14 +- documents/Examples/Looks.mtlx | 26 +- ...MaterialGraphs.mtlx => MaterialBasic.mtlx} | 21 +- documents/Examples/MultiOutput.mtlx | 6 +- documents/Examples/NodeGraphs.mtlx | 198 +++++++-------- documents/Examples/PaintMaterials.mtlx | 8 +- documents/Examples/PostShaderComposite.mtlx | 81 ++++-- documents/Examples/PreShaderComposite.mtlx | 141 ++++++----- documents/Examples/SimpleSrf.mtlx | 4 +- documents/Examples/SubGraphs.mtlx | 16 +- python/MaterialXTest/main.py | 2 +- source/MaterialXTest/File.cpp | 2 +- source/MaterialXTest/XmlIo.cpp | 2 +- 17 files changed, 396 insertions(+), 381 deletions(-) rename documents/Examples/{MaterialGraphs.mtlx => MaterialBasic.mtlx} (54%) diff --git a/documents/Examples/BxDF/Disney_BRDF_2012.mtlx b/documents/Examples/BxDF/Disney_BRDF_2012.mtlx index 41c6f99288..b39e7502b0 100644 --- a/documents/Examples/BxDF/Disney_BRDF_2012.mtlx +++ b/documents/Examples/BxDF/Disney_BRDF_2012.mtlx @@ -1,6 +1,6 @@ - - + + @@ -13,5 +13,6 @@ - + diff --git a/documents/Examples/BxDF/Disney_BSDF_2015.mtlx b/documents/Examples/BxDF/Disney_BSDF_2015.mtlx index a9d39d09c4..75cf776424 100644 --- a/documents/Examples/BxDF/Disney_BSDF_2015.mtlx +++ b/documents/Examples/BxDF/Disney_BSDF_2015.mtlx @@ -1,6 +1,6 @@ - - + + @@ -17,7 +17,8 @@ - + diff --git a/documents/Examples/BxDF/alSurface.mtlx b/documents/Examples/BxDF/alSurface.mtlx index d308e16efd..fde41a5951 100644 --- a/documents/Examples/BxDF/alSurface.mtlx +++ b/documents/Examples/BxDF/alSurface.mtlx @@ -1,120 +1,122 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/documents/Examples/CustomNode.mtlx b/documents/Examples/CustomNode.mtlx index 2ccdf336b8..7f6eafa1f5 100644 --- a/documents/Examples/CustomNode.mtlx +++ b/documents/Examples/CustomNode.mtlx @@ -1,9 +1,9 @@ - + - + @@ -11,7 +11,7 @@ - + diff --git a/documents/Examples/GeomInfos.mtlx b/documents/Examples/GeomInfos.mtlx index 2c8656492c..8574b7f1c1 100644 --- a/documents/Examples/GeomInfos.mtlx +++ b/documents/Examples/GeomInfos.mtlx @@ -1,14 +1,8 @@ - - - - - - - - - - + + + + diff --git a/documents/Examples/Looks.mtlx b/documents/Examples/Looks.mtlx index 3a4d8c57ce..5affdf13d0 100644 --- a/documents/Examples/Looks.mtlx +++ b/documents/Examples/Looks.mtlx @@ -1,5 +1,5 @@ - + @@ -30,20 +30,12 @@ - - - - - - - - - - - - + + + + - + @@ -62,14 +54,14 @@ - + - + - + diff --git a/documents/Examples/MaterialGraphs.mtlx b/documents/Examples/MaterialBasic.mtlx similarity index 54% rename from documents/Examples/MaterialGraphs.mtlx rename to documents/Examples/MaterialBasic.mtlx index 79773f050f..ffc4db383f 100644 --- a/documents/Examples/MaterialGraphs.mtlx +++ b/documents/Examples/MaterialBasic.mtlx @@ -1,42 +1,35 @@ - - + - + - + - - + + - + - - - - - + - diff --git a/documents/Examples/MultiOutput.mtlx b/documents/Examples/MultiOutput.mtlx index acacdd5a71..1dcf256686 100644 --- a/documents/Examples/MultiOutput.mtlx +++ b/documents/Examples/MultiOutput.mtlx @@ -1,14 +1,14 @@ - + - + - + diff --git a/documents/Examples/NodeGraphs.mtlx b/documents/Examples/NodeGraphs.mtlx index 0c972af31c..7248ea0b5c 100644 --- a/documents/Examples/NodeGraphs.mtlx +++ b/documents/Examples/NodeGraphs.mtlx @@ -1,109 +1,99 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/Examples/PaintMaterials.mtlx b/documents/Examples/PaintMaterials.mtlx index 30f92a007b..7578a20d18 100644 --- a/documents/Examples/PaintMaterials.mtlx +++ b/documents/Examples/PaintMaterials.mtlx @@ -1,5 +1,5 @@ - + @@ -10,16 +10,14 @@ - - + - - + diff --git a/documents/Examples/PostShaderComposite.mtlx b/documents/Examples/PostShaderComposite.mtlx index adb98d62a0..1166ba6b61 100644 --- a/documents/Examples/PostShaderComposite.mtlx +++ b/documents/Examples/PostShaderComposite.mtlx @@ -1,33 +1,54 @@ - - + + - - - - - - - - - + + + + + + + + - - + + + - + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + @@ -37,15 +58,21 @@ + + + + + - - - - - - - + + + + + + + + diff --git a/documents/Examples/PreShaderComposite.mtlx b/documents/Examples/PreShaderComposite.mtlx index ae0ac2be91..8b6bb9764e 100644 --- a/documents/Examples/PreShaderComposite.mtlx +++ b/documents/Examples/PreShaderComposite.mtlx @@ -1,7 +1,38 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12,18 +43,7 @@ - - - - - - - - - - - - + @@ -34,80 +54,77 @@ - - - + + + + + + + + + + + - + + + + - + - - + + - - + + - - - + + - - + + - - - + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - + + + + + diff --git a/documents/Examples/SimpleSrf.mtlx b/documents/Examples/SimpleSrf.mtlx index e3bb336c35..3c8fab8b48 100644 --- a/documents/Examples/SimpleSrf.mtlx +++ b/documents/Examples/SimpleSrf.mtlx @@ -1,6 +1,6 @@ - - + + diff --git a/documents/Examples/SubGraphs.mtlx b/documents/Examples/SubGraphs.mtlx index 4d96ad4c9e..00ea9f586f 100644 --- a/documents/Examples/SubGraphs.mtlx +++ b/documents/Examples/SubGraphs.mtlx @@ -1,13 +1,13 @@ - + - + - + @@ -61,12 +61,12 @@ - + - + @@ -82,13 +82,13 @@ - + - + - + diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index ab56f45b96..1a10f1b272 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -32,7 +32,7 @@ 'mx_stdlib_impl_osl.mtlx') _exampleFilenames = ('CustomNode.mtlx', 'Looks.mtlx', - 'MaterialGraphs.mtlx', + 'MaterialBasic.mtlx', 'MultiOutput.mtlx', 'PaintMaterials.mtlx', 'PreShaderComposite.mtlx', diff --git a/source/MaterialXTest/File.cpp b/source/MaterialXTest/File.cpp index 8e681a7f1d..9fcee5a2bd 100644 --- a/source/MaterialXTest/File.cpp +++ b/source/MaterialXTest/File.cpp @@ -35,7 +35,7 @@ TEST_CASE("File system operations", "[file]") std::vector filenames = { "documents/Libraries/mx_stdlib_defs.mtlx", - "documents/Examples/MaterialGraphs.mtlx", + "documents/Examples/MaterialBasic.mtlx", "documents/Examples/PaintMaterials.mtlx", }; diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index ed79b6aac9..fb4bd5e155 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -20,7 +20,7 @@ TEST_CASE("Load content", "[xmlio]") { "CustomNode.mtlx", "Looks.mtlx", - "MaterialGraphs.mtlx", + "MaterialBasic.mtlx", "MultiOutput.mtlx", "PaintMaterials.mtlx", "PreShaderComposite.mtlx", From 3fe05c0df4b155d7f8a4dd0454917a0679d862f9 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 13 Jul 2018 16:01:30 -0700 Subject: [PATCH 21/27] Update forward declarations for v1.36 --- source/MaterialXCore/Element.h | 5 +++-- source/MaterialXCore/Node.h | 5 +++-- source/MaterialXCore/Variant.h | 16 ++++++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index 1312fca46b..f29cb077ce 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -21,6 +21,7 @@ namespace MaterialX class Element; class TypedElement; class ValueElement; +class Token; class StringResolver; class Document; class Material; @@ -41,9 +42,9 @@ using ValueElementPtr = shared_ptr; using ConstValueElementPtr = shared_ptr; /// A shared pointer to a Token -using TokenPtr = shared_ptr; +using TokenPtr = shared_ptr; /// A shared pointer to a const Token -using ConstTokenPtr = shared_ptr; +using ConstTokenPtr = shared_ptr; /// A shared pointer to a StringResolver using StringResolverPtr = shared_ptr; diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index d53f7f9bf1..643e28ffb0 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -17,6 +17,7 @@ namespace MaterialX { class Node; +class GraphElement; class NodeGraph; /// A shared pointer to a Node @@ -25,9 +26,9 @@ using NodePtr = shared_ptr; using ConstNodePtr = shared_ptr; /// A shared pointer to a GraphElement -using GraphElementPtr = shared_ptr; +using GraphElementPtr = shared_ptr; /// A shared pointer to a const GraphElement -using ConstGraphElementPtr = shared_ptr; +using ConstGraphElementPtr = shared_ptr; /// A shared pointer to a NodeGraph using NodeGraphPtr = shared_ptr; diff --git a/source/MaterialXCore/Variant.h b/source/MaterialXCore/Variant.h index 307548595c..8849531f48 100644 --- a/source/MaterialXCore/Variant.h +++ b/source/MaterialXCore/Variant.h @@ -16,20 +16,24 @@ namespace MaterialX { +class Variant; +class VariantSet; +class VariantAssign; + /// A shared pointer to a Variant -using VariantPtr = shared_ptr; +using VariantPtr = shared_ptr; /// A shared pointer to a const Variant -using ConstVariantPtr = shared_ptr; +using ConstVariantPtr = shared_ptr; /// A shared pointer to a VariantSet -using VariantSetPtr = shared_ptr; +using VariantSetPtr = shared_ptr; /// A shared pointer to a const VariantSet -using ConstVariantSetPtr = shared_ptr; +using ConstVariantSetPtr = shared_ptr; /// A shared pointer to a VariantAssign -using VariantAssignPtr = shared_ptr; +using VariantAssignPtr = shared_ptr; /// A shared pointer to a const VariantAssign -using ConstVariantAssignPtr = shared_ptr; +using ConstVariantAssignPtr = shared_ptr; /// @class Variant /// A variant element within a VariantSet From 1202f8bbf564c092648e582258b25152f8e4c91a Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 18 Jul 2018 10:54:10 -0700 Subject: [PATCH 22/27] Additional updates for v1.36 - Rename 'nodecategory' to 'nodegroup'. - Add helper method Element::getActiveSourceUri. - Fix a null check in GraphElement::flattenSubgraphs. - Remove unneeded flag CopyOptions.copySourceUris. --- source/MaterialXCore/Definition.cpp | 12 +++++------ source/MaterialXCore/Definition.h | 32 ++++++++++++++--------------- source/MaterialXCore/Document.cpp | 3 +-- source/MaterialXCore/Document.h | 4 +--- source/MaterialXCore/Element.cpp | 5 +---- source/MaterialXCore/Element.h | 21 +++++++++++++------ source/MaterialXCore/Node.cpp | 6 +++--- source/MaterialXFormat/XmlIo.cpp | 9 ++++---- source/MaterialXTest/Node.cpp | 4 ++-- source/PyMaterialX/PyDefinition.cpp | 6 +++--- source/PyMaterialX/PyElement.cpp | 4 ++-- 11 files changed, 55 insertions(+), 51 deletions(-) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 95af518ef4..022d00b8b3 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -13,14 +13,14 @@ namespace MaterialX const string COLOR_SEMANTIC = "color"; const string SHADER_SEMANTIC = "shader"; -const string TEXTURE_NODE_CATEGORY = "texture"; -const string PROCEDURAL_NODE_CATEGORY = "procedural"; -const string GEOMETRIC_NODE_CATEGORY = "geometric"; -const string ADJUSTMENT_NODE_CATEGORY = "adjustment"; -const string CONDITIONAL_NODE_CATEGORY = "conditional"; +const string TEXTURE_NODE_GROUP = "texture"; +const string PROCEDURAL_NODE_GROUP = "procedural"; +const string GEOMETRIC_NODE_GROUP = "geometric"; +const string ADJUSTMENT_NODE_GROUP = "adjustment"; +const string CONDITIONAL_NODE_GROUP = "conditional"; const string NodeDef::NODE_ATTRIBUTE = "node"; -const string NodeDef::NODE_CATEGORY_ATTRIBUTE = "nodecategory"; +const string NodeDef::NODE_GROUP_ATTRIBUTE = "nodegroup"; const string TypeDef::SEMANTIC_ATTRIBUTE = "semantic"; const string TypeDef::CONTEXT_ATTRIBUTE = "context"; const string Implementation::NODE_DEF_ATTRIBUTE = "nodedef"; diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index f5c730eb82..2f92762f57 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -19,11 +19,11 @@ namespace MaterialX extern const string COLOR_SEMANTIC; extern const string SHADER_SEMANTIC; -extern const string TEXTURE_NODE_CATEGORY; -extern const string PROCEDURAL_NODE_CATEGORY; -extern const string GEOMETRIC_NODE_CATEGORY; -extern const string ADJUSTMENT_NODE_CATEGORY; -extern const string CONDITIONAL_NODE_CATEGORY; +extern const string TEXTURE_NODE_GROUP; +extern const string PROCEDURAL_NODE_GROUP; +extern const string GEOMETRIC_NODE_GROUP; +extern const string ADJUSTMENT_NODE_GROUP; +extern const string CONDITIONAL_NODE_GROUP; class NodeDef; class Implementation; @@ -89,25 +89,25 @@ class NodeDef : public InterfaceElement } /// @} - /// @name Node Category + /// @name Node Group /// @{ - /// Set the node category of the NodeDef. - void setNodeCategory(const string& category) + /// Set the node group of the NodeDef. + void setNodeGroup(const string& category) { - setAttribute(NODE_CATEGORY_ATTRIBUTE, category); + setAttribute(NODE_GROUP_ATTRIBUTE, category); } - /// Return true if the given NodeDef has a node category. - bool hasNodeCategory() const + /// Return true if the given NodeDef has a node group. + bool hasNodeGroup() const { - return hasAttribute(NODE_CATEGORY_ATTRIBUTE); + return hasAttribute(NODE_GROUP_ATTRIBUTE); } - /// Return the node category of the NodeDef. - const string& getNodeCategory() const + /// Return the node group of the NodeDef. + const string& getNodeGroup() const { - return getAttribute(NODE_CATEGORY_ATTRIBUTE); + return getAttribute(NODE_GROUP_ATTRIBUTE); } /// @} @@ -155,7 +155,7 @@ class NodeDef : public InterfaceElement public: static const string CATEGORY; static const string NODE_ATTRIBUTE; - static const string NODE_CATEGORY_ATTRIBUTE; + static const string NODE_GROUP_ATTRIBUTE; }; /// @class Implementation diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index bbdbeface5..68ead107a1 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -146,7 +146,6 @@ void Document::initialize() void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOptions) { bool skipDuplicateElements = copyOptions && copyOptions->skipDuplicateElements; - bool copySourceUris = copyOptions && copyOptions->copySourceUris; for (ElementPtr child : library->getChildren()) { string childName = child->getQualifiedName(child->getName()); @@ -173,7 +172,7 @@ void Document::importLibrary(ConstDocumentPtr library, const CopyOptions* copyOp { childCopy->setNamespace(library->getNamespace()); } - if (copySourceUris && !childCopy->hasSourceUri()) + if (!childCopy->hasSourceUri() && library->hasSourceUri()) { childCopy->setSourceUri(library->getSourceUri()); } diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 0977963d65..3b62ce2242 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -52,9 +52,7 @@ class Document : public GraphElement virtual DocumentPtr copy() { DocumentPtr doc = createDocument(); - CopyOptions copyOptions; - copyOptions.copySourceUris = true; - doc->copyContentFrom(getSelf(), ©Options); + doc->copyContentFrom(getSelf()); return doc; } diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index c33a710046..b1bbb2962d 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -373,10 +373,7 @@ AncestorIterator Element::traverseAncestors() const void Element::copyContentFrom(ConstElementPtr source, const CopyOptions* copyOptions) { - if (copyOptions && copyOptions->copySourceUris) - { - _sourceUri = source->_sourceUri; - } + _sourceUri = source->_sourceUri; for (const string& attr : source->getAttributeNames()) { setAttribute(attr, source->getAttribute(attr)); diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index f29cb077ce..ad6ba903db 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -738,6 +738,20 @@ class Element : public std::enable_shared_from_this return _sourceUri; } + /// Return the source URI that is active at the scope of this + /// element, taking all ancestor elements into account. + const string& getActiveSourceUri() const + { + for (ConstElementPtr elem : traverseAncestors()) + { + if (elem->hasSourceUri()) + { + return elem->getSourceUri(); + } + } + return EMPTY_STRING; + } + /// @} /// @name Validation /// @{ @@ -1219,8 +1233,7 @@ class CopyOptions { public: CopyOptions() : - skipDuplicateElements(false), - copySourceUris(false) + skipDuplicateElements(false) { } ~CopyOptions() { } @@ -1228,10 +1241,6 @@ class CopyOptions /// If true, elements at the same scope with duplicate names will be skipped; /// otherwise, they will trigger an exception. Defaults to false. bool skipDuplicateElements; - - /// If true, then source URIs from the given element - /// and its descendants are also copied. Defaults to false. - bool copySourceUris; }; /// @class ExceptionOrphanedElement diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 36fd1615a8..374fb92fc8 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -160,7 +160,7 @@ void GraphElement::flattenSubgraphs(const string& target) } ValueElementPtr refValue = refNode->getChildOfType(newValue->getInterfaceName()); - if (refNode) + if (refValue) { if (refValue->hasValueString()) { @@ -304,8 +304,8 @@ string GraphElement::asStringDot() const { dot += " \"" + node->getName() + "\" "; NodeDefPtr nodeDef = node->getNodeDef(); - const string& nodeCategory = nodeDef ? nodeDef->getNodeCategory() : EMPTY_STRING; - if (nodeCategory == CONDITIONAL_NODE_CATEGORY) + const string& nodeGroup = nodeDef ? nodeDef->getNodeGroup() : EMPTY_STRING; + if (nodeGroup == CONDITIONAL_NODE_GROUP) { dot += "[shape=diamond];\n"; } diff --git a/source/MaterialXFormat/XmlIo.cpp b/source/MaterialXFormat/XmlIo.cpp index 89ba69b466..12c3b111ea 100644 --- a/source/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXFormat/XmlIo.cpp @@ -125,7 +125,10 @@ void xmlDocumentFromFile(xml_document& xmlDoc, string filename, const string& se } else { - throw ExceptionParseError("XML parse error in file: " + filename + " (" + result.description() + ")"); + string desc = result.description(); + string offset = std::to_string(result.offset); + throw ExceptionParseError("XML parse error in file: " + filename + + " (" + desc + " at character " + offset + ")"); } } } @@ -145,9 +148,7 @@ void processXIncludes(DocumentPtr doc, xml_node& xmlNode, const string& searchPa readFromXmlFile(library, fileAttr.value(), searchPath, readOptions); // Import the library. - CopyOptions copyOptions = readOptions ? (CopyOptions) *readOptions : CopyOptions(); - copyOptions.copySourceUris = true; - doc->importLibrary(library, ©Options); + doc->importLibrary(library, readOptions); } // Remove include directive. diff --git a/source/MaterialXTest/Node.cpp b/source/MaterialXTest/Node.cpp index 6df9c14b9c..a90d940287 100644 --- a/source/MaterialXTest/Node.cpp +++ b/source/MaterialXTest/Node.cpp @@ -66,14 +66,14 @@ TEST_CASE("Node", "[node]") // Create a custom nodedef. mx::NodeDefPtr customNodeDef = doc->addNodeDef("ND_turbulence3d", "float", "turbulence3d"); - customNodeDef->setNodeCategory(mx::PROCEDURAL_NODE_CATEGORY); + customNodeDef->setNodeGroup(mx::PROCEDURAL_NODE_GROUP); customNodeDef->setParameterValue("octaves", 3); customNodeDef->setParameterValue("lacunarity", 2.0f); customNodeDef->setParameterValue("gain", 0.5f); // Reference the custom nodedef. mx::NodePtr custom = doc->addNodeInstance(customNodeDef); - REQUIRE(custom->getNodeDef()->getNodeCategory() == mx::PROCEDURAL_NODE_CATEGORY); + REQUIRE(custom->getNodeDef()->getNodeGroup() == mx::PROCEDURAL_NODE_GROUP); REQUIRE(custom->getParameterValue("octaves")->isA()); REQUIRE(custom->getParameterValue("octaves")->asA() == 3); custom->setParameterValue("octaves", 5); diff --git a/source/PyMaterialX/PyDefinition.cpp b/source/PyMaterialX/PyDefinition.cpp index dd836711f7..312b475741 100644 --- a/source/PyMaterialX/PyDefinition.cpp +++ b/source/PyMaterialX/PyDefinition.cpp @@ -18,9 +18,9 @@ void bindPyDefinition(py::module& mod) .def("setNodeString", &mx::NodeDef::setNodeString) .def("hasNodeString", &mx::NodeDef::hasNodeString) .def("getNodeString", &mx::NodeDef::getNodeString) - .def("setNodeCategory", &mx::NodeDef::setNodeCategory) - .def("hasNodeCategory", &mx::NodeDef::hasNodeCategory) - .def("getNodeCategory", &mx::NodeDef::getNodeCategory) + .def("setNodeGroup", &mx::NodeDef::setNodeGroup) + .def("hasNodeGroup", &mx::NodeDef::hasNodeGroup) + .def("getNodeGroup", &mx::NodeDef::getNodeGroup) .def("getImplementation", &mx::NodeDef::getImplementation) .def("getImplementation", &mx::NodeDef::getImplementation, py::arg("target") = mx::EMPTY_STRING, diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index b8d4f91488..fcc8021bec 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -28,8 +28,7 @@ void bindPyElement(py::module& mod) { py::class_(mod, "CopyOptions") .def(py::init()) - .def_readwrite("skipDuplicateElements", &mx::CopyOptions::skipDuplicateElements) - .def_readwrite("copySourceUris", &mx::CopyOptions::copySourceUris); + .def_readwrite("skipDuplicateElements", &mx::CopyOptions::skipDuplicateElements); py::class_(mod, "Element") .def(py::self == py::self) @@ -100,6 +99,7 @@ void bindPyElement(py::module& mod) .def("setSourceUri", &mx::Element::setSourceUri) .def("hasSourceUri", &mx::Element::hasSourceUri) .def("getSourceUri", &mx::Element::getSourceUri) + .def("getActiveSourceUri", &mx::Element::getActiveSourceUri) .def("validate", [](mx::Element& elem) { std::string message; From 5993b1de9ca402d833e3f79807b7b8880f9422c6 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 18 Jul 2018 21:51:48 -0700 Subject: [PATCH 23/27] Improvements to GraphElement::flattenSubgraphs - Add support for references to multi-output nodes. - Precompute downstream ports for efficiency. --- source/MaterialXCore/Node.cpp | 62 ++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 374fb92fc8..8d0e12141d 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -140,77 +140,85 @@ void GraphElement::flattenSubgraphs(const string& target) continue; } - GraphElementPtr origSubGraph = implement->asA(); + NodeGraphPtr sourceSubGraph = implement->asA(); std::unordered_map subNodeMap; + // Precompute downstream ports for efficiency. + using PortElementVec = vector; + PortElementVec outerPorts = refNode->getDownstreamPorts(); + std::unordered_map sourcePortsMap; + for (NodePtr sourceSubNode : sourceSubGraph->getNodes()) + { + sourcePortsMap[sourceSubNode] = sourceSubNode->getDownstreamPorts(); + } + // Create a new instance of each original subnode. - for (NodePtr origSubNode : origSubGraph->getNodes()) + for (NodePtr sourceSubNode : sourceSubGraph->getNodes()) { - string newName = createValidChildName(implement->getName() + "_" + origSubNode->getName()); - NodePtr newSubNode = addNode(origSubNode->getCategory(), newName); - newSubNode->copyContentFrom(origSubNode); - setChildIndex(newSubNode->getName(), getChildIndex(refNode->getName())); + string destName = createValidChildName(implement->getName() + "_" + sourceSubNode->getName()); + NodePtr destSubNode = addNode(sourceSubNode->getCategory(), destName); + destSubNode->copyContentFrom(sourceSubNode); + setChildIndex(destSubNode->getName(), getChildIndex(refNode->getName())); // Transfer interface properties from the reference node to the new subnode. - for (ValueElementPtr newValue : newSubNode->getChildrenOfType()) + for (ValueElementPtr destValue : destSubNode->getChildrenOfType()) { - if (!newValue->hasInterfaceName()) + if (!destValue->hasInterfaceName()) { continue; } - ValueElementPtr refValue = refNode->getChildOfType(newValue->getInterfaceName()); + ValueElementPtr refValue = refNode->getChildOfType(destValue->getInterfaceName()); if (refValue) { if (refValue->hasValueString()) { - newValue->setValueString(refValue->getValueString()); + destValue->setValueString(refValue->getValueString()); } - if (newValue->isA() && refValue->isA()) + if (destValue->isA() && refValue->isA()) { InputPtr refInput = refValue->asA(); - InputPtr newInput = newValue->asA(); + InputPtr newInput = destValue->asA(); if (refInput->hasNodeName()) { newInput->setNodeName(refInput->getNodeName()); } + if (refInput->hasOutputString()) + { + newInput->setOutputString(refInput->getOutputString()); + } } } - newValue->removeAttribute(ValueElement::INTERFACE_NAME_ATTRIBUTE); + destValue->removeAttribute(ValueElement::INTERFACE_NAME_ATTRIBUTE); } // Store the mapping between subgraphs. - subNodeMap[origSubNode] = newSubNode; + subNodeMap[sourceSubNode] = destSubNode; - // Check if the new subnode has a graph implementation. - // If so this subgraph will need to be flattened as well. - InterfaceElementPtr subNodeImplement = newSubNode->getImplementation(target); - if (subNodeImplement && subNodeImplement->isA()) - { - nodeQueue.push_back(newSubNode); - } + // Add the subnode to the queue, allowing processing of nested subgraphs. + nodeQueue.push_back(destSubNode); } // Transfer internal connections between subgraphs. for (auto subNodePair : subNodeMap) { - NodePtr origSubNode = subNodePair.first; - NodePtr newSubNode = subNodePair.second; - for (PortElementPtr origPort : origSubNode->getDownstreamPorts()) + NodePtr sourceSubNode = subNodePair.first; + NodePtr destSubNode = subNodePair.second; + for (PortElementPtr origPort : sourcePortsMap[sourceSubNode]) { if (origPort->isA()) { auto it = subNodeMap.find(origPort->getParent()->asA()); if (it != subNodeMap.end()) { - it->second->setConnectedNode(origPort->getName(), newSubNode); + it->second->setConnectedNode(origPort->getName(), destSubNode); } } else if (origPort->isA()) { - for (PortElementPtr outerPort : refNode->getDownstreamPorts()) + for (PortElementPtr outerPort : outerPorts) { - outerPort->setConnectedNode(newSubNode); + outerPort->setConnectedNode(destSubNode); } } } From f095bc6e3c25bfea44fea8d1f3e224b4d5f0a3f0 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Fri, 20 Jul 2018 17:36:29 -0700 Subject: [PATCH 24/27] Additional optimizations for v1.36 - Merge NodeDef methods from Implementation and NodeGraph to their InterfaceElement super class. - Replace Element::traverseAncestors with explicit loops. - Combine precomputations in NodeGraph::flattenSubgraphs. --- source/MaterialXCore/Definition.cpp | 10 -- source/MaterialXCore/Definition.h | 38 ------- source/MaterialXCore/Document.cpp | 49 +++++---- source/MaterialXCore/Element.cpp | 7 +- source/MaterialXCore/Element.h | 24 +---- source/MaterialXCore/Interface.cpp | 28 +++-- source/MaterialXCore/Interface.h | 31 +++++- source/MaterialXCore/Node.cpp | 158 +++++++++++++--------------- source/MaterialXCore/Node.h | 40 ------- source/MaterialXCore/Traversal.cpp | 25 ----- source/MaterialXCore/Traversal.h | 50 --------- source/MaterialXTest/Traversal.cpp | 4 - source/PyMaterialX/PyDefinition.cpp | 6 -- source/PyMaterialX/PyElement.cpp | 1 - source/PyMaterialX/PyInterface.cpp | 8 +- source/PyMaterialX/PyNode.cpp | 5 - source/PyMaterialX/PyTraversal.cpp | 12 --- 17 files changed, 167 insertions(+), 329 deletions(-) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 022d00b8b3..5e96d02103 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -23,7 +23,6 @@ const string NodeDef::NODE_ATTRIBUTE = "node"; const string NodeDef::NODE_GROUP_ATTRIBUTE = "nodegroup"; const string TypeDef::SEMANTIC_ATTRIBUTE = "semantic"; const string TypeDef::CONTEXT_ATTRIBUTE = "context"; -const string Implementation::NODE_DEF_ATTRIBUTE = "nodedef"; const string Implementation::FILE_ATTRIBUTE = "file"; const string Implementation::FUNCTION_ATTRIBUTE = "function"; const string Implementation::LANGUAGE_ATTRIBUTE = "language"; @@ -104,13 +103,4 @@ bool NodeDef::isVersionCompatible(ConstElementPtr elem) const return false; } -// -// Implementation methods -// - -NodeDefPtr Implementation::getNodeDef() const -{ - return resolveRootNameReference(getNodeDefString()); -} - } // namespace MaterialX diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 2f92762f57..6523900455 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -173,44 +173,6 @@ class Implementation : public InterfaceElement } virtual ~Implementation() { } - /// @name NodeDef - /// @{ - - /// Set the NodeDef string for the Implementation. - void setNodeDefString(const string& nodeDef) - { - setAttribute(NODE_DEF_ATTRIBUTE, nodeDef); - } - - /// Return true if the given Implementation has a NodeDef string. - bool hasNodeDefString() const - { - return hasAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Return the NodeDef string for the Implementation. - const string& getNodeDefString() const - { - return getAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Set the NodeDef element for the Implementation. - void setNodeDef(ConstNodeDefPtr nodeDef) - { - if (nodeDef) - { - setNodeDefString(nodeDef->getName()); - } - else - { - removeAttribute(NODE_DEF_ATTRIBUTE); - } - } - - /// Return the NodeDef element for the Implementation. - NodeDefPtr getNodeDef() const; - - /// @} /// @name File String /// @{ diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index 68ead107a1..8cbeb307a0 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -70,34 +70,39 @@ class Document::Cache // Traverse the document to build a new cache. for (ElementPtr elem : doc.lock()->traverseTree()) { - PortElementPtr portElem = elem->asA(); - NodeDefPtr nodeDef = elem->asA(); - NodeGraphPtr nodeGraph = elem->asA(); - ImplementationPtr implementation = elem->asA(); + string nodeName = elem->getAttribute(PortElement::NODE_NAME_ATTRIBUTE); + string nodeString = elem->getAttribute(NodeDef::NODE_ATTRIBUTE); + string nodeDefString = elem->getAttribute(InterfaceElement::NODE_DEF_ATTRIBUTE); - if (portElem && portElem->hasNodeName()) + if (!nodeName.empty()) { - portElementMap.insert(std::pair( - portElem->getQualifiedName(portElem->getNodeName()), - portElem)); - } - if (nodeDef && nodeDef->hasNodeString()) - { - nodeDefMap.insert(std::pair( - nodeDef->getQualifiedName(nodeDef->getNodeString()), - nodeDef)); + PortElementPtr portElem = elem->asA(); + if (portElem) + { + portElementMap.insert(std::pair( + portElem->getQualifiedName(nodeName), + portElem)); + } } - if (nodeGraph && nodeGraph->hasNodeDefString()) + if (!nodeString.empty()) { - implementationMap.insert(std::pair( - nodeGraph->getQualifiedName(nodeGraph->getNodeDefString()), - nodeGraph)); + NodeDefPtr nodeDef = elem->asA(); + if (nodeDef) + { + nodeDefMap.insert(std::pair( + nodeDef->getQualifiedName(nodeString), + nodeDef)); + } } - if (implementation && implementation->hasNodeDefString()) + if (!nodeDefString.empty()) { - implementationMap.insert(std::pair( - implementation->getQualifiedName(implementation->getNodeDefString()), - implementation)); + InterfaceElementPtr interface = elem->asA(); + if (interface) + { + implementationMap.insert(std::pair( + interface->getQualifiedName(nodeDefString), + interface)); + } } } diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index b1bbb2962d..d0f39a0579 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -96,7 +96,7 @@ string Element::getNamePath(ConstElementPtr relativeTo) const } string res; - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem == relativeTo) { @@ -366,11 +366,6 @@ InheritanceIterator Element::traverseInheritance() const return InheritanceIterator(getSelf()); } -AncestorIterator Element::traverseAncestors() const -{ - return AncestorIterator(getSelf()); -} - void Element::copyContentFrom(ConstElementPtr source, const CopyOptions* copyOptions) { _sourceUri = source->_sourceUri; diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index ad6ba903db..64f025a122 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -162,7 +162,7 @@ class Element : public std::enable_shared_from_this /// element, taking all ancestor elements into account. const string& getActiveFilePrefix() const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem->hasFilePrefix()) { @@ -198,7 +198,7 @@ class Element : public std::enable_shared_from_this /// element, taking all ancestor elements into account. const string& getActiveGeomPrefix() const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem->hasGeomPrefix()) { @@ -234,7 +234,7 @@ class Element : public std::enable_shared_from_this /// element, taking all ancestor elements into account. const string& getActiveColorSpace() const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem->hasColorSpace()) { @@ -340,7 +340,7 @@ class Element : public std::enable_shared_from_this /// scope of this element into account. string getQualifiedName(const string& name) const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem->hasNamespace()) { @@ -698,20 +698,6 @@ class Element : public std::enable_shared_from_this /// @endcode InheritanceIterator traverseInheritance() const; - /// Traverse the tree from the given element to each of its ancestors. - /// @return An AncestorIterator object. - /// @details Example usage: - /// @code - /// ConstElementPtr childElem; - /// for (ConstElementPtr elem : inputElem->traverseAncestors()) - /// { - /// if (childElem) - /// cout << childElem->asString() << " is a child of " << elem->asString() << endl; - /// childElem = elem; - /// } - /// @endcode - AncestorIterator traverseAncestors() const; - /// @} /// @name Source URI /// @{ @@ -742,7 +728,7 @@ class Element : public std::enable_shared_from_this /// element, taking all ancestor elements into account. const string& getActiveSourceUri() const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { if (elem->hasSourceUri()) { diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 004f017d57..5568044724 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -14,6 +14,7 @@ namespace MaterialX const string PortElement::NODE_NAME_ATTRIBUTE = "nodename"; const string PortElement::OUTPUT_ATTRIBUTE = "output"; +const string InterfaceElement::NODE_DEF_ATTRIBUTE = "nodedef"; // // PortElement methods @@ -33,7 +34,7 @@ void PortElement::setConnectedNode(NodePtr node) NodePtr PortElement::getConnectedNode() const { - for (ConstElementPtr elem : traverseAncestors()) + for (ConstElementPtr elem = getSelf(); elem; elem = elem->getParent()) { ConstGraphElementPtr graph = elem->asA(); if (graph) @@ -191,6 +192,23 @@ bool Output::validate(string* message) const // InterfaceElement methods // +void InterfaceElement::setNodeDef(ConstNodeDefPtr nodeDef) +{ + if (nodeDef) + { + setNodeDefString(nodeDef->getName()); + } + else + { + removeAttribute(NODE_DEF_ATTRIBUTE); + } +} + +NodeDefPtr InterfaceElement::getNodeDef() const +{ + return resolveRootNameReference(getNodeDefString()); +} + ParameterPtr InterfaceElement::getActiveParameter(const string& name) const { for (ConstElementPtr elem : traverseInheritance()) @@ -395,13 +413,9 @@ NodeDefPtr InterfaceElement::getDeclaration(const string& target) const { return asA()->getNodeDef(target); } - else if (isA()) - { - return asA()->getNodeDef(); - } - else if (isA()) + else if (isA()) { - return asA()->getNodeDef(); + return asA()->getNodeDef(); } return NodeDefPtr(); diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index 0068426824..3f8330c6dd 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -272,7 +272,33 @@ class InterfaceElement : public TypedElement using ConstNodeDefPtr = shared_ptr; public: - /// @} + /// @name NodeDef String + /// @{ + + /// Set the NodeDef string for the interface. + void setNodeDefString(const string& nodeDef) + { + setAttribute(NODE_DEF_ATTRIBUTE, nodeDef); + } + + /// Return true if the given interface has a NodeDef string. + bool hasNodeDefString() const + { + return hasAttribute(NODE_DEF_ATTRIBUTE); + } + + /// Return the NodeDef string for the interface. + const string& getNodeDefString() const + { + return getAttribute(NODE_DEF_ATTRIBUTE); + } + + /// Set the NodeDef element for the interface. + void setNodeDef(ConstNodeDefPtr nodeDef); + + /// Return the NodeDef element for the interface. + NodeDefPtr getNodeDef() const; + /// @name Parameters /// @{ @@ -558,6 +584,9 @@ class InterfaceElement : public TypedElement /// @} + public: + static const string NODE_DEF_ATTRIBUTE; + protected: void registerChildElement(ElementPtr child) override; void unregisterChildElement(ElementPtr child) override; diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 8d0e12141d..6ff5291537 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -13,8 +13,6 @@ namespace MaterialX { -const string NodeGraph::NODE_DEF_ATTRIBUTE = "nodedef"; - // // Node methods // @@ -126,107 +124,112 @@ bool Node::validate(string* message) const void GraphElement::flattenSubgraphs(const string& target) { - vector initialNodes = getNodes(); - std::deque nodeQueue(initialNodes.begin(), initialNodes.end()); - - while (!nodeQueue.empty()) + vector processNodeVec = getNodes(); + while (!processNodeVec.empty()) { - NodePtr refNode = nodeQueue.front(); - nodeQueue.pop_front(); - - InterfaceElementPtr implement = refNode->getImplementation(target); - if (!implement || !implement->isA()) - { - continue; - } - - NodeGraphPtr sourceSubGraph = implement->asA(); - std::unordered_map subNodeMap; - - // Precompute downstream ports for efficiency. + // Precompute graph implementations and downstream ports for this node vector. using PortElementVec = vector; - PortElementVec outerPorts = refNode->getDownstreamPorts(); - std::unordered_map sourcePortsMap; - for (NodePtr sourceSubNode : sourceSubGraph->getNodes()) + std::unordered_map graphImplMap; + std::unordered_map downstreamPortMap; + for (NodePtr cacheNode : processNodeVec) { - sourcePortsMap[sourceSubNode] = sourceSubNode->getDownstreamPorts(); + InterfaceElementPtr implement = cacheNode->getImplementation(target); + if (!implement || !implement->isA()) + { + continue; + } + NodeGraphPtr subNodeGraph = implement->asA(); + graphImplMap[cacheNode] = subNodeGraph; + downstreamPortMap[cacheNode] = cacheNode->getDownstreamPorts(); + for (NodePtr subNode : subNodeGraph->getNodes()) + { + downstreamPortMap[subNode] = subNode->getDownstreamPorts(); + } } - - // Create a new instance of each original subnode. - for (NodePtr sourceSubNode : sourceSubGraph->getNodes()) + processNodeVec.clear(); + + // Iterate through nodes with graph implementations. + for (auto pair : graphImplMap) { - string destName = createValidChildName(implement->getName() + "_" + sourceSubNode->getName()); - NodePtr destSubNode = addNode(sourceSubNode->getCategory(), destName); - destSubNode->copyContentFrom(sourceSubNode); - setChildIndex(destSubNode->getName(), getChildIndex(refNode->getName())); + NodePtr processNode = pair.first; + NodeGraphPtr sourceSubGraph = pair.second; + std::unordered_map subNodeMap; - // Transfer interface properties from the reference node to the new subnode. - for (ValueElementPtr destValue : destSubNode->getChildrenOfType()) + // Create a new instance of each original subnode. + for (NodePtr sourceSubNode : sourceSubGraph->getNodes()) { - if (!destValue->hasInterfaceName()) - { - continue; - } + string destName = createValidChildName(sourceSubGraph->getName() + "_" + sourceSubNode->getName()); + NodePtr destSubNode = addNode(sourceSubNode->getCategory(), destName); + destSubNode->copyContentFrom(sourceSubNode); + setChildIndex(destSubNode->getName(), getChildIndex(processNode->getName())); - ValueElementPtr refValue = refNode->getChildOfType(destValue->getInterfaceName()); - if (refValue) + // Transfer interface properties from the reference node to the new subnode. + for (ValueElementPtr destValue : destSubNode->getChildrenOfType()) { - if (refValue->hasValueString()) + if (!destValue->hasInterfaceName()) { - destValue->setValueString(refValue->getValueString()); + continue; } - if (destValue->isA() && refValue->isA()) + + ValueElementPtr refValue = processNode->getChildOfType(destValue->getInterfaceName()); + if (refValue) { - InputPtr refInput = refValue->asA(); - InputPtr newInput = destValue->asA(); - if (refInput->hasNodeName()) + if (refValue->hasValueString()) { - newInput->setNodeName(refInput->getNodeName()); + destValue->setValueString(refValue->getValueString()); } - if (refInput->hasOutputString()) + if (destValue->isA() && refValue->isA()) { - newInput->setOutputString(refInput->getOutputString()); + InputPtr refInput = refValue->asA(); + InputPtr newInput = destValue->asA(); + if (refInput->hasNodeName()) + { + newInput->setNodeName(refInput->getNodeName()); + } + if (refInput->hasOutputString()) + { + newInput->setOutputString(refInput->getOutputString()); + } } } + destValue->removeAttribute(ValueElement::INTERFACE_NAME_ATTRIBUTE); } - destValue->removeAttribute(ValueElement::INTERFACE_NAME_ATTRIBUTE); - } - // Store the mapping between subgraphs. - subNodeMap[sourceSubNode] = destSubNode; + // Store the mapping between subgraphs. + subNodeMap[sourceSubNode] = destSubNode; - // Add the subnode to the queue, allowing processing of nested subgraphs. - nodeQueue.push_back(destSubNode); - } + // Add the subnode to the queue, allowing processing of nested subgraphs. + processNodeVec.push_back(destSubNode); + } - // Transfer internal connections between subgraphs. - for (auto subNodePair : subNodeMap) - { - NodePtr sourceSubNode = subNodePair.first; - NodePtr destSubNode = subNodePair.second; - for (PortElementPtr origPort : sourcePortsMap[sourceSubNode]) + // Transfer internal connections between subgraphs. + for (auto subNodePair : subNodeMap) { - if (origPort->isA()) + NodePtr sourceSubNode = subNodePair.first; + NodePtr destSubNode = subNodePair.second; + for (PortElementPtr sourcePort : downstreamPortMap[sourceSubNode]) { - auto it = subNodeMap.find(origPort->getParent()->asA()); - if (it != subNodeMap.end()) + if (sourcePort->isA()) { - it->second->setConnectedNode(origPort->getName(), destSubNode); + auto it = subNodeMap.find(sourcePort->getParent()->asA()); + if (it != subNodeMap.end()) + { + it->second->setConnectedNode(sourcePort->getName(), destSubNode); + } } - } - else if (origPort->isA()) - { - for (PortElementPtr outerPort : outerPorts) + else if (sourcePort->isA()) { - outerPort->setConnectedNode(destSubNode); + for (PortElementPtr processNodePort : downstreamPortMap[processNode]) + { + processNodePort->setConnectedNode(destSubNode); + } } } } - } - // The original referencing node has been replaced, so remove it from - // the graph. - removeNode(refNode->getName()); + // The processed node has been replaced, so remove it from the graph. + removeNode(processNode->getName()); + } } } @@ -349,13 +352,4 @@ string GraphElement::asStringDot() const return dot; } -// -// NodeGraph methods -// - -NodeDefPtr NodeGraph::getNodeDef() const -{ - return resolveRootNameReference(getNodeDefString()); -} - } // namespace MaterialX diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index 643e28ffb0..8441686bac 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -225,48 +225,8 @@ class NodeGraph : public GraphElement } virtual ~NodeGraph() { } - /// @name NodeDef - /// @{ - - /// Set the NodeDef string for the graph. - void setNodeDefString(const string& nodeDef) - { - setAttribute(NODE_DEF_ATTRIBUTE, nodeDef); - } - - /// Return true if the given graph has a NodeDef string. - bool hasNodeDefString() const - { - return hasAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Return the NodeDef string for the graph. - const string& getNodeDefString() const - { - return getAttribute(NODE_DEF_ATTRIBUTE); - } - - /// Set the NodeDef element for the graph. - void setNodeDef(ConstNodeDefPtr nodeDef) - { - if (nodeDef) - { - setNodeDefString(nodeDef->getName()); - } - else - { - removeAttribute(NODE_DEF_ATTRIBUTE); - } - } - - /// Return the NodeDef element for the graph. - NodeDefPtr getNodeDef() const; - - /// @} - public: static const string CATEGORY; - static const string NODE_DEF_ATTRIBUTE; }; } // namespace MaterialX diff --git a/source/MaterialXCore/Traversal.cpp b/source/MaterialXCore/Traversal.cpp index 7ea4514ddd..1eb6110b57 100644 --- a/source/MaterialXCore/Traversal.cpp +++ b/source/MaterialXCore/Traversal.cpp @@ -15,7 +15,6 @@ const Edge NULL_EDGE(nullptr, nullptr, nullptr); const TreeIterator NULL_TREE_ITERATOR(nullptr); const GraphIterator NULL_GRAPH_ITERATOR(nullptr, nullptr); const InheritanceIterator NULL_INHERITANCE_ITERATOR(nullptr); -const AncestorIterator NULL_ANCESTOR_ITERATOR(nullptr); // // Edge methods @@ -213,28 +212,4 @@ InheritanceIterator& InheritanceIterator::operator++() return *this; } -// -// AncestorIterator methods -// - -const AncestorIterator& AncestorIterator::end() -{ - return NULL_ANCESTOR_ITERATOR; -} - -AncestorIterator& AncestorIterator::operator++() -{ - if (_holdCount) - { - _holdCount--; - return *this; - } - - if (_elem) - { - _elem = _elem->getParent(); - } - return *this; -} - } // namespace MaterialX diff --git a/source/MaterialXCore/Traversal.h b/source/MaterialXCore/Traversal.h index 30a23c6627..9353080256 100644 --- a/source/MaterialXCore/Traversal.h +++ b/source/MaterialXCore/Traversal.h @@ -388,55 +388,6 @@ class InheritanceIterator size_t _holdCount; }; -/// @class AncestorIterator -/// An iterator object representing the current state of an ancestor traversal. -/// -/// @sa Element::traverseAncestors -class AncestorIterator -{ - public: - explicit AncestorIterator(ConstElementPtr elem) : - _elem(elem), - _holdCount(0) - { - } - ~AncestorIterator() { } - - bool operator==(const AncestorIterator& rhs) const - { - return _elem == rhs._elem; - } - bool operator!=(const AncestorIterator& rhs) const - { - return !(*this == rhs); - } - - /// Dereference this iterator, returning the current element in the - /// traversal. - ConstElementPtr operator*() const - { - return _elem; - } - - /// Iterate to the next element in the traversal. - AncestorIterator& operator++(); - - /// Interpret this object as an iteration range, and return its begin - /// iterator. - AncestorIterator& begin(size_t holdCount = 0) - { - _holdCount = holdCount; - return *this; - } - - /// Return the sentinel end iterator for this class. - static const AncestorIterator& end(); - - private: - ConstElementPtr _elem; - size_t _holdCount; -}; - /// @class ExceptionFoundCycle /// An exception that is thrown when a traversal call encounters a cycle. class ExceptionFoundCycle : public Exception @@ -450,7 +401,6 @@ extern const Edge NULL_EDGE; extern const TreeIterator NULL_TREE_ITERATOR; extern const GraphIterator NULL_GRAPH_ITERATOR; extern const InheritanceIterator NULL_INHERITANCE_ITERATOR; -extern const AncestorIterator NULL_ANCESTOR_ITERATOR; } // namespace MaterialX diff --git a/source/MaterialXTest/Traversal.cpp b/source/MaterialXTest/Traversal.cpp index bfe9a507f5..38e22068f8 100644 --- a/source/MaterialXTest/Traversal.cpp +++ b/source/MaterialXTest/Traversal.cpp @@ -14,16 +14,12 @@ TEST_CASE("Traversal", "[traversal]") // Test null iterators. mx::TreeIterator nullTree = mx::NULL_TREE_ITERATOR; mx::GraphIterator nullGraph = mx::NULL_GRAPH_ITERATOR; - mx::AncestorIterator nullAncestor = mx::NULL_ANCESTOR_ITERATOR; REQUIRE(*nullTree == nullptr); REQUIRE(*nullGraph == mx::NULL_EDGE); - REQUIRE(*nullAncestor == nullptr); ++nullTree; ++nullGraph; - ++nullAncestor; REQUIRE(nullTree == mx::NULL_TREE_ITERATOR); REQUIRE(nullGraph == mx::NULL_GRAPH_ITERATOR); - REQUIRE(nullAncestor == mx::NULL_ANCESTOR_ITERATOR); // Create a document. mx::DocumentPtr doc = mx::createDocument(); diff --git a/source/PyMaterialX/PyDefinition.cpp b/source/PyMaterialX/PyDefinition.cpp index 312b475741..e245e32df5 100644 --- a/source/PyMaterialX/PyDefinition.cpp +++ b/source/PyMaterialX/PyDefinition.cpp @@ -31,11 +31,6 @@ void bindPyDefinition(py::module& mod) .def_readonly_static("NODE_ATTRIBUTE", &mx::NodeDef::NODE_ATTRIBUTE); py::class_(mod, "Implementation") - .def("setNodeDefString", &mx::Implementation::setNodeDefString) - .def("hasNodeDefString", &mx::Implementation::hasNodeDefString) - .def("getNodeDefString", &mx::Implementation::getNodeDefString) - .def("setNodeDef", &mx::Implementation::setNodeDef) - .def("getNodeDef", &mx::Implementation::getNodeDef) .def("setFile", &mx::Implementation::setFile) .def("hasFile", &mx::Implementation::hasFile) .def("getFile", &mx::Implementation::getFile) @@ -46,7 +41,6 @@ void bindPyDefinition(py::module& mod) .def("hasLanguage", &mx::Implementation::hasLanguage) .def("getLanguage", &mx::Implementation::getLanguage) .def_readonly_static("CATEGORY", &mx::Implementation::CATEGORY) - .def_readonly_static("NODE_DEF_ATTRIBUTE", &mx::Implementation::NODE_DEF_ATTRIBUTE) .def_readonly_static("FILE_ATTRIBUTE", &mx::Implementation::FILE_ATTRIBUTE) .def_readonly_static("FUNCTION_ATTRIBUTE", &mx::Implementation::FUNCTION_ATTRIBUTE) .def_readonly_static("LANGUAGE_ATTRIBUTE", &mx::Implementation::LANGUAGE_ATTRIBUTE); diff --git a/source/PyMaterialX/PyElement.cpp b/source/PyMaterialX/PyElement.cpp index fcc8021bec..9e48594827 100644 --- a/source/PyMaterialX/PyElement.cpp +++ b/source/PyMaterialX/PyElement.cpp @@ -95,7 +95,6 @@ void bindPyElement(py::module& mod) .def("getUpstreamElement", &mx::Element::getUpstreamElement, py::arg("material") = nullptr, py::arg("index") = 0) .def("traverseInheritance", &mx::Element::traverseInheritance) - .def("traverseAncestors", &mx::Element::traverseAncestors) .def("setSourceUri", &mx::Element::setSourceUri) .def("hasSourceUri", &mx::Element::hasSourceUri) .def("getSourceUri", &mx::Element::getSourceUri) diff --git a/source/PyMaterialX/PyInterface.cpp b/source/PyMaterialX/PyInterface.cpp index 673d7bc301..22a12dedc5 100644 --- a/source/PyMaterialX/PyInterface.cpp +++ b/source/PyMaterialX/PyInterface.cpp @@ -35,6 +35,11 @@ void bindPyInterface(py::module& mod) .def_readonly_static("CATEGORY", &mx::Output::CATEGORY); py::class_(mod, "InterfaceElement") + .def("setNodeDefString", &mx::InterfaceElement::setNodeDefString) + .def("hasNodeDefString", &mx::InterfaceElement::hasNodeDefString) + .def("getNodeDefString", &mx::InterfaceElement::getNodeDefString) + .def("setNodeDef", &mx::InterfaceElement::setNodeDef) + .def("getNodeDef", &mx::InterfaceElement::getNodeDef) .def("addParameter", &mx::InterfaceElement::addParameter, py::arg("name") = mx::EMPTY_STRING, py::arg("type") = mx::DEFAULT_TYPE_STRING) .def("getParameter", &mx::InterfaceElement::getParameter) @@ -86,5 +91,6 @@ void bindPyInterface(py::module& mod) BIND_INTERFACE_TYPE_INSTANCE(vector4, mx::Vector4) BIND_INTERFACE_TYPE_INSTANCE(matrix33, mx::Matrix33) BIND_INTERFACE_TYPE_INSTANCE(matrix44, mx::Matrix44) - BIND_INTERFACE_TYPE_INSTANCE(string, std::string); + BIND_INTERFACE_TYPE_INSTANCE(string, std::string) + .def_readonly_static("NODE_DEF_ATTRIBUTE", &mx::InterfaceElement::NODE_DEF_ATTRIBUTE); } diff --git a/source/PyMaterialX/PyNode.cpp b/source/PyMaterialX/PyNode.cpp index 39b512a9ca..9e804f6fc9 100644 --- a/source/PyMaterialX/PyNode.cpp +++ b/source/PyMaterialX/PyNode.cpp @@ -40,10 +40,5 @@ void bindPyNode(py::module& mod) .def("asStringDot", &mx::NodeGraph::asStringDot); py::class_(mod, "NodeGraph") - .def("setNodeDefString", &mx::NodeGraph::setNodeDefString) - .def("hasNodeDefString", &mx::NodeGraph::hasNodeDefString) - .def("getNodeDefString", &mx::NodeGraph::getNodeDefString) - .def("setNodeDef", &mx::NodeGraph::setNodeDef) - .def("getNodeDef", &mx::NodeGraph::getNodeDef) .def_readonly_static("CATEGORY", &mx::NodeGraph::CATEGORY); } diff --git a/source/PyMaterialX/PyTraversal.cpp b/source/PyMaterialX/PyTraversal.cpp index b1de7685c1..77991c15b3 100644 --- a/source/PyMaterialX/PyTraversal.cpp +++ b/source/PyMaterialX/PyTraversal.cpp @@ -68,17 +68,5 @@ void bindPyTraversal(py::module& mod) return *it; }); - py::class_(mod, "AncestorIterator") - .def("__iter__", [](mx::AncestorIterator& it) -> mx::AncestorIterator& - { - return it.begin(1); - }) - .def("__next__", [](mx::AncestorIterator& it) - { - if (++it == it.end()) - throw py::stop_iteration(); - return *it; - }); - py::register_exception(mod, "ExceptionFoundCycle"); } From ac566d3d1ba6e3370bc58ab5e9a85749ec14480e Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 21 Jul 2018 16:39:42 -0700 Subject: [PATCH 25/27] Update standard library for v1.36 --- documents/Examples/MultiOutput.mtlx | 10 +- documents/Examples/NodeGraphs.mtlx | 6 +- documents/Examples/PostShaderComposite.mtlx | 20 +- documents/Examples/PreShaderComposite.mtlx | 13 +- documents/Examples/SubGraphs.mtlx | 4 +- documents/Libraries/mx_stdlib_defs.mtlx | 2777 -------------- documents/Libraries/mx_stdlib_impl_osl.mtlx | 730 ---- documents/Libraries/stdlib_defs.mtlx | 3693 +++++++++++++++++++ documents/Libraries/stdlib_ng.mtlx | 2350 ++++++++++++ documents/Libraries/stdlib_osl_impl.mtlx | 932 +++++ python/MaterialXTest/main.py | 6 +- source/MaterialXTest/Document.cpp | 23 + source/MaterialXTest/File.cpp | 2 +- source/MaterialXTest/XmlIo.cpp | 142 +- 14 files changed, 7101 insertions(+), 3607 deletions(-) delete mode 100644 documents/Libraries/mx_stdlib_defs.mtlx delete mode 100644 documents/Libraries/mx_stdlib_impl_osl.mtlx create mode 100644 documents/Libraries/stdlib_defs.mtlx create mode 100644 documents/Libraries/stdlib_ng.mtlx create mode 100644 documents/Libraries/stdlib_osl_impl.mtlx diff --git a/documents/Examples/MultiOutput.mtlx b/documents/Examples/MultiOutput.mtlx index 1dcf256686..1056b1ee0f 100644 --- a/documents/Examples/MultiOutput.mtlx +++ b/documents/Examples/MultiOutput.mtlx @@ -15,23 +15,19 @@ - - - - - + - + - + diff --git a/documents/Examples/NodeGraphs.mtlx b/documents/Examples/NodeGraphs.mtlx index 7248ea0b5c..cd38754043 100644 --- a/documents/Examples/NodeGraphs.mtlx +++ b/documents/Examples/NodeGraphs.mtlx @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -75,7 +75,7 @@ - + diff --git a/documents/Examples/PostShaderComposite.mtlx b/documents/Examples/PostShaderComposite.mtlx index 1166ba6b61..bfbf7ec3aa 100644 --- a/documents/Examples/PostShaderComposite.mtlx +++ b/documents/Examples/PostShaderComposite.mtlx @@ -1,10 +1,10 @@ - + - + @@ -20,24 +20,24 @@ - + - + - + - + @@ -53,13 +53,13 @@ - + - + @@ -67,11 +67,11 @@ - + - + diff --git a/documents/Examples/PreShaderComposite.mtlx b/documents/Examples/PreShaderComposite.mtlx index 8b6bb9764e..8174529c33 100644 --- a/documents/Examples/PreShaderComposite.mtlx +++ b/documents/Examples/PreShaderComposite.mtlx @@ -77,34 +77,34 @@ - + - + - + - + - + - + @@ -127,4 +127,3 @@ - diff --git a/documents/Examples/SubGraphs.mtlx b/documents/Examples/SubGraphs.mtlx index 00ea9f586f..ebbeb5c5bc 100644 --- a/documents/Examples/SubGraphs.mtlx +++ b/documents/Examples/SubGraphs.mtlx @@ -1,6 +1,6 @@ - + @@ -73,7 +73,7 @@ - + diff --git a/documents/Libraries/mx_stdlib_defs.mtlx b/documents/Libraries/mx_stdlib_defs.mtlx deleted file mode 100644 index 44f1c7b267..0000000000 --- a/documents/Libraries/mx_stdlib_defs.mtlx +++ /dev/null @@ -1,2777 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/documents/Libraries/mx_stdlib_impl_osl.mtlx b/documents/Libraries/mx_stdlib_impl_osl.mtlx deleted file mode 100644 index e62568c388..0000000000 --- a/documents/Libraries/mx_stdlib_impl_osl.mtlx +++ /dev/null @@ -1,730 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/documents/Libraries/stdlib_defs.mtlx b/documents/Libraries/stdlib_defs.mtlx new file mode 100644 index 0000000000..2761ee5384 --- /dev/null +++ b/documents/Libraries/stdlib_defs.mtlx @@ -0,0 +1,3693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/Libraries/stdlib_ng.mtlx b/documents/Libraries/stdlib_ng.mtlx new file mode 100644 index 0000000000..4a0326995a --- /dev/null +++ b/documents/Libraries/stdlib_ng.mtlx @@ -0,0 +1,2350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/Libraries/stdlib_osl_impl.mtlx b/documents/Libraries/stdlib_osl_impl.mtlx new file mode 100644 index 0000000000..47897940c5 --- /dev/null +++ b/documents/Libraries/stdlib_osl_impl.mtlx @@ -0,0 +1,932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py index 1a10f1b272..deedc5a126 100644 --- a/python/MaterialXTest/main.py +++ b/python/MaterialXTest/main.py @@ -28,13 +28,15 @@ _exampleDir = os.path.join(_fileDir, '../../documents/Examples/') _searchPath = _libraryDir + ';' + _exampleDir -_libraryFilenames = ('mx_stdlib_defs.mtlx', - 'mx_stdlib_impl_osl.mtlx') +_libraryFilenames = ('stdlib_defs.mtlx', + 'stdlib_ng.mtlx', + 'stdlib_osl_impl.mtlx') _exampleFilenames = ('CustomNode.mtlx', 'Looks.mtlx', 'MaterialBasic.mtlx', 'MultiOutput.mtlx', 'PaintMaterials.mtlx', + 'PostShaderComposite.mtlx', 'PreShaderComposite.mtlx', 'BxDF/alSurface.mtlx', 'BxDF/Disney_BRDF_2012.mtlx', diff --git a/source/MaterialXTest/Document.cpp b/source/MaterialXTest/Document.cpp index 48e2fa5608..ea5dd750e5 100644 --- a/source/MaterialXTest/Document.cpp +++ b/source/MaterialXTest/Document.cpp @@ -73,4 +73,27 @@ TEST_CASE("Document", "[document]") // Validate the document. REQUIRE(doc->validate()); + + // Create a namespaced custom library. + mx::DocumentPtr customLibrary = mx::createDocument(); + customLibrary->setNamespace("custom"); + mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("NG_custom"); + mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("ND_simpleSrf", "surfaceshader", "simpleSrf"); + mx::ImplementationPtr customImpl = customLibrary->addImplementation("IM_custom"); + mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "custom1"); + customImpl->setNodeDef(customNodeDef); + REQUIRE(customLibrary->validate()); + + // Import the custom library. + doc->importLibrary(customLibrary); + mx::NodeGraphPtr importedNodeGraph = doc->getNodeGraph("custom:NG_custom"); + mx::NodeDefPtr importedNodeDef = doc->getNodeDef("custom:ND_simpleSrf"); + mx::ImplementationPtr importedImpl = doc->getImplementation("custom:IM_custom"); + mx::NodePtr importedNode = importedNodeGraph->getNode("custom1"); + REQUIRE(importedNodeDef != nullptr); + REQUIRE(importedNode->getNodeDef() == importedNodeDef); + REQUIRE(importedImpl->getNodeDef() == importedNodeDef); + + // Validate the combined document. + REQUIRE(doc->validate()); } diff --git a/source/MaterialXTest/File.cpp b/source/MaterialXTest/File.cpp index 9fcee5a2bd..bb6473d981 100644 --- a/source/MaterialXTest/File.cpp +++ b/source/MaterialXTest/File.cpp @@ -34,7 +34,7 @@ TEST_CASE("File system operations", "[file]") { std::vector filenames = { - "documents/Libraries/mx_stdlib_defs.mtlx", + "documents/Libraries/stdlib_defs.mtlx", "documents/Examples/MaterialBasic.mtlx", "documents/Examples/PaintMaterials.mtlx", }; diff --git a/source/MaterialXTest/XmlIo.cpp b/source/MaterialXTest/XmlIo.cpp index fb4bd5e155..2dfec35dc6 100644 --- a/source/MaterialXTest/XmlIo.cpp +++ b/source/MaterialXTest/XmlIo.cpp @@ -13,8 +13,9 @@ TEST_CASE("Load content", "[xmlio]") { std::string libraryFilenames[] = { - "mx_stdlib_defs.mtlx", - "mx_stdlib_impl_osl.mtlx" + "stdlib_defs.mtlx", + "stdlib_ng.mtlx", + "stdlib_osl_impl.mtlx" }; std::string exampleFilenames[] = { @@ -23,6 +24,7 @@ TEST_CASE("Load content", "[xmlio]") "MaterialBasic.mtlx", "MultiOutput.mtlx", "PaintMaterials.mtlx", + "PostShaderComposite.mtlx", "PreShaderComposite.mtlx", "BxDF/alSurface.mtlx", "BxDF/Disney_BRDF_2012.mtlx", @@ -41,6 +43,7 @@ TEST_CASE("Load content", "[xmlio]") } // Read and validate each example document. + bool firstExample = true; for (std::string filename : exampleFilenames) { mx::DocumentPtr doc = mx::createDocument(); @@ -97,103 +100,106 @@ TEST_CASE("Load content", "[xmlio]") mx::readFromXmlString(writtenDoc, xmlString); REQUIRE(*writtenDoc == *doc); - // Serialize to XML with a custom predicate that skips images. - auto skipImages = [](mx::ElementPtr elem) - { - return !elem->isA("image"); - }; - xmlString = mx::writeToXmlString(doc, false, skipImages); - - // Verify that the serialized document contains no images. - writtenDoc = mx::createDocument(); - mx::readFromXmlString(writtenDoc, xmlString); - unsigned imageElementCount = 0; - for (mx::ElementPtr elem : writtenDoc->traverseTree()) - { - if (elem->isA("image")) - { - imageElementCount++; - } - } - REQUIRE(imageElementCount == 0); - // Combine document with the standard library. - mx::DocumentPtr doc2 = doc->copy(); for (mx::DocumentPtr lib : libs) { - doc2->importLibrary(lib); + doc->importLibrary(lib); } - REQUIRE(doc2->validate()); + REQUIRE(doc->validate()); // Verify that all referenced types and nodes are declared, and that // referenced node declarations are implemented. - for (mx::ElementPtr elem : doc2->traverseTree()) + bool referencesValid = true; + for (mx::ElementPtr elem : doc->traverseTree()) { + if (!firstExample && elem->getActiveSourceUri() != doc->getSourceUri()) + { + continue; + } + mx::TypedElementPtr typedElem = elem->asA(); mx::NodePtr node = elem->asA(); if (typedElem && typedElem->hasType() && !typedElem->isMultiOutputType()) { - REQUIRE(typedElem->getTypeDef()); + if (!typedElem->getTypeDef()) + { + WARN("[" + node->getActiveSourceUri() + "] TypedElement " + node->getName() + " has no matching TypeDef"); + referencesValid = false; + } } if (node) { - REQUIRE(node->getNodeDef()); - REQUIRE(node->getImplementation()); + if (!node->getNodeDef()) + { + WARN("[" + node->getActiveSourceUri() + "] Node " + node->getName() + " has no matching NodeDef"); + referencesValid = false; + } + if (!node->getImplementation()) + { + WARN("[" + node->getActiveSourceUri() + "] Node " + node->getName() + " has no matching Implementation"); + referencesValid = false; + } } } - - // Create a namespaced custom library. - mx::DocumentPtr customLibrary = mx::createDocument(); - customLibrary->setNamespace("custom"); - mx::NodeGraphPtr customNodeGraph = customLibrary->addNodeGraph("NG_custom"); - mx::NodeDefPtr customNodeDef = customLibrary->addNodeDef("ND_simpleSrf", "surfaceshader", "simpleSrf"); - mx::ImplementationPtr customImpl = customLibrary->addImplementation("IM_custom"); - mx::NodePtr customNode = customNodeGraph->addNodeInstance(customNodeDef, "custom1"); - customImpl->setNodeDef(customNodeDef); - REQUIRE(customLibrary->validate()); - - // Import the custom library. - doc2->importLibrary(customLibrary); - mx::NodeGraphPtr importedNodeGraph = doc2->getNodeGraph("custom:NG_custom"); - mx::NodeDefPtr importedNodeDef = doc2->getNodeDef("custom:ND_simpleSrf"); - mx::ImplementationPtr importedImpl = doc2->getImplementation("custom:IM_custom"); - mx::NodePtr importedNode = importedNodeGraph->getNode("custom1"); - REQUIRE(importedNodeDef != nullptr); - REQUIRE(importedNode->getNodeDef() == importedNodeDef); - REQUIRE(importedImpl->getNodeDef() == importedNodeDef); - REQUIRE(doc2->validate()); + REQUIRE(referencesValid); // Flatten subgraph references. - for (mx::NodeGraphPtr nodeGraph : doc2->getNodeGraphs()) + for (mx::NodeGraphPtr nodeGraph : doc->getNodeGraphs()) { + if (!firstExample && nodeGraph->getActiveSourceUri() != doc->getSourceUri()) + { + continue; + } nodeGraph->flattenSubgraphs(); } - REQUIRE(doc2->validate()); - - // Read document without XIncludes. - mx::DocumentPtr doc3 = mx::createDocument(); - mx::XmlReadOptions readOptions; - readOptions.readXIncludes = false; - mx::readFromXmlFile(doc3, filename, searchPath, &readOptions); - if (*doc3 != *doc) - { - writtenDoc = mx::createDocument(); - xmlString = mx::writeToXmlString(doc); - mx::readFromXmlString(writtenDoc, xmlString, &readOptions); - REQUIRE(*doc3 == *writtenDoc); - } + REQUIRE(doc->validate()); + + firstExample = false; } // Read the same document twice with duplicate elements skipped. mx::DocumentPtr doc = mx::createDocument(); mx::XmlReadOptions readOptions; readOptions.skipDuplicateElements = true; - std::string filename = "PaintMaterials.mtlx"; + std::string filename = "PostShaderComposite.mtlx"; mx::readFromXmlFile(doc, filename, searchPath, &readOptions); mx::readFromXmlFile(doc, filename, searchPath, &readOptions); REQUIRE(doc->validate()); - // Read a non-existent document. + // Read document without XIncludes. mx::DocumentPtr doc2 = mx::createDocument(); - REQUIRE_THROWS_AS(mx::readFromXmlFile(doc2, "NonExistent.mtlx"), mx::ExceptionFileMissing&); + mx::XmlReadOptions readOptions2; + readOptions2.readXIncludes = false; + mx::readFromXmlFile(doc2, filename, searchPath, &readOptions2); + REQUIRE(*doc2 != *doc); + + // Serialize to XML and reconstruct. + std::string xmlString = mx::writeToXmlString(doc2); + mx::DocumentPtr doc3 = mx::createDocument(); + mx::readFromXmlString(doc3, xmlString, &readOptions2); + REQUIRE(*doc3 == *doc2); + + // Serialize to XML with a custom predicate that skips images. + auto skipImages = [](mx::ElementPtr elem) + { + return !elem->isA("image"); + }; + xmlString = mx::writeToXmlString(doc, false, skipImages); + + // Reconstruct and verify that the document contains no images. + mx::DocumentPtr doc4 = mx::createDocument(); + mx::readFromXmlString(doc4, xmlString); + unsigned imageElementCount = 0; + for (mx::ElementPtr elem : doc4->traverseTree()) + { + if (elem->isA("image")) + { + imageElementCount++; + } + } + REQUIRE(imageElementCount == 0); + + // Read a non-existent document. + mx::DocumentPtr doc5 = mx::createDocument(); + REQUIRE_THROWS_AS(mx::readFromXmlFile(doc5, "NonExistent.mtlx"), mx::ExceptionFileMissing&); } From 67a1c31e8ffa9419ec75bdbb65a758489431f614 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sat, 21 Jul 2018 17:23:04 -0700 Subject: [PATCH 26/27] Additional data updates for v1.36 --- documents/Examples/PostShaderComposite.mtlx | 10 ++--- documents/Libraries/stdlib_ng.mtlx | 49 ++++++--------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/documents/Examples/PostShaderComposite.mtlx b/documents/Examples/PostShaderComposite.mtlx index bfbf7ec3aa..721c179517 100644 --- a/documents/Examples/PostShaderComposite.mtlx +++ b/documents/Examples/PostShaderComposite.mtlx @@ -20,24 +20,24 @@ - + - + - + - + @@ -59,7 +59,7 @@ - + diff --git a/documents/Libraries/stdlib_ng.mtlx b/documents/Libraries/stdlib_ng.mtlx index 4a0326995a..9eeb9e5670 100644 --- a/documents/Libraries/stdlib_ng.mtlx +++ b/documents/Libraries/stdlib_ng.mtlx @@ -950,15 +950,12 @@ A 4-corner bilinear value ramp. --> - - - - + - + @@ -980,15 +977,12 @@ - - - - + - + @@ -1010,15 +1004,12 @@ - - - - + - + @@ -1040,15 +1031,12 @@ - - - - + - + @@ -1070,15 +1058,12 @@ - - - - + - + @@ -1100,15 +1085,12 @@ - - - - + - + @@ -1130,15 +1112,12 @@ - - - - + - + From b5c83b6641fa6705fcf6c1b4c6cb6a57ce3438ca Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Sun, 22 Jul 2018 17:04:51 -0700 Subject: [PATCH 27/27] Updates for v1.36 release - Finalize changelog for v1.36.0. - Update MaterialX specification to v1.36. - Minor updates to NodeGraphs.mtlx and unit tests. --- CHANGELOG.md | 6 +- documents/Examples/NodeGraphs.mtlx | 182 +++++++++--------- .../Specification/MaterialX.v1.35.Final.pdf | Bin 777993 -> 0 bytes .../Specification/MaterialX.v1.36.Spec.pdf | Bin 0 -> 765571 bytes python/MaterialXTest/main.py | 9 +- source/MaterialXTest/XmlIo.cpp | 52 +++-- 6 files changed, 123 insertions(+), 126 deletions(-) delete mode 100644 documents/Specification/MaterialX.v1.35.Final.pdf create mode 100644 documents/Specification/MaterialX.v1.36.Spec.pdf diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8dffd0d1..2f44892bd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,15 @@ # Change Log -## [1.36.0] - Development +## [1.36.0] - 2018-07-23 -Updating the MaterialX library to the v1.36 specification. +Updated the MaterialX library to the v1.36 specification. ### Added - Added support for Element namespaces. - Added support for NodeDef inheritance. +- Added support for root-level node elements. - Added support for inheritance attributes on MaterialX\:\:Material and MaterialX\:\:Look. - Added support for include and exclude attributes on MaterialX\:\:Collection. -- Added support for root-level node elements. - Added the MaterialX\:\:Token class for string substitutions. - Added the MaterialX\:\:Variant, MaterialX\:\:VariantSet, and MaterialX\:\:VariantAssign classes. - Added the MaterialX\:\:GeomPath class for geometry name comparisons. diff --git a/documents/Examples/NodeGraphs.mtlx b/documents/Examples/NodeGraphs.mtlx index cd38754043..e7945d89bd 100644 --- a/documents/Examples/NodeGraphs.mtlx +++ b/documents/Examples/NodeGraphs.mtlx @@ -1,99 +1,105 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/Specification/MaterialX.v1.35.Final.pdf b/documents/Specification/MaterialX.v1.35.Final.pdf deleted file mode 100644 index f9b22966224abf62d12e39acae1bb5bec7450ef0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 777993 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