Package nukescripts :: Module precomp
[hide private]
[frames] | no frames]

Source Code for Module nukescripts.precomp

  1  # Copyright (c) 2009 The Foundry Visionmongers Ltd.  All Rights Reserved. 
  2  import nuke, os, re, sys, math, time 
  3  from nukescripts import execute_panel 
  4  from nukescripts import panels 
  5   
6 -class PrecompOptionsDialog( panels.PythonPanel ):
7 - def __init__( self ):
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
33 -class PrecompOptions:
34 - def __init__(self):
35 self.scriptPath = "" 36 self.renderPath = "" 37 self.channels = "" 38 self.addBackdrop = False 39 self.delete = False
40
41 - def askUserForOptions(self):
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
77 -def precomp_open(precomp):
78 precomp.executePythonCallback(nuke.PRECOMP_CALLBACK_OPENED) 79 nuke.Root().setModified( True ) 80 nuke.scriptOpen(precomp["file"].evaluate())
81
82 -def precomp_render(precomp):
83 reading = precomp["reading"].getValue() 84 precomp["reading"].setValue( False ) 85 try: 86 finalNode = None 87 if precomp['useOutput'].value() == True: 88 finalNode = nuke.toNode( precomp['output'].value() ) 89 else: 90 if precomp.output() and precomp.output().input(0): 91 finalNode = precomp.output().input(0) 92 execute_panel( [ finalNode ] ) 93 except RuntimeError, e: 94 if e.message[0:9] != "Cancelled": # TO DO: change this to an exception type 95 raise 96 return 97 precomp["reading"].setValue( True )
98
99 -def findNextName(name):
100 i = 1 101 while nuke.toNode ( name + str(i) ) != None: 102 i += 1 103 104 return name + str(i)
105
106 -def precomp_copyToGroup(precomp):
107 108 ## group context is set to precomp, so back up one level. 109 nuke.endGroup() 110 111 g = nuke.nodes.Group() 112 with precomp: 113 nuke.selectAll() 114 nuke.nodeCopy ( '%clipboard%' ) 115 116 with g: 117 nuke.nodePaste( '%clipboard%' ) 118 119 for k in ['label', 'icon', 'indicators', 'tile_color', 'disable']: 120 v = precomp[k].value() 121 if v: 122 g[k].setValue( v ) 123 124 for k in precomp.allKnobs(): 125 if isinstance( k, nuke.Link_Knob ): 126 lnk = nuke.Link_Knob( k.name() ) 127 lnk.setLink( k.getLink() ) 128 g.addKnob( lnk )
129
130 -def precomp_selected():
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 ## select upstream nodes 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 ## find all the dependent nodes 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 ## make group and export 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 ## insert write node or use existing one 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 ## reload saved out script 274 g = nuke.createNode( "Precomp" ) 275 g[ "file" ].setValue( options.scriptPath ) 276 277 #nuke.tprint( "Selected Node: " + sel.name() ) 278 279 for d in inputDeps: 280 node = d[0] 281 for inp in d[1]: 282 #nuke.tprint ( "Reconnecting dep " + node.name() + " input " + str(inp) ) 283 node.setInput(inp, g) 284 285 ## reconnect inputs, if any 286 for i in range(0, len(inputs)): 287 #nuke.tprint ( "Reconnecting input " + inputs[i].name() + " " + str(i) ) 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