Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

183 lines
7.6 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#include <MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.h>
#include <MaterialXGenMdl/MdlSyntax.h>
#include <MaterialXGenShader/HwShaderGenerator.h>
#include <MaterialXGenShader/ShaderGenerator.h>
#include <MaterialXGenShader/Util.h>
#include <MaterialXCore/Definition.h>
MATERIALX_NAMESPACE_BEGIN
ShaderNodeImplPtr ClosureCompoundNodeMdl::create()
{
return std::make_shared<ClosureCompoundNodeMdl>();
}
void ClosureCompoundNodeMdl::addClassification(ShaderNode& node) const
{
// Add classification from the graph implementation.
node.addClassification(_rootGraph->getClassification());
}
void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
{
DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
{
const ShaderGenerator& shadergen = context.getShaderGenerator();
const MdlSyntax& mdlSyntax = static_cast<const MdlSyntax&>(shadergen.getSyntax());
// Emit functions for all child nodes
shadergen.emitFunctionDefinitions(*_rootGraph, context, stage);
// split all fields into separate functions
if (!_returnStruct.empty() && _unrollReturnStructMembers)
{
// make sure the upstream definitions are known
for (const ShaderGraphOutputSocket* outputSocket : _rootGraph->getOutputSockets())
{
if (!outputSocket->getConnection())
continue;
const ShaderNode* upstream = outputSocket->getConnection()->getNode();
const bool isMaterialExpr = (upstream->hasClassification(ShaderNode::Classification::CLOSURE) ||
upstream->hasClassification(ShaderNode::Classification::SHADER));
// since the emit functions are const, the field name to generate a function for is passed via context
const std::string& fieldName = outputSocket->getName();
GenUserDataStringPtr fieldNamePtr = std::make_shared<GenUserDataString>(fieldName);
context.pushUserData(CompoundNodeMdl::GEN_USER_DATA_RETURN_STRUCT_FIELD_NAME, fieldNamePtr);
// Emit function signature.
shadergen.emitComment("unrolled structure field: " + _returnStruct + "." + fieldName + " (name=\"" + node.getName() + "\")", stage);
emitFunctionSignature(node, context, stage);
// Special case for material expressions.
if (isMaterialExpr)
{
shadergen.emitLine(" = let", stage, false);
}
// Function body.
shadergen.emitScopeBegin(stage);
// Emit all texturing nodes. These are inputs to the
// closure nodes and need to be emitted first.
shadergen.emitFunctionCalls(*_rootGraph, context, stage, ShaderNode::Classification::TEXTURE);
// Emit function calls for internal closures nodes connected to the graph sockets.
// These will in turn emit function calls for any dependent closure nodes upstream.
if (upstream->getParent() == _rootGraph.get() &&
(upstream->hasClassification(ShaderNode::Classification::CLOSURE) || upstream->hasClassification(ShaderNode::Classification::SHADER)))
{
shadergen.emitFunctionCall(*upstream, context, stage);
}
// Emit final results
if (isMaterialExpr)
{
shadergen.emitScopeEnd(stage);
const string result = shadergen.getUpstreamResult(outputSocket, context);
shadergen.emitLine("in material(" + result + ")", stage);
}
else
{
const string result = shadergen.getUpstreamResult(outputSocket, context);
shadergen.emitLine("return " + result, stage);
}
shadergen.emitLineBreak(stage);
context.popUserData(CompoundNodeMdl::GEN_USER_DATA_RETURN_STRUCT_FIELD_NAME);
}
return;
}
const bool isMaterialExpr = (_rootGraph->hasClassification(ShaderNode::Classification::CLOSURE) ||
_rootGraph->hasClassification(ShaderNode::Classification::SHADER));
// Emit function signature.
emitFunctionSignature(node, context, stage);
// Special case for material expressions.
if (isMaterialExpr)
{
shadergen.emitLine(" = let", stage, false);
}
// Function body.
shadergen.emitScopeBegin(stage);
// Emit all texturing nodes. These are inputs to the
// closure nodes and need to be emitted first.
shadergen.emitFunctionCalls(*_rootGraph, context, stage, ShaderNode::Classification::TEXTURE);
// Emit function calls for internal closures nodes connected to the graph sockets.
// These will in turn emit function calls for any dependent closure nodes upstream.
for (ShaderGraphOutputSocket* outputSocket : _rootGraph->getOutputSockets())
{
if (outputSocket->getConnection())
{
const ShaderNode* upstream = outputSocket->getConnection()->getNode();
if (upstream->getParent() == _rootGraph.get() &&
(upstream->hasClassification(ShaderNode::Classification::CLOSURE) || upstream->hasClassification(ShaderNode::Classification::SHADER)))
{
shadergen.emitFunctionCall(*upstream, context, stage);
}
}
}
// Emit final results
if (isMaterialExpr)
{
shadergen.emitScopeEnd(stage);
const ShaderGraphOutputSocket* outputSocket = _rootGraph->getOutputSocket();
const string result = shadergen.getUpstreamResult(outputSocket, context);
shadergen.emitLine("in material(" + result + ")", stage);
}
else
{
if (!_returnStruct.empty())
{
const string resultVariableName = "result__";
shadergen.emitLine(_returnStruct + " " + resultVariableName, stage);
for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets())
{
const string result = shadergen.getUpstreamResult(output, context);
shadergen.emitLine(resultVariableName + mdlSyntax.modifyPortName(output->getName()) + " = " + result, stage);
}
shadergen.emitLine("return " + resultVariableName, stage);
}
else
{
const ShaderGraphOutputSocket* outputSocket = _rootGraph->getOutputSocket();
const string result = shadergen.getUpstreamResult(outputSocket, context);
shadergen.emitLine("return " + result, stage);
}
shadergen.emitScopeEnd(stage);
}
shadergen.emitLineBreak(stage);
}
}
void ClosureCompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const
{
DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
{
const ShaderGenerator& shadergen = context.getShaderGenerator();
// First emit calls for any closure dependencies upstream from this node.
shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE);
// Then emit this nodes function call.
CompoundNodeMdl::emitFunctionCall(node, context, stage);
}
}
MATERIALX_NAMESPACE_END