11import bpy
22
3- from bpy .types import Node
3+ from bpy .types import Node , CompositorNodeColorBalance , CompositorNodeTree
44
55from ..ntp_operator import NTP_Operator
66from ..ntp_node_tree import NTP_NodeTree
@@ -37,125 +37,139 @@ def __init__(self):
3737
3838 def _create_scene (self , indent : str ):
3939 #TODO: wrap in more general unique name util function
40- self ._write (f"{ indent } # Generate unique scene name\n " )
41- self ._write (f"{ indent } { BASE_NAME_VAR } = { str_to_py_str (self .compositor_name )} \n " )
42- self ._write (f"{ indent } { END_NAME_VAR } = { BASE_NAME_VAR } \n " )
43- self ._write (f"{ indent } if bpy.data.scenes.get({ END_NAME_VAR } ) != None:\n " )
44- self ._write (f"{ indent } \t i = 1\n " )
45- self ._write (f"{ indent } \t { END_NAME_VAR } = { BASE_NAME_VAR } + f\" .{{i:03d}}\" \n " )
46- self ._write (f"{ indent } \t while bpy.data.scenes.get({ END_NAME_VAR } ) != None:\n " )
47- self ._write (f"{ indent } \t \t { END_NAME_VAR } = { BASE_NAME_VAR } + f\" .{{i:03d}}\" \n " )
48- self ._write (f"{ indent } \t \t i += 1\n \n " )
49-
50- self ._write (f"{ indent } { SCENE_VAR } = bpy.context.window.scene.copy()\n \n " )
51- self ._write (f"{ indent } { SCENE_VAR } .name = { END_NAME_VAR } \n " )
52- self ._write (f"{ indent } { SCENE_VAR } .use_fake_user = True\n " )
53- self ._write (f"{ indent } bpy.context.window.scene = { SCENE_VAR } \n " )
54-
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 " )
62- 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 " )
40+ self ._write (f"# Generate unique scene name" , indent )
41+ self ._write (f"{ BASE_NAME_VAR } = { str_to_py_str (self .compositor_name )} " ,
42+ indent )
43+ self ._write (f"{ END_NAME_VAR } = { BASE_NAME_VAR } " , indent )
44+ self ._write (f"if bpy.data.scenes.get({ END_NAME_VAR } ) != None:" , indent )
45+
46+ indent2 = f"{ indent } \t "
47+ self ._write (f"i = 1" , indent2 )
48+ self ._write (f"{ END_NAME_VAR } = { BASE_NAME_VAR } + f\" .{{i:03d}}\" " ,
49+ indent2 )
50+ self ._write (f"while bpy.data.scenes.get({ END_NAME_VAR } ) != None:" ,
51+ indent2 )
52+
53+ indent3 = f"{ indent } \t \t "
54+ self ._write (f"{ END_NAME_VAR } = { BASE_NAME_VAR } + f\" .{{i:03d}}\" " , indent3 )
55+ self ._write (f"i += 1\n " , indent3 )
56+
57+ self ._write (f"{ SCENE_VAR } = bpy.context.window.scene.copy()\n " , indent )
58+ self ._write (f"{ SCENE_VAR } .name = { END_NAME_VAR } " , indent )
59+ self ._write (f"{ SCENE_VAR } .use_fake_user = True" , indent )
60+ self ._write (f"bpy.context.window.scene = { SCENE_VAR } " , indent )
61+
62+ def _initialize_compositor_node_tree (self , ntp_nt , nt_name ):
63+ #initialize node group
64+ self ._write (f"#initialize { nt_name } node group" , self ._outer )
65+ self ._write (f"def { ntp_nt .var } _node_group():" , self ._outer )
66+
67+ if ntp_nt .node_tree == self ._base_node_tree :
68+ self ._write (f"{ ntp_nt .var } = { SCENE_VAR } .node_tree" )
69+ self ._write (f"#start with a clean node tree" )
70+ self ._write (f"for node in { ntp_nt .var } .nodes:" )
71+ self ._write (f"\t { ntp_nt .var } .nodes.remove(node)" )
6572 else :
66- self ._write ((f"{ inner } { nt_var } "
67- f"= bpy.data.node_groups.new("
73+ self ._write ((f"{ ntp_nt .var } = bpy.data.node_groups.new("
6874 f"type = \' CompositorNodeTree\' , "
69- f"name = { str_to_py_str (nt_name )} )\n " ))
70- self ._write ("\n " )
71-
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-
80- node_var : str = self ._create_node (node , inner , ntp_nt .var )
75+ f"name = { str_to_py_str (nt_name )} )" ))
76+ self ._write ("" )
77+
78+ def _set_color_balance_settings (self , node : CompositorNodeColorBalance
79+ ) -> None :
80+ """
81+ Sets the color balance settings so we only set the active variables,
82+ preventing conflict
83+
84+ node (CompositorNodeColorBalance): the color balance node
85+ """
86+ if node .correction_method == 'LIFT_GAMMA_GAIN' :
87+ lst = [("correction_method" , ST .ENUM ),
88+ ("gain" , ST .COLOR ),
89+ ("gamma" , ST .COLOR ),
90+ ("lift" , ST .COLOR )]
91+ else :
92+ lst = [("correction_method" , ST .ENUM ),
93+ ("offset" , ST .COLOR ),
94+ ("offset_basis" , ST .FLOAT ),
95+ ("power" , ST .COLOR ),
96+ ("slope" , ST .COLOR )]
97+
98+ self ._settings ['CompositorNodeColorBalance' ] = lst
99+
100+ def _process_node (self , node : Node , ntp_nt : NTP_NodeTree ):
101+ """
102+ Create node and set settings, defaults, and cosmetics
103+
104+ Parameters:
105+ node (Node): node to process
106+ ntp_nt (NTP_NodeTree): the node tree that node belongs to
107+ """
108+ node_var : str = self ._create_node (node , ntp_nt .var )
81109
82110 if node .bl_idname == 'CompositorNodeColorBalance' :
83- if node .correction_method == 'LIFT_GAMMA_GAIN' :
84- lst = [("correction_method" , ST .ENUM ),
85- ("gain" , ST .COLOR ),
86- ("gamma" , ST .COLOR ),
87- ("lift" , ST .COLOR )]
88- else :
89- lst = [("correction_method" , ST .ENUM ),
90- ("offset" , ST .COLOR ),
91- ("offset_basis" , ST .FLOAT ),
92- ("power" , ST .COLOR ),
93- ("slope" , ST .COLOR )]
94-
95- self ._settings ['CompositorNodeColorBalance' ] = lst
96-
97- self ._set_settings_defaults (node , inner , node_var )
98- self ._hide_hidden_sockets (node , inner , node_var )
99-
100- 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 :
106- self ._group_io_settings (node , inner , "input" , ntp_nt )
107- inputs_set = True
108-
109- elif node .bl_idname == 'NodeGroupOutput' and not outputs_set :
110- self ._group_io_settings (node , inner , "output" , ntp_nt )
111- outputs_set = True
112-
113- self ._set_socket_defaults (node , node_var , inner )
111+ self ._set_color_balance_settings (node )
112+
113+ self ._set_settings_defaults (node )
114+ self ._hide_hidden_sockets (node )
115+
116+ if bpy .app .version < (4 , 0 , 0 ):
117+ if node .bl_idname == 'NodeGroupInput' and not ntp_nt .inputs_set :
118+ self ._group_io_settings (node , "input" , ntp_nt )
119+ ntp_nt .inputs_set = True
120+
121+ elif node .bl_idname == 'NodeGroupOutput' and not ntp_nt .outputs_set :
122+ self ._group_io_settings (node , "output" , ntp_nt )
123+ ntp_nt .outputs_set = True
124+
125+ self ._set_socket_defaults (node )
114126
115- def _process_node_tree (self , node_tree , level ):
127+ def _process_node_tree (self , node_tree : CompositorNodeTree ):
116128 """
117129 Generates a Python function to recreate a compositor node tree
118130
119131 Parameters:
120- node_tree (NodeTree): node tree to be recreated
121- level (int): number of tabs to use for each line
122-
132+ node_tree (CompositorNodeTree): node tree to be recreated
123133 """
124- if self ._is_outermost_node_group ( level ) :
134+ if node_tree == self ._base_node_tree :
125135 nt_var = self ._create_var (self .compositor_name )
126136 nt_name = self .compositor_name
127137 else :
128138 nt_var = self ._create_var (node_tree .name )
129139 nt_name = node_tree .name
130140
131- outer , inner = make_indents ( level )
141+ self . _node_tree_vars [ node_tree ] = nt_var
132142
133- self ._initialize_compositor_node_tree (outer , nt_var , level , inner , nt_name )
134-
135143 ntp_nt = NTP_NodeTree (node_tree , nt_var )
144+ self ._initialize_compositor_node_tree (ntp_nt , nt_name )
145+
146+ if bpy .app .version >= (4 , 0 , 0 ):
147+ self ._tree_interface_settings (ntp_nt )
136148
137149 #initialize nodes
138- self ._write (f"{ inner } #initialize { nt_var } nodes\n " )
150+ self ._write (f"#initialize { nt_var } nodes" )
139151
140152 for node in node_tree .nodes :
141- self ._process_node (node , ntp_nt , inner , level )
153+ self ._process_node (node , ntp_nt )
142154
143- self ._set_parents (node_tree , inner )
144- self ._set_locations (node_tree , inner )
145- self ._set_dimensions (node_tree , inner )
155+ self ._set_parents (node_tree )
156+ self ._set_locations (node_tree )
157+ self ._set_dimensions (node_tree )
146158
147- self ._init_links (node_tree , inner , nt_var )
159+ self ._init_links (node_tree )
148160
149- self ._write (f"\n { outer } { nt_var } _node_group()\n \n " )
161+ self ._write (f"return { nt_var } \n " )
162+
163+ self ._write (f"{ nt_var } = { nt_var } _node_group()\n " , self ._outer )
150164
151165 def execute (self , context ):
152166 #find node group to replicate
153167 if self .is_scene :
154- nt = bpy .data .scenes [self .compositor_name ].node_tree
168+ self . _base_node_tree = bpy .data .scenes [self .compositor_name ].node_tree
155169 else :
156- nt = bpy .data .node_groups [self .compositor_name ]
170+ self . _base_node_tree = bpy .data .node_groups [self .compositor_name ]
157171
158- if nt is None :
172+ if self . _base_node_tree is None :
159173 #shouldn't happen
160174 self .report ({'ERROR' },("NodeToPython: This doesn't seem to be a "
161175 "valid compositor node tree. Is Use Nodes "
@@ -166,6 +180,9 @@ def execute(self, context):
166180 comp_var = clean_string (self .compositor_name )
167181
168182 if self .mode == 'ADDON' :
183+ self ._outer = "\t \t "
184+ self ._inner = "\t \t \t "
185+
169186 self ._setup_addon_directories (context , comp_var )
170187
171188 self ._file = open (f"{ self ._addon_dir } /__init__.py" , "w" )
@@ -174,7 +191,7 @@ def execute(self, context):
174191 self ._class_name = clean_string (self .compositor_name , lower = False )
175192 self ._init_operator (comp_var , self .compositor_name )
176193
177- self ._write ("\t def execute(self, context):\n " )
194+ self ._write ("def execute(self, context):" , " \t " )
178195 else :
179196 self ._file = StringIO ("" )
180197
@@ -183,15 +200,14 @@ def execute(self, context):
183200 self ._create_scene ("\t \t " )
184201 elif self .mode == 'SCRIPT' :
185202 self ._create_scene ("" )
186-
187- if self .mode == 'ADDON' :
188- level = 2
189- else :
190- level = 0
191- self ._process_node_tree (nt , level )
203+
204+ node_trees_to_process = self ._topological_sort (self ._base_node_tree )
205+
206+ for node_tree in node_trees_to_process :
207+ self ._process_node_tree (node_tree )
192208
193209 if self .mode == 'ADDON' :
194- self ._write ("\t \t return {'FINISHED'}\n \n " )
210+ self ._write ("return {'FINISHED'}\n " , self . _outer )
195211
196212 self ._create_menu_func ()
197213 self ._create_register_func ()
0 commit comments