mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-26 06:34:57 +00:00
678 lines
20 KiB
C++
678 lines
20 KiB
C++
//
|
|
// Copyright Contributors to the MaterialX Project
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#ifndef MATERIALX_INTERFACE_H
|
|
#define MATERIALX_INTERFACE_H
|
|
|
|
/// @file
|
|
/// Interface element subclasses
|
|
|
|
#include <MaterialXCore/Export.h>
|
|
|
|
#include <MaterialXCore/Geom.h>
|
|
|
|
MATERIALX_NAMESPACE_BEGIN
|
|
|
|
class PortElement;
|
|
class Input;
|
|
class Output;
|
|
class InterfaceElement;
|
|
class Node;
|
|
class NodeDef;
|
|
|
|
/// A shared pointer to a PortElement
|
|
using PortElementPtr = shared_ptr<PortElement>;
|
|
/// A shared pointer to a const PortElement
|
|
using ConstPortElementPtr = shared_ptr<const PortElement>;
|
|
|
|
/// A shared pointer to an Input
|
|
using InputPtr = shared_ptr<Input>;
|
|
/// A shared pointer to a const Input
|
|
using ConstInputPtr = shared_ptr<const Input>;
|
|
|
|
/// A shared pointer to an Output
|
|
using OutputPtr = shared_ptr<Output>;
|
|
/// A shared pointer to a const Output
|
|
using ConstOutputPtr = shared_ptr<const Output>;
|
|
|
|
/// A shared pointer to an InterfaceElement
|
|
using InterfaceElementPtr = shared_ptr<InterfaceElement>;
|
|
/// A shared pointer to a const InterfaceElement
|
|
using ConstInterfaceElementPtr = shared_ptr<const InterfaceElement>;
|
|
|
|
using CharSet = std::set<char>;
|
|
|
|
/// @class PortElement
|
|
/// The base class for port elements such as Input and Output.
|
|
///
|
|
/// Port elements support spatially-varying upstream connections to nodes.
|
|
class MX_CORE_API PortElement : public ValueElement
|
|
{
|
|
protected:
|
|
PortElement(ElementPtr parent, const string& category, const string& name) :
|
|
ValueElement(parent, category, name)
|
|
{
|
|
}
|
|
|
|
public:
|
|
virtual ~PortElement() { }
|
|
|
|
protected:
|
|
using NodePtr = shared_ptr<Node>;
|
|
using ConstNodePtr = shared_ptr<const Node>;
|
|
|
|
public:
|
|
/// @name Node Name
|
|
/// @{
|
|
|
|
/// Set the node name string of this element, creating a connection to
|
|
/// the Node with the given name within the same NodeGraph.
|
|
void setNodeName(const string& node)
|
|
{
|
|
setAttribute(NODE_NAME_ATTRIBUTE, node);
|
|
}
|
|
|
|
/// Return true if this element has a node name string.
|
|
bool hasNodeName() const
|
|
{
|
|
return hasAttribute(NODE_NAME_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the node name string of this element.
|
|
const string& getNodeName() const
|
|
{
|
|
return getAttribute(NODE_NAME_ATTRIBUTE);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Node Graph
|
|
/// @{
|
|
|
|
/// Set the node graph string of this element.
|
|
void setNodeGraphString(const string& node)
|
|
{
|
|
setAttribute(NODE_GRAPH_ATTRIBUTE, node);
|
|
}
|
|
|
|
/// 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);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Output
|
|
/// @{
|
|
|
|
/// Set the output string of this element.
|
|
void setOutputString(const string& output)
|
|
{
|
|
setAttribute(OUTPUT_ATTRIBUTE, output);
|
|
}
|
|
|
|
/// Return true if this element has an output string.
|
|
bool hasOutputString() const
|
|
{
|
|
return hasAttribute(OUTPUT_ATTRIBUTE);
|
|
}
|
|
|
|
/// Set the output to which this input is connected. If the output
|
|
/// argument is null, then any existing output connection will be cleared.
|
|
void setConnectedOutput(ConstOutputPtr output);
|
|
|
|
/// Return the output, if any, to which this input is connected.
|
|
OutputPtr getConnectedOutput() const;
|
|
|
|
/// Return the output string of this element.
|
|
const string& getOutputString() const
|
|
{
|
|
return getAttribute(OUTPUT_ATTRIBUTE);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Connections
|
|
/// @{
|
|
|
|
/// Set the node to which this element is connected. The given node must
|
|
/// belong to the same node graph. If the node argument is null, then
|
|
/// any existing node connection will be cleared.
|
|
void setConnectedNode(ConstNodePtr node);
|
|
|
|
/// Return the node, if any, to which this element is connected.
|
|
virtual NodePtr getConnectedNode() 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 NODE_NAME_ATTRIBUTE;
|
|
static const string NODE_GRAPH_ATTRIBUTE;
|
|
static const string OUTPUT_ATTRIBUTE;
|
|
};
|
|
|
|
/// @class Input
|
|
/// An input element within a Node or NodeDef.
|
|
///
|
|
/// An Input holds either a uniform value or a connection to a spatially-varying
|
|
/// Output, either of which may be modified within the scope of a Material.
|
|
class MX_CORE_API Input : public PortElement
|
|
{
|
|
public:
|
|
Input(ElementPtr parent, const string& name) :
|
|
PortElement(parent, CATEGORY, name)
|
|
{
|
|
}
|
|
virtual ~Input() { }
|
|
|
|
public:
|
|
/// @name Default Geometric Property
|
|
/// @{
|
|
|
|
/// Set the defaultgeomprop string for the input.
|
|
void setDefaultGeomPropString(const string& geomprop)
|
|
{
|
|
setAttribute(DEFAULT_GEOM_PROP_ATTRIBUTE, geomprop);
|
|
}
|
|
|
|
/// Return true if the given input has a defaultgeomprop string.
|
|
bool hasDefaultGeomPropString() const
|
|
{
|
|
return hasAttribute(DEFAULT_GEOM_PROP_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the defaultgeomprop string for the input.
|
|
const string& getDefaultGeomPropString() const
|
|
{
|
|
return getAttribute(DEFAULT_GEOM_PROP_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the GeomPropDef element to use, if defined for this input.
|
|
GeomPropDefPtr getDefaultGeomProp() const;
|
|
|
|
/// @}
|
|
/// @name Connections
|
|
/// @{
|
|
|
|
/// Return the node, if any, to which this input is connected.
|
|
NodePtr getConnectedNode() const override;
|
|
|
|
/// Connects this input to a corresponding interface with the given name.
|
|
/// If the interface name specified is an empty string then any existing connection is removed.
|
|
void setConnectedInterfaceName(const string& interfaceName);
|
|
|
|
/// Return the input on the parent graph corresponding to the interface name
|
|
/// for this input.
|
|
InputPtr getInterfaceInput() const;
|
|
|
|
/// @}
|
|
/// @name Hints
|
|
/// @{
|
|
|
|
/// Return true if the input has a hint
|
|
bool hasHint() const
|
|
{
|
|
return hasAttribute(HINT_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the code generation hint
|
|
const string& getHint() const
|
|
{
|
|
return getAttribute(HINT_ATTRIBUTE);
|
|
}
|
|
|
|
// Set the code generation hint
|
|
void setHint(const string& hint)
|
|
{
|
|
setAttribute(HINT_ATTRIBUTE, hint);
|
|
}
|
|
|
|
/// @}
|
|
/// @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 CATEGORY;
|
|
static const string DEFAULT_GEOM_PROP_ATTRIBUTE;
|
|
static const string HINT_ATTRIBUTE;
|
|
static const string TRANSPARENCY_HINT;
|
|
static const string OPACITY_HINT;
|
|
static const string ANISOTROPY_HINT;
|
|
};
|
|
|
|
/// @class Output
|
|
/// A spatially-varying output element within a NodeGraph or NodeDef.
|
|
class MX_CORE_API Output : public PortElement
|
|
{
|
|
public:
|
|
Output(ElementPtr parent, const string& name) :
|
|
PortElement(parent, CATEGORY, name)
|
|
{
|
|
}
|
|
virtual ~Output() { }
|
|
|
|
public:
|
|
/// @name Traversal
|
|
/// @{
|
|
|
|
/// Return the Edge with the given index that lies directly upstream from
|
|
/// this element in the dataflow graph.
|
|
Edge getUpstreamEdge(size_t index = 0) const override;
|
|
|
|
/// Return the number of queryable upstream edges for this element.
|
|
size_t getUpstreamEdgeCount() const override
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/// Return true if a cycle exists in any upstream path from this element.
|
|
bool hasUpstreamCycle() 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 CATEGORY;
|
|
static const string DEFAULT_INPUT_ATTRIBUTE;
|
|
};
|
|
|
|
/// @class InterfaceElement
|
|
/// The base class for interface elements such as Node, NodeDef, and NodeGraph.
|
|
///
|
|
/// An InterfaceElement supports a set of Input and Output elements, with an API
|
|
/// for setting their values.
|
|
class MX_CORE_API InterfaceElement : public TypedElement
|
|
{
|
|
protected:
|
|
InterfaceElement(ElementPtr parent, const string& category, const string& name) :
|
|
TypedElement(parent, category, name),
|
|
_inputCount(0),
|
|
_outputCount(0)
|
|
{
|
|
}
|
|
|
|
public:
|
|
virtual ~InterfaceElement() { }
|
|
|
|
protected:
|
|
using NodeDefPtr = shared_ptr<NodeDef>;
|
|
using ConstNodeDefPtr = shared_ptr<const NodeDef>;
|
|
|
|
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);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Inputs
|
|
/// @{
|
|
|
|
/// 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 = EMPTY_STRING,
|
|
const string& type = DEFAULT_TYPE_STRING)
|
|
{
|
|
InputPtr child = addChild<Input>(name);
|
|
child->setType(type);
|
|
return child;
|
|
}
|
|
|
|
/// Return the Input, if any, with the given name.
|
|
InputPtr getInput(const string& name) const
|
|
{
|
|
return getChildOfType<Input>(name);
|
|
}
|
|
|
|
/// Return a vector of all Input elements.
|
|
vector<InputPtr> getInputs() const
|
|
{
|
|
return getChildrenOfType<Input>();
|
|
}
|
|
|
|
/// Return the number of Input elements.
|
|
size_t getInputCount() const
|
|
{
|
|
return _inputCount;
|
|
}
|
|
|
|
/// Remove the Input, if any, with the given name.
|
|
void removeInput(const string& name)
|
|
{
|
|
removeChildOfType<Input>(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<InputPtr> getActiveInputs() const;
|
|
|
|
/// @}
|
|
/// @name Outputs
|
|
/// @{
|
|
|
|
/// 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.
|
|
/// @param type An optional type string.
|
|
/// @return A shared pointer to the new Output.
|
|
OutputPtr addOutput(const string& name = EMPTY_STRING,
|
|
const string& type = DEFAULT_TYPE_STRING)
|
|
{
|
|
OutputPtr output = addChild<Output>(name);
|
|
output->setType(type);
|
|
return output;
|
|
}
|
|
|
|
/// Return the Output, if any, with the given name.
|
|
OutputPtr getOutput(const string& name) const
|
|
{
|
|
return getChildOfType<Output>(name);
|
|
}
|
|
|
|
/// Return a vector of all Output elements.
|
|
vector<OutputPtr> getOutputs() const
|
|
{
|
|
return getChildrenOfType<Output>();
|
|
}
|
|
|
|
/// 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<Output>(name);
|
|
}
|
|
|
|
/// 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<OutputPtr> getActiveOutputs() const;
|
|
|
|
/// Set the output to which the given input is connected, creating a
|
|
/// child input if needed. If the node argument is null, then any
|
|
/// existing output connection on the input will be cleared.
|
|
void setConnectedOutput(const string& inputName, OutputPtr output);
|
|
|
|
/// Return the output connected to the given input. If the given input is
|
|
/// not present, then an empty OutputPtr is returned.
|
|
OutputPtr getConnectedOutput(const string& inputName) 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<Token>(name);
|
|
}
|
|
|
|
/// Return the Token, if any, with the given name.
|
|
TokenPtr getToken(const string& name) const
|
|
{
|
|
return getChildOfType<Token>(name);
|
|
}
|
|
|
|
/// Return a vector of all Token elements.
|
|
vector<TokenPtr> getTokens() const
|
|
{
|
|
return getChildrenOfType<Token>();
|
|
}
|
|
|
|
/// Remove the Token, if any, with the given name.
|
|
void removeToken(const string& name)
|
|
{
|
|
removeChildOfType<Token>(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<TokenPtr> getActiveTokens() const;
|
|
|
|
/// @}
|
|
/// @name Value Elements
|
|
/// @{
|
|
|
|
/// Return the ValueElement, if any, with the given name.
|
|
ValueElementPtr getValueElement(const string& name) const
|
|
{
|
|
return getChildOfType<ValueElement>(name);
|
|
}
|
|
|
|
/// Return the first value element with the given name that belongs to this
|
|
/// interface, taking interface inheritance into account.
|
|
/// Examples of value elements are 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 Input, Output, and Token.
|
|
vector<ValueElementPtr> getActiveValueElements() const;
|
|
|
|
/// @}
|
|
/// @name Values
|
|
/// @{
|
|
|
|
/// Set the typed value of an input by its name, creating a child element
|
|
/// to hold the input if needed.
|
|
template <class T> InputPtr setInputValue(const string& name,
|
|
const T& value,
|
|
const string& type = EMPTY_STRING);
|
|
|
|
/// Return the typed value of an input by its name, taking both the calling
|
|
/// element and its declaration into account.
|
|
/// @param name The name of the input to be evaluated.
|
|
/// @param target An optional target name, which will be used to filter
|
|
/// the declarations that are considered.
|
|
/// @return If the given input is found in this interface or its
|
|
/// declaration, then a shared pointer to its value is returned;
|
|
/// 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<string>(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 Target
|
|
/// @{
|
|
|
|
/// Set the target string of this interface.
|
|
void setTarget(const string& target)
|
|
{
|
|
setAttribute(TARGET_ATTRIBUTE, target);
|
|
}
|
|
|
|
/// Return true if the given interface has a target string.
|
|
bool hasTarget() const
|
|
{
|
|
return hasAttribute(TARGET_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the target string of this interface.
|
|
const string& getTarget() const
|
|
{
|
|
return getAttribute(TARGET_ATTRIBUTE);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Version
|
|
/// @{
|
|
|
|
/// Set the version string of this interface.
|
|
void setVersionString(const string& version)
|
|
{
|
|
setAttribute(VERSION_ATTRIBUTE, version);
|
|
}
|
|
|
|
/// Return true if this interface has a version string.
|
|
bool hasVersionString() const
|
|
{
|
|
return hasAttribute(VERSION_ATTRIBUTE);
|
|
}
|
|
|
|
/// Return the version string of this interface.
|
|
const string& getVersionString() const
|
|
{
|
|
return getAttribute(VERSION_ATTRIBUTE);
|
|
}
|
|
|
|
/// Set the major and minor versions as an integer pair.
|
|
void setVersionIntegers(int majorVersion, int minorVersion);
|
|
|
|
/// Return the major and minor versions as an integer pair.
|
|
virtual std::pair<int, int> getVersionIntegers() const;
|
|
|
|
/// @}
|
|
/// @name Default Version
|
|
/// @{
|
|
|
|
/// Set the default version flag of this element.
|
|
void setDefaultVersion(bool defaultVersion)
|
|
{
|
|
setTypedAttribute<bool>(DEFAULT_VERSION_ATTRIBUTE, defaultVersion);
|
|
}
|
|
|
|
/// Return the default version flag of this element.
|
|
bool getDefaultVersion() const
|
|
{
|
|
return getTypedAttribute<bool>(DEFAULT_VERSION_ATTRIBUTE);
|
|
}
|
|
|
|
/// @}
|
|
/// @name Utility
|
|
/// @{
|
|
|
|
/// Return the first declaration of this interface, optionally filtered
|
|
/// by the given target name.
|
|
/// @param target An optional target name, which will be used to filter
|
|
/// the declarations that are considered.
|
|
/// @return A shared pointer to declaration, or an empty shared pointer if
|
|
/// no declaration was found.
|
|
virtual ConstInterfaceElementPtr getDeclaration(const string& target = EMPTY_STRING) const;
|
|
|
|
/// Clear all attributes and descendants from this element.
|
|
void clearContent() override;
|
|
|
|
/// Return true if this instance has an exact input match with the given
|
|
/// declaration, where each input of this the instance corresponds to a
|
|
/// declaration input of the same name and type.
|
|
///
|
|
/// If an exact input match is not found, and the optional message argument
|
|
/// is provided, then an error message will be appended to the given string.
|
|
bool hasExactInputMatch(ConstInterfaceElementPtr declaration, string* message = nullptr) const;
|
|
|
|
/// @}
|
|
|
|
public:
|
|
static const string NODE_DEF_ATTRIBUTE;
|
|
static const string TARGET_ATTRIBUTE;
|
|
static const string VERSION_ATTRIBUTE;
|
|
static const string DEFAULT_VERSION_ATTRIBUTE;
|
|
|
|
protected:
|
|
void registerChildElement(ElementPtr child) override;
|
|
void unregisterChildElement(ElementPtr child) override;
|
|
|
|
private:
|
|
size_t _inputCount;
|
|
size_t _outputCount;
|
|
};
|
|
|
|
template <class T> InputPtr InterfaceElement::setInputValue(const string& name,
|
|
const T& value,
|
|
const string& type)
|
|
{
|
|
InputPtr input = getChildOfType<Input>(name);
|
|
if (!input)
|
|
input = addInput(name);
|
|
input->setValue(value, type);
|
|
return input;
|
|
}
|
|
|
|
MATERIALX_NAMESPACE_END
|
|
|
|
#endif
|