Blender V5.0
node_graph.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#ifdef WITH_USD
6# include <pxr/base/tf/stringUtils.h>
7#endif
8
9#include "BLI_hash.hh"
10#include "BLI_string_utils.hh"
11
12#include "BKE_node_runtime.hh"
13
14#include "node_graph.h"
15
17
18/* Prefix for nodes that don't map directly to a Blender shader node. */
19static const char *ANONYMOUS_NODE_NAME_PREFIX = "node";
20
21/* Valid name for MaterialX and USD. */
22static std::string valid_name(const StringRef name)
23{
24#ifdef WITH_USD
25 /* Node name should suite to MatX and USD valid names.
26 * It shouldn't start from '_', due to error occurred in Storm delegate. */
27 std::string res = MaterialX::createValidName(pxr::TfMakeValidIdentifier(name));
28#else
29 std::string res = MaterialX::createValidName(name);
30#endif
31 if (res[0] == '_') {
32 res = "node" + res;
33 }
34 return res;
35}
36
37/* Node Key */
38
43
45{
46 return node == other.node && socket_name == other.socket_name && to_type == other.to_type &&
48}
49
50/* Node Graph */
51
53 const Material *material,
55 const MaterialX::DocumentPtr &document)
59 graph_element_(document.get()),
61{
62}
63
64NodeGraph::NodeGraph(const NodeGraph &parent, const StringRef child_name)
65 : depsgraph(parent.depsgraph),
66 material(parent.material),
68#ifdef USE_MATERIALX_NODEGRAPH
70#else
72#endif
73{
74 std::string valid_child_name = valid_name(child_name);
75
76#ifdef USE_MATERIALX_NODEGRAPH
77 MaterialX::NodeGraphPtr graph = parent.graph_element_->getChildOfType<MaterialX::NodeGraph>(
78 valid_child_name);
79 if (!graph) {
80 CLOG_DEBUG(LOG_IO_MATERIALX, "<nodegraph name=%s>", valid_child_name.c_str());
81 graph = parent.graph_element_->addChild<MaterialX::NodeGraph>(valid_child_name);
82 }
83 graph_element_ = graph.get();
84#else
86 node_name_prefix_ = node_name_prefix_ + valid_child_name + "_";
87#endif
88}
89
94
96{
97 NodeItem item = empty_node();
98 item.node = graph_element_->getNode(name);
99 return item;
100}
101
103{
104 NodeItem item = empty_node();
105 item.output = graph_element_->getOutput(name);
106 return item;
107}
108
110{
111 NodeItem item = empty_node();
112 item.input = graph_element_->getInput(name);
113 return item;
114}
115
116std::string NodeGraph::unique_node_name(const bNode *node,
117 const StringRef socket_out_name,
119{
120 /* Reuse existing name, important in case it got changed due to conflicts. */
121 NodeKey key{node, socket_out_name, to_type, graph_element_};
122 const std::string *existing_name = key_to_name_map_.lookup_ptr(key);
123 if (existing_name) {
124 return *existing_name;
125 }
126
127 /* Generate name based on node, socket, to type and node groups. */
128 std::string name = node->name;
129
130 if (!socket_out_name.is_empty() && node->output_sockets().size() > 1) {
131 name += std::string("_") + socket_out_name;
132 }
134 name += "_" + NodeItem::type(to_type);
135 }
136
138
139 /* Avoid conflicts with anonymous node names. */
140 if (StringRef(name).startswith(ANONYMOUS_NODE_NAME_PREFIX)) {
141 name = "b" + name;
142 }
143
144 /* Ensure the name does not conflict with other nodes in the graph, which may happen when
145 * another Blender node name happens to match the complete name here. Can not just check
146 * the graph because the node with this name might not get added to it immediately. */
148 [this](const StringRef check_name) {
149 return check_name == export_params.output_node_name ||
150 graph_element_->getNode(check_name) != nullptr ||
151 used_node_names_.contains(check_name);
152 },
153 '_',
154 name);
155
157 key_to_name_map_.add_new(key, name);
158 return name;
159}
160
162{
163 if (item.node) {
164 item.node->setName(export_params.output_node_name);
165 }
166}
167
168std::string NodeGraph::unique_anonymous_node_name(MaterialX::GraphElement *graph_element)
169{
170 return BLI_uniquename_cb(
171 [graph_element](const StringRef check_name) {
172 return graph_element->getNode(check_name) != nullptr;
173 },
174 '_',
176}
177
178} // namespace blender::nodes::materialx
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
unsigned long long int uint64_t
constexpr bool is_empty() const
MaterialX::OutputPtr output
Definition node_item.h:56
static Type to_type(const GPUType type)
static const char * ANONYMOUS_NODE_NAME_PREFIX
Definition node_graph.cc:19
static std::string valid_name(const StringRef name)
Definition node_graph.cc:22
struct CLG_LogRef * LOG_IO_MATERIALX
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
const char * name
char name[64]
MaterialX::GraphElement * graph_element
Definition node_graph.h:56
bool operator==(const NodeKey &other) const
Definition node_graph.cc:44
void set_output_node_name(const NodeItem &item) const
NodeItem get_node(StringRef name) const
Definition node_graph.cc:95
std::string unique_node_name(const bNode *node, StringRef socket_out_name, NodeItem::Type to_type)
static std::string unique_anonymous_node_name(MaterialX::GraphElement *graph_element)
Map< NodeKey, const std::string > root_key_to_name_map_
Definition node_graph.h:63
NodeItem get_input(StringRef name) const
const ExportParams & export_params
Definition node_graph.h:31
Map< NodeKey, const std::string > & key_to_name_map_
Definition node_graph.h:64
NodeItem get_output(StringRef name) const
Set< std::string > used_node_names_
Definition node_graph.h:65
NodeGraph(const Depsgraph *depsgraph, const Material *material, const ExportParams &export_params, const MaterialX::DocumentPtr &document)
Definition node_graph.cc:52
MaterialX::GraphElement * graph_element_
Definition node_graph.h:62