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 else:
56 nukeExt = ".nk"
57
58 (root, ext) = os.path.splitext(self.scriptPath)
59 if not ext:
60 self.scriptPath += nukeExt
61 elif ext == ".nk" and ext != nukeExt:
62 self.scriptPath = self.scriptPath[0:-3] + nukeExt
63
64 (root,ext) = os.path.splitext(self.renderPath)
65 if not ext:
66 self.renderPath += ".exr"
67
68 if os.path.exists(self.scriptPath):
69 if not nuke.ask("Overwrite existing " + self.scriptPath + " ?"):
70 return False
71 return True
72 else:
73 return False
74
78
95
102
120
121
123
124 nodes = nuke.selectedNodes()
125 if len(nodes) == 0:
126 g = nuke.createNode( "Precomp" )
127 return
128
129 options = PrecompOptions()
130
131 if not options.askUserForOptions():
132 return False
133
134 sel = nodes[0]
135
136
137 if len( nodes ) == 1:
138 upstreamNodes = nuke.dependencies( nodes )
139 while len ( upstreamNodes ) != 0:
140 nodes += upstreamNodes
141 upstreamNodes = nuke.dependencies( upstreamNodes )
142
143 left = right = nodes[0].xpos()
144 top = bottom = nodes[0].ypos()
145
146 nodeSize = 100
147 titleHeight = 50
148
149 inputs = []
150
151 for n in nodes:
152 n["selected"].setValue ( True )
153 if n.xpos() < left:
154 left = n.xpos()
155
156 if n.xpos() > right:
157 right = n.xpos()
158
159 if n.ypos() < top:
160 top = n.ypos()
161
162 if n.ypos() > bottom:
163 bottom = n.ypos()
164
165 for i in range( 0, n.inputs() ):
166 if not n.input(i):
167 continue
168
169 if not n.input(i) in nodes:
170 inputs.append( n.input(i) )
171
172
173 inputDeps = []
174 expressionDeps = []
175
176 for n in nodes:
177 for d in nuke.dependentNodes( nuke.INPUTS, [n]):
178 if d not in nodes:
179 if d.Class() != 'Viewer':
180 inputIndices = [i for i in range(d.inputs()) if d.input(i) == n]
181 inputDeps.append( (d, inputIndices) )
182
183 for d in nuke.dependencies( [n], nuke.EXPRESSIONS ):
184 if d not in nodes:
185 expressionDeps.append( d )
186
187 if len(inputDeps) > 1:
188 nuke.message( "You cannot precomp the selected nodes because there are multiple outputs." )
189 return
190
191 addLinkedExpressionNodes = False
192 if len(expressionDeps) > 0:
193 addLinkedExpressionNodes = nuke.ask( "Warning: The selected nodes have expressions to nodes outside the precomp. Do you want to copy these nodes to the precomp?" )
194
195
196 if len( nodes ) == 1 and nodes[0].Class() == "Group":
197 group = nodes[0]
198 else:
199 group = nuke.makeGroup( False )
200
201 with group:
202 outputInputs = []
203 output = group.output()
204 for i in range(0, output.inputs()):
205 outputInputs.append( output.input(i) )
206
207
208 outInp = output.input(0)
209 if outInp is None or outInp.Class() != "Write":
210 w = nuke.createNode( "Write", inpanel = False)
211 w.setInput( 0, None )
212 else:
213 w = outInp
214
215 for i in range(0, len(outputInputs) ):
216 w.setInput( i, outputInputs[i] )
217 output.setInput(i, None )
218
219 output.setInput(0, w )
220
221 w.knob("file").setValue( options.renderPath )
222 type = os.path.splitext( options.renderPath)[1][1:].lower()
223 w.knob("file_type").setValue( type )
224 w.knob("channels").setValue( options.channels )
225
226 for n in nuke.allNodes():
227 n['selected'].setValue( False )
228
229 if addLinkedExpressionNodes:
230 for n in nuke.allNodes():
231 n['selected'].setValue( False )
232
233 for n in expressionDeps:
234 n['selected'].setValue( True )
235
236 nuke.nodeCopy ( '%clipboard%' )
237
238 with group:
239 nuke.nodePaste( '%clipboard%' )
240
241 writeOk = True
242 with group:
243 try:
244 nuke.tcl("export_as_precomp", options.scriptPath)
245 except:
246 nuke.message( "Could not write precomp script, permission denied, please specify a different \'script path\' and try again.")
247 writeOk = False
248
249 for n in nuke.selectedNodes():
250 n['selected'].setValue( False )
251
252 if group != nodes[0]:
253 group['selected'].setValue( False )
254 nuke.delete( group )
255
256 if not writeOk:
257 for n in nuke.selectedNodes():
258 n['selected'].setValue( False )
259
260 for n in nodes:
261 n['selected'].setValue( True )
262
263 return
264
265
266 g = nuke.createNode( "Precomp" )
267 g[ "file" ].setValue( options.scriptPath )
268
269
270
271 for d in inputDeps:
272 node = d[0]
273 for inp in d[1]:
274
275 node.setInput(inp, g)
276
277
278 for i in range(0, len(inputs)):
279
280 g.setInput(i, inputs[i] )
281
282 pad = 5
283
284 if options.addBackdrop:
285 b = nuke.createNode( "BackdropNode", inpanel = False )
286 width = int(math.fabs(right - left)) + (pad * 2) + nodeSize
287 height = int(math.fabs(bottom - top)) + ( pad * 2 ) + nodeSize + titleHeight
288 b['label'].setValue( os.path.basename( options.scriptPath ) )
289 b['note_font_size'].setValue( 18 )
290 b.setXYpos( left - pad * 2, top - ( pad * 2) - titleHeight )
291 b.knob( "bdwidth" ).setValue( width )
292 b.knob( "bdheight").setValue( height )
293 b.knob( "z_order" ).setValue( 0 )
294 b['selected'].setValue(False)
295 g.setXYpos( b.xpos() + width/2 - nodeSize/2, b.ypos() + height + pad * 2 )
296 elif options.delete:
297 for n in nodes:
298 nuke.delete( n )
299
300 if len(inputs) > 0:
301 nuke.message( "Warning: The precomp script requires inputs and may not render the same independent of its parent script." )
302
303 return group
304