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['ple']: 54 nukeExt = ".nkple" 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
75 -def precomp_open(precomp):
76 nuke.Root().setModified( True ) 77 nuke.scriptOpen(precomp["file"].evaluate())
78
79 -def precomp_render(precomp):
80 reading = precomp["reading"].getValue() 81 precomp["reading"].setValue( False ) 82 try: 83 finalNode = None 84 if precomp['useOutput'].value() == True: 85 finalNode = nuke.toNode( precomp['output'].value() ) 86 else: 87 if precomp.output() and precomp.output().input(0): 88 finalNode = precomp.output().input(0) 89 execute_panel( [ finalNode ] ) 90 except RuntimeError, e: 91 if e.message[0:9] != "Cancelled": # TO DO: change this to an exception type 92 raise 93 return 94 precomp["reading"].setValue( True )
95
96 -def findNextName(name):
97 i = 1 98 while nuke.toNode ( name + str(i) ) != None: 99 i += 1 100 101 return name + str(i)
102
103 -def precomp_copyToGroup(precomp):
104 105 ## group context is set to precomp, so back up one level. 106 nuke.endGroup() 107 108 g = nuke.nodes.Group() 109 with precomp: 110 nuke.selectAll() 111 nuke.nodeCopy ( '%clipboard%' ) 112 113 with g: 114 nuke.nodePaste( '%clipboard%' ) 115 116 for k in ['label', 'icon', 'indicators', 'tile_color', 'disable']: 117 v = precomp[k].getValue() 118 if v: 119 g[k].setValue( v )
120 121
122 -def precomp_selected():
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 ## select upstream nodes 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 ## find all the dependent nodes 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 ## make group and export 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 ## insert write node or use existing one 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 ## reload saved out script 266 g = nuke.createNode( "Precomp" ) 267 g[ "file" ].setValue( options.scriptPath ) 268 269 #nuke.tprint( "Selected Node: " + sel.name() ) 270 271 for d in inputDeps: 272 node = d[0] 273 for inp in d[1]: 274 #nuke.tprint ( "Reconnecting dep " + node.name() + " input " + str(inp) ) 275 node.setInput(inp, g) 276 277 ## reconnect inputs, if any 278 for i in range(0, len(inputs)): 279 #nuke.tprint ( "Reconnecting input " + inputs[i].name() + " " + str(i) ) 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['selected'].setValue(False) 294 g.setXYpos( b.xpos() + width/2 - nodeSize/2, b.ypos() + height + pad * 2 ) 295 elif options.delete: 296 for n in nodes: 297 nuke.delete( n ) 298 299 if len(inputs) > 0: 300 nuke.message( "Warning: The precomp script requires inputs and may not render the same independent of its parent script." ) 301 302 return group
303