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