Skip to content

Commit 86f6c0f

Browse files
committed
fix: group logic better accounts for dependencies
1 parent 8b5e4fe commit 86f6c0f

File tree

4 files changed

+178
-110
lines changed

4 files changed

+178
-110
lines changed

compositor/operator.py

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,31 +52,25 @@ def _create_scene(self, indent: str):
5252
self._write(f"{indent}{SCENE_VAR}.use_fake_user = True\n")
5353
self._write(f"{indent}bpy.context.window.scene = {SCENE_VAR}\n")
5454

55-
def _initialize_compositor_node_tree(self, outer, nt_var, level, inner, nt_name):
56-
#initialize node group
57-
self._write(f"{outer}#initialize {nt_var} node group\n")
58-
self._write(f"{outer}def {nt_var}_node_group():\n")
59-
60-
if self._is_outermost_node_group(level): #outermost node group
61-
self._write(f"{inner}{nt_var} = {SCENE_VAR}.node_tree\n")
55+
def _initialize_compositor_node_tree(self, outer, ntp_nt, nt_name):
56+
#initialize node group
57+
self._write(f"{outer}#initialize {nt_name} node group\n")
58+
self._write(f"{outer}def {ntp_nt.var}_node_group():\n")
59+
60+
inner = f"{outer}\t"
61+
if ntp_nt.node_tree == self._base_node_tree:
62+
self._write(f"{inner}{ntp_nt.var} = {SCENE_VAR}.node_tree\n")
6263
self._write(f"{inner}#start with a clean node tree\n")
63-
self._write(f"{inner}for node in {nt_var}.nodes:\n")
64-
self._write(f"{inner}\t{nt_var}.nodes.remove(node)\n")
64+
self._write(f"{inner}for node in {ntp_nt.var}.nodes:\n")
65+
self._write(f"{inner}\t{ntp_nt.var}.nodes.remove(node)\n")
6566
else:
66-
self._write((f"{inner}{nt_var}"
67+
self._write((f"{inner}{ntp_nt.var}"
6768
f"= bpy.data.node_groups.new("
6869
f"type = \'CompositorNodeTree\', "
6970
f"name = {str_to_py_str(nt_name)})\n"))
7071
self._write("\n")
7172

72-
def _process_node(self, node: Node, ntp_nt: NTP_NodeTree, inner: str, level: int):
73-
if node.bl_idname == 'CompositorNodeGroup':
74-
node_nt = node.node_tree
75-
if node_nt is not None and node_nt not in self._node_trees:
76-
self._process_comp_node_group(node_nt, level + 1, self._node_vars,
77-
self._used_vars)
78-
self._node_trees.add(node_nt)
79-
73+
def _process_node(self, node: Node, ntp_nt: NTP_NodeTree, inner: str):
8074
node_var: str = self._create_node(node, inner, ntp_nt.var)
8175

8276
if node.bl_idname == 'CompositorNodeColorBalance':
@@ -98,17 +92,14 @@ def _process_node(self, node: Node, ntp_nt: NTP_NodeTree, inner: str, level: int
9892
self._hide_hidden_sockets(node, inner, node_var)
9993

10094
if node.bl_idname == 'CompositorNodeGroup':
101-
if node.node_tree is not None:
102-
self._write((f"{inner}{node_var}.node_tree = "
103-
f"bpy.data.node_groups"
104-
f"[\"{node.node_tree.name}\"]\n"))
105-
elif node.bl_idname == 'NodeGroupInput' and not inputs_set:
95+
self._process_group_node_tree(node, node_var, inner)
96+
elif node.bl_idname == 'NodeGroupInput' and not ntp_nt.inputs_set:
10697
self._group_io_settings(node, inner, "input", ntp_nt)
107-
inputs_set = True
98+
ntp_nt.inputs_set = True
10899

109-
elif node.bl_idname == 'NodeGroupOutput' and not outputs_set:
100+
elif node.bl_idname == 'NodeGroupOutput' and not ntp_nt.outputs_set:
110101
self._group_io_settings(node, inner, "output", ntp_nt)
111-
outputs_set = True
102+
ntp_nt.outputs_set = True
112103

113104
self._set_socket_defaults(node, node_var, inner)
114105

@@ -121,7 +112,7 @@ def _process_node_tree(self, node_tree, level):
121112
level (int): number of tabs to use for each line
122113
123114
"""
124-
if self._is_outermost_node_group(level):
115+
if node_tree == self._base_node_tree:
125116
nt_var = self._create_var(self.compositor_name)
126117
nt_name = self.compositor_name
127118
else:
@@ -130,32 +121,34 @@ def _process_node_tree(self, node_tree, level):
130121

131122
outer, inner = make_indents(level)
132123

133-
self._initialize_compositor_node_tree(outer, nt_var, level, inner, nt_name)
134-
135124
ntp_nt = NTP_NodeTree(node_tree, nt_var)
125+
self._initialize_compositor_node_tree(outer, ntp_nt, nt_name)
136126

137127
#initialize nodes
138128
self._write(f"{inner}#initialize {nt_var} nodes\n")
139129

140130
for node in node_tree.nodes:
141-
self._process_node(node, ntp_nt, inner, level)
131+
self._process_node(node, ntp_nt, inner)
142132

143133
self._set_parents(node_tree, inner)
144134
self._set_locations(node_tree, inner)
145135
self._set_dimensions(node_tree, inner)
146136

147137
self._init_links(node_tree, inner, nt_var)
148138

149-
self._write(f"\n{outer}{nt_var}_node_group()\n\n")
139+
self._write(f"{inner}return {nt_var}\n")
140+
141+
self._write(f"\n{outer}{nt_var} = {nt_var}_node_group()\n\n")
142+
self._node_trees[node_tree] = nt_var
150143

151144
def execute(self, context):
152145
#find node group to replicate
153146
if self.is_scene:
154-
nt = bpy.data.scenes[self.compositor_name].node_tree
147+
self._base_node_tree = bpy.data.scenes[self.compositor_name].node_tree
155148
else:
156-
nt = bpy.data.node_groups[self.compositor_name]
149+
self._base_node_tree = bpy.data.node_groups[self.compositor_name]
157150

158-
if nt is None:
151+
if self._base_node_tree is None:
159152
#shouldn't happen
160153
self.report({'ERROR'},("NodeToPython: This doesn't seem to be a "
161154
"valid compositor node tree. Is Use Nodes "
@@ -187,8 +180,12 @@ def execute(self, context):
187180
if self.mode == 'ADDON':
188181
level = 2
189182
else:
190-
level = 0
191-
self._process_node_tree(nt, level)
183+
level = 0
184+
185+
node_trees_to_process = self._topological_sort(self._base_node_tree)
186+
187+
for node_tree in node_trees_to_process:
188+
self._process_node_tree(node_tree, level)
192189

193190
if self.mode == 'ADDON':
194191
self._write("\t\treturn {'FINISHED'}\n\n")

geometry/operator.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ def _process_zone_output_node(self, node: GeometryNode, inner: str,
6565
f"{attr_domain}\n"))
6666

6767
def _process_node(self, node: Node, ntp_node_tree: NTP_GeoNodeTree,
68-
inner: str, level: int) -> None:
68+
inner: str) -> None:
6969
#create node
7070
node_var: str = self._create_node(node, inner, ntp_node_tree.var)
7171
self._set_settings_defaults(node, inner, node_var)
7272
if node.bl_idname == 'GeometryNodeGroup':
73-
self._process_group_node_tree(node, node_var, level, inner)
73+
self._process_group_node_tree(node, node_var, inner)
7474

7575
elif node.bl_idname == 'NodeGroupInput' and not ntp_node_tree.inputs_set:
7676
self._group_io_settings(node, inner, "input", ntp_node_tree)
@@ -169,7 +169,7 @@ def _process_node_tree(self, node_tree: GeometryNodeTree,
169169
ntp_nt = NTP_GeoNodeTree(node_tree, nt_var)
170170

171171
for node in node_tree.nodes:
172-
self._process_node(node, ntp_nt, inner, level)
172+
self._process_node(node, ntp_nt, inner)
173173

174174
if bpy.app.version >= (3, 6, 0):
175175
self._process_zones(ntp_nt.sim_inputs, inner)
@@ -188,7 +188,8 @@ def _process_node_tree(self, node_tree: GeometryNodeTree,
188188

189189
#create node group
190190
self._write(f"\n{outer}{nt_var} = {nt_var}_node_group()\n\n")
191-
return self._used_vars
191+
192+
self._node_trees[node_tree] = nt_var
192193

193194

194195
def _apply_modifier(self, nt: GeometryNodeTree, nt_var: str):
@@ -226,7 +227,11 @@ def execute(self, context):
226227
level = 2
227228
else:
228229
level = 0
229-
self._process_node_tree(nt, level)
230+
231+
node_trees_to_process = self._topological_sort(nt)
232+
233+
for node_tree in node_trees_to_process:
234+
self._process_node_tree(node_tree, level)
230235

231236
if self.mode == 'ADDON':
232237
self._apply_modifier(nt, nt_var)

material/operator.py

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,46 @@ def _create_material(self, indent: str):
2828
f"name = {str_to_py_str(self.material_name)})\n"))
2929
self._write(f"{indent}{MAT_VAR}.use_nodes = True\n")
3030

31-
def _initialize_shader_node_tree(self, outer, nt_var, level, inner, nt_name):
32-
#initialize node group
33-
self._write(f"{outer}#initialize {nt_var} node group\n")
34-
self._write(f"{outer}def {nt_var}_node_group():\n")
31+
def _initialize_shader_node_tree(self, outer: str, ntp_node_tree: NTP_NodeTree, nt_name: str) -> None:
32+
"""
33+
Initialize the shader node group
34+
35+
Parameters:
36+
outer (str): indentation level
37+
ntp_node_tree (NTP_NodeTree): node tree to be generated and
38+
variable to use
39+
nt_name (str): name to use for the node tree
40+
"""
41+
self._write(f"{outer}#initialize {nt_name} node group\n")
42+
self._write(f"{outer}def {ntp_node_tree.var}_node_group():\n")
3543

36-
if self._is_outermost_node_group(level):
37-
self._write(f"{inner}{nt_var} = {MAT_VAR}.node_tree\n")
44+
inner = f"{outer}\t"
45+
if ntp_node_tree.node_tree == self._base_node_tree:
46+
self._write(f"{inner}{ntp_node_tree.var} = {MAT_VAR}.node_tree\n")
3847
self._write(f"{inner}#start with a clean node tree\n")
39-
self._write(f"{inner}for node in {nt_var}.nodes:\n")
40-
self._write(f"{inner}\t{nt_var}.nodes.remove(node)\n")
48+
self._write(f"{inner}for node in {ntp_node_tree.var}.nodes:\n")
49+
self._write(f"{inner}\t{ntp_node_tree.var}.nodes.remove(node)\n")
4150
else:
42-
self._write((f"{inner}{nt_var} = bpy.data.node_groups.new("
51+
self._write((f"{inner}{ntp_node_tree.var} = bpy.data.node_groups.new("
4352
f"type = \'ShaderNodeTree\', "
4453
f"name = {str_to_py_str(nt_name)})\n"))
4554
self._write("\n")
4655

47-
def _process_node(self, node: Node, ntp_node_tree: NTP_NodeTree, inner: str, level: int) -> None:
48-
#create node
56+
def _process_node(self, node: Node, ntp_node_tree: NTP_NodeTree, inner: str) -> None:
57+
"""
58+
Creates a node and sets settings, inputs, outputs, and cosmetics
59+
60+
Parameters:
61+
node (Node): node to process
62+
ntp_node_tree (NTP_NodeTree): node tree the node belongs to, and
63+
variable to use
64+
inner
65+
"""
4966
node_var: str = self._create_node(node, inner, ntp_node_tree.var)
5067
self._set_settings_defaults(node, inner, node_var)
5168

5269
if node.bl_idname == 'ShaderNodeGroup':
53-
self._process_group_node_tree(node, node_var, level, inner)
70+
self._process_group_node_tree(node, node_var, inner)
5471
elif node.bl_idname == 'NodeGroupInput' and not ntp_node_tree.inputs_set:
5572
self._group_io_settings(node, inner, "input", ntp_node_tree)
5673
ntp_node_tree.inputs_set = True
@@ -72,7 +89,7 @@ def _process_node_tree(self, node_tree: ShaderNodeTree, level: int) -> None:
7289
node groups within node groups and script/add-on differences
7390
"""
7491

75-
if self._is_outermost_node_group(level):
92+
if node_tree == self._base_node_tree:
7693
nt_var = self._create_var(self.material_name)
7794
nt_name = self.material_name #TODO: this is probably overcomplicating things if we move to a harder material vs shader node tree difference
7895
else:
@@ -81,15 +98,15 @@ def _process_node_tree(self, node_tree: ShaderNodeTree, level: int) -> None:
8198

8299
outer, inner = make_indents(level)
83100

84-
self._initialize_shader_node_tree(outer, nt_var, level, inner, nt_name)
85-
86101
ntp_nt = NTP_NodeTree(node_tree, nt_var)
87102

103+
self._initialize_shader_node_tree(outer, ntp_nt, nt_name)
104+
88105
#initialize nodes
89106
self._write(f"{inner}#initialize {nt_var} nodes\n")
90107

91108
for node in node_tree.nodes:
92-
self._process_node(node, ntp_nt, inner, level)
109+
self._process_node(node, ntp_nt, inner)
93110

94111
self._set_parents(node_tree, inner)
95112
self._set_locations(node_tree, inner)
@@ -99,12 +116,15 @@ def _process_node_tree(self, node_tree: ShaderNodeTree, level: int) -> None:
99116

100117
self._write(f"{inner}return {nt_var}\n")
101118

102-
self._write(f"\n{outer}{nt_var}_node_group()\n\n")
119+
self._write(f"\n{outer}{nt_var} = {nt_var}_node_group()\n\n")
120+
121+
self._node_trees[node_tree] = nt_var
122+
103123

104124
def execute(self, context):
105125
#find node group to replicate
106-
nt = bpy.data.materials[self.material_name].node_tree
107-
if nt is None:
126+
self._base_node_tree = bpy.data.materials[self.material_name].node_tree
127+
if self._base_node_tree is None:
108128
self.report({'ERROR'}, ("NodeToPython: This doesn't seem to be a "
109129
"valid material. Is Use Nodes selected?"))
110130
return {'CANCELLED'}
@@ -130,12 +150,15 @@ def execute(self, context):
130150
elif self.mode == 'SCRIPT':
131151
self._create_material("")
132152

133-
134153
if self.mode == 'ADDON':
135154
level = 2
136155
else:
137156
level = 0
138-
self._process_node_tree(nt, level)
157+
158+
node_trees_to_process = self._topological_sort(self._base_node_tree)
159+
160+
for node_tree in node_trees_to_process:
161+
self._process_node_tree(node_tree, level)
139162

140163
if self.mode == 'ADDON':
141164
self._write("\t\treturn {'FINISHED'}\n\n")

0 commit comments

Comments
 (0)