1
2 import nuke, os, re, sys, math, time
3 from nukescripts import execute_panel
4 from nukescripts import panels
5
8 panels.PythonPanel.__init__( self, "Precomp Nodes", "uk.co.thefoundry.PrecompOptionsDialog" )
9 self.scriptPath = nuke.File_Knob( "script", "Precomp script path " )
10 self.renderPath = nuke.File_Knob( "render", "Precomp render path " )
11 self.channels = nuke.Channel_Knob( "channels", "Channels " )
12 self.origNodes = nuke.Enumeration_Knob( "orig", "Original nodes ", ["add backdrop", "delete", "no change" ] )
13 self.addKnob ( self.scriptPath )
14 self.addKnob ( self.renderPath )
15 self.addKnob ( self.channels )
16 self.addKnob ( self.origNodes )
17
18 self.channels.setValue('all')
19
20 defaultDir = nuke.Root()['name'].value()
21 if defaultDir and defaultDir != "":
22 defaultDir = os.path.dirname( defaultDir )
23 if not defaultDir.endswith("/"):
24 defaultDir += "/"
25 else:
26 defaultDir = ""
27
28 basename = findNextName("Precomp")
29 self.scriptPath.setValue( defaultDir + basename + "_v01.nk" )
30 self.renderPath.setValue( defaultDir + basename + ".####.exr" )
31 self.setMinimumSize( 420, 50 )
32
35 self.scriptPath = ""
36 self.renderPath = ""
37 self.channels = ""
38 self.addBackdrop = False
39 self.delete = False
40
42 p = PrecompOptionsDialog()
43 result = p.showModalDialog()
44 if result:
45 self.scriptPath = p.scriptPath.value()
46 self.renderPath = p.renderPath.value()
47 self.channels = p.channels.value()
48 if p.origNodes.value() == "delete":
49 self.delete = True
50 elif p.origNodes.value() == "add backdrop":
51 self.addBackdrop = True
52
53 if nuke.env['nc']:
54 nukeExt = ".nknc"
55 if nuke.env['indie']:
56 nukeExt = ".nkind"
57 else:
58 nukeExt = ".nk"
59
60 (root, ext) = os.path.splitext(self.scriptPath)
61 if not ext:
62 self.scriptPath += nukeExt
63 elif ext == ".nk" and ext != nukeExt:
64 self.scriptPath = self.scriptPath[0:-3] + nukeExt
65
66 (root,ext) = os.path.splitext(self.renderPath)
67 if not ext:
68 self.renderPath += ".exr"
69
70 if os.path.exists(self.scriptPath):
71 if not nuke.ask("Overwrite existing " + self.scriptPath + " ?"):
72 return False
73 return True
74 else:
75 return False
76
81
98
105
129
131
132 nodes = nuke.selectedNodes()
133 if len(nodes) == 0:
134 g = nuke.createNode( "Precomp" )
135 return
136
137 options = PrecompOptions()
138
139 if not options.askUserForOptions():
140 return False
141
142 sel = nodes[0]
143
144
145 if len( nodes ) == 1:
146 upstreamNodes = nuke.dependencies( nodes )
147 while len ( upstreamNodes ) != 0:
148 nodes += upstreamNodes
149 upstreamNodes = nuke.dependencies( upstreamNodes )
150
151 left = right = nodes[0].xpos()
152 top = bottom = nodes[0].ypos()
153
154 nodeSize = 100
155 titleHeight = 50
156
157 inputs = []
158
159 for n in nodes:
160 n["selected"].setValue ( True )
161 if n.xpos() < left:
162 left = n.xpos()
163
164 if n.xpos() > right:
165 right = n.xpos()
166
167 if n.ypos() < top:
168 top = n.ypos()
169
170 if n.ypos() > bottom:
171 bottom = n.ypos()
172
173 for i in range( 0, n.inputs() ):
174 if not n.input(i):
175 continue
176
177 if not n.input(i) in nodes:
178 inputs.append( n.input(i) )
179
180
181 inputDeps = []
182 expressionDeps = []
183
184 for n in nodes:
185 for d in nuke.dependentNodes( nuke.INPUTS, [n]):
186 if d not in nodes:
187 if d.Class() != 'Viewer':
188 inputIndices = [i for i in range(d.inputs()) if d.input(i) == n]
189 inputDeps.append( (d, inputIndices) )
190
191 for d in nuke.dependencies( [n], nuke.EXPRESSIONS ):
192 if d not in nodes:
193 expressionDeps.append( d )
194
195 if len(inputDeps) > 1:
196 nuke.message( "You cannot precomp the selected nodes because there are multiple outputs." )
197 return
198
199 addLinkedExpressionNodes = False
200 if len(expressionDeps) > 0:
201 addLinkedExpressionNodes = nuke.ask( "Warning: The selected nodes have expressions to nodes outside the precomp. Do you want to copy these nodes to the precomp?" )
202
203
204 if len( nodes ) == 1 and nodes[0].Class() == "Group":
205 group = nodes[0]
206 else:
207 group = nuke.makeGroup( False )
208
209 with group:
210 outputInputs = []
211 output = group.output()
212 for i in range(0, output.inputs()):
213 outputInputs.append( output.input(i) )
214
215
216 outInp = output.input(0)
217 if outInp is None or outInp.Class() != "Write":
218 w = nuke.createNode( "Write", inpanel = False)
219 w.setInput( 0, None )
220 else:
221 w = outInp
222
223 for i in range(0, len(outputInputs) ):
224 w.setInput( i, outputInputs[i] )
225 output.setInput(i, None )
226
227 output.setInput(0, w )
228
229 w.knob("file").setValue( options.renderPath )
230 type = os.path.splitext( options.renderPath)[1][1:].lower()
231 w.knob("file_type").setValue( type )
232 w.knob("channels").setValue( options.channels )
233
234 for n in nuke.allNodes():
235 n['selected'].setValue( False )
236
237 if addLinkedExpressionNodes:
238 for n in nuke.allNodes():
239 n['selected'].setValue( False )
240
241 for n in expressionDeps:
242 n['selected'].setValue( True )
243
244 nuke.nodeCopy ( '%clipboard%' )
245
246 with group:
247 nuke.nodePaste( '%clipboard%' )
248
249 writeOk = True
250 with group:
251 try:
252 nuke.tcl("export_as_precomp", options.scriptPath)
253 except:
254 nuke.message( "Could not write precomp script, permission denied, please specify a different \'script path\' and try again.")
255 writeOk = False
256
257 for n in nuke.selectedNodes():
258 n['selected'].setValue( False )
259
260 if group != nodes[0]:
261 group['selected'].setValue( False )
262 nuke.delete( group )
263
264 if not writeOk:
265 for n in nuke.selectedNodes():
266 n['selected'].setValue( False )
267
268 for n in nodes:
269 n['selected'].setValue( True )
270
271 return
272
273
274 g = nuke.createNode( "Precomp" )
275 g[ "file" ].setValue( options.scriptPath )
276
277
278
279 for d in inputDeps:
280 node = d[0]
281 for inp in d[1]:
282
283 node.setInput(inp, g)
284
285
286 for i in range(0, len(inputs)):
287
288 g.setInput(i, inputs[i] )
289
290 pad = 5
291
292 if options.addBackdrop:
293 b = nuke.createNode( "BackdropNode", inpanel = False )
294 width = int(math.fabs(right - left)) + (pad * 2) + nodeSize
295 height = int(math.fabs(bottom - top)) + ( pad * 2 ) + nodeSize + titleHeight
296 b['label'].setValue( os.path.basename( options.scriptPath ) )
297 b['note_font_size'].setValue( 18 )
298 b.setXYpos( left - pad * 2, top - ( pad * 2) - titleHeight )
299 b.knob( "bdwidth" ).setValue( width )
300 b.knob( "bdheight").setValue( height )
301 b.knob( "z_order" ).setValue( 0 )
302 b['selected'].setValue(False)
303 g.setXYpos( b.xpos() + width/2 - nodeSize/2, b.ypos() + height + pad * 2 )
304 elif options.delete:
305 for n in nodes:
306 nuke.delete( n )
307
308 if len(inputs) > 0:
309 nuke.message( "Warning: The precomp script requires inputs and may not render the same independent of its parent script." )
310
311 return group
312