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

Source Code for Module nukescripts.renderdialog

  1  # Copyright (c) 2010 The Foundry Visionmongers Ltd.  All Rights Reserved. 
  2  from __future__ import with_statement 
  3  import nuke 
  4  import nukescripts 
  5  import flipbooking 
  6  from nukescripts import pyAppUtils 
  7  import os 
  8  import string 
  9  import subprocess 
 10  import uuid 
 11  import re 
 12   
 13  from threading import Thread 
 14  from nukescripts import utils, sys, os, captureViewer 
 15   
 16  #import traceback 
 17   
 18  ############################################################################## 
 19  # Dialogs 
 20  ############################################################################## 
 21   
22 -class DialogState:
23 - def __init__(self):
24 self._state = {}
25
26 - def get(self, knob, defaultValue = None):
27 """Return the given knob's stored last state value. 28 If none exists, defaultValue is returned. 29 Values are stored in a dict referenced by knob name, so names must be unique!""" 30 return self.getValue(knob.name(), defaultValue)
31
32 - def save(self, knob):
33 """Store the knob's current value as the 'last state' for the next time the dialog is opened. 34 Values are stored in a dict referenced by knob name, so names must be unique!""" 35 self.saveValue(knob.name(), knob.value())
36
37 - def setKnob(self, knob, defaultValue = None):
38 """Convenience method for setting a value straight on a knob.""" 39 knob.setValue(self.get(knob, defaultValue))
40 - def saveValue(self, id, value):
41 """Stores the value with the given id.""" 42 self._state[id] = value
43 - def getValue(self, id, defaultValue = None):
44 """Recalls the value. If it was not set before, it will return the defaultValue.""" 45 return self._state.get(id, defaultValue)
46 47 _gRenderDialogState = DialogState() 48 _gFlipbookDialogState = DialogState() 49 _gViewerCaptureDialogState = DialogState() 50
51 -class ExecuteDialog(nukescripts.PythonPanel):
52 - def _titleString(self):
53 return "Execute"
54
55 - def _idString(self):
56 return "uk.co.thefoundry.ExecuteDialog"
57
58 - def _addPreKnobs(self):
59 """Add knobs that must appear before the render knobs.""" 60 return
61
62 - def _addPostKnobs(self):
63 """Add knobs that must appear after the render knobs.""" 64 return
65
66 - def _addTrailingKnobs(self):
67 """Add knobs that must appear at the very end.""" 68 return
69
70 - def _getDefaultViews(self):
71 oc = nuke.OutputContext() 72 allViews = [oc.viewname(i) for i in xrange(1, oc.viewcount())] 73 return " ".join(allViews)
74
75 - def _addViewKnob(self):
76 """Add knobs for view selection.""" 77 oc = nuke.OutputContext() 78 if (oc.viewcount() > 2): 79 self._viewSelection = nuke.MultiView_Knob("multi_view", "Views") 80 self._viewSelection.fromScript(self._state.get(self._viewSelection, self._getDefaultViews())) 81 self.addKnob(self._viewSelection) 82 self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
83
84 - def addKnob(self, knob):
85 """Add the knob and make sure it cannot be animated.""" 86 knob.setFlag(nuke.NO_ANIMATION | nuke.NO_MULTIVIEW) 87 super(ExecuteDialog, self).addKnob(knob)
88
89 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
90 self._state = dialogState 91 self._nodeSelection = nodeSelection 92 self._exceptOnError = exceptOnError 93 94 nukescripts.PythonPanel.__init__(self, self._titleString(), self._idString(), False) 95 96 self._viewers = {} 97 for n in nuke.allNodes("Viewer", groupContext): 98 self._viewers[n.name()] = n 99 self._specialRanges = ["input", "global", "custom"] 100 101 self._addPreKnobs() 102 103 # Frame range knobs 104 self._rangeEnum = nuke.Enumeration_Knob( "frame_range", "Frame range", self._specialRanges + self._viewers.keys() ) 105 self._state.setKnob(self._rangeEnum, "input") 106 self.addKnob( self._rangeEnum ) 107 self._frameRange = nuke.String_Knob( "frame_range_string", "") 108 self._frameRange.clearFlag(nuke.STARTLINE) 109 if self._rangeEnum.value() == "custom": 110 self._state.setKnob(self._frameRange, str(nuke.root().frameRange())) 111 else: 112 self._setFrameRangeFromSource(self._rangeEnum.value()) 113 114 self.addKnob(self._frameRange) 115 116 # Proxy 117 self._useProxy = nuke.Boolean_Knob("use_proxy", "Use proxy") 118 self._useProxy.setFlag(nuke.STARTLINE) 119 self._state.setKnob(self._useProxy, nuke.root().proxy()) 120 self.addKnob(self._useProxy) 121 122 self._addPostKnobs() 123 124 self._continueOnError = nuke.Boolean_Knob("continue", "Continue on error") 125 self._state.setKnob(self._continueOnError, True) 126 self._continueOnError.setFlag(nuke.STARTLINE) 127 self.addKnob(self._continueOnError) 128 129 self._addViewKnob() 130 131 self._addTrailingKnobs()
132
133 - def knobChanged( self, knob ):
134 self._state.save(knob) 135 if (knob == self._frameRange): 136 self._rangeEnum.setValue("custom") 137 self._state.save(self._rangeEnum) 138 if (knob == self._rangeEnum): 139 self._setFrameRangeFromSource(knob.value()) 140 self._state.save(self._frameRange)
141
142 - def _setFrameRangeFromSource(self, source):
143 if (source == "input"): 144 try: 145 activeInput = nuke.activeViewer().activeInput() 146 self._frameRange.setValue(str(nuke.activeViewer().node().input(activeInput).frameRange())) 147 except: 148 self._frameRange.setValue(str(nuke.root().frameRange())) 149 elif (source == "global"): 150 self._frameRange.setValue(str(nuke.root().frameRange())) 151 elif (source == "custom"): 152 pass 153 else: 154 self._frameRangeFromViewer(source);
155
156 - def _frameRangeFromViewer( self, viewer ):
157 """"Set the framerange knob to have the framerange from the given viewer.""" 158 viewerRange = str(self._viewers[viewer].knob("frame_range").value()) 159 if viewerRange == "": 160 viewerRange = str(self._viewers[viewer].playbackRange()) 161 self._frameRange.setValue(viewerRange)
162
163 - def _selectedViews(self):
164 try: 165 return self._viewSelection.value().split() 166 except AttributeError: 167 # If we didn't add the view selection knob, there should be just the one view. 168 return [nuke.OutputContext().viewname(1)]
169
170 - def addToPane(self):
172
173 - def run(self):
174 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(',')) 175 views = self._selectedViews() 176 rootProxyMode = nuke.root().proxy() 177 try: 178 nuke.Undo().disable() 179 nuke.root().setProxy(self._useProxy.value()) 180 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value()) 181 except RuntimeError, e: 182 if self._exceptOnError or e.args[0][0:9] != "Cancelled": # TO DO: change this to an exception type 183 raise 184 finally: 185 nuke.root().setProxy(rootProxyMode) 186 nuke.Undo().enable()
187
188 -class RenderDialog(ExecuteDialog):
189 - def _titleString(self):
190 return "Render"
191
192 - def _idString(self):
193 return "uk.co.thefoundry.RenderDialog"
194
195 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
196 ExecuteDialog.__init__(self, dialogState, groupContext, nodeSelection, exceptOnError)
197
198 - def _addPostKnobs(self):
199 # Background render stuff 200 self._bgRender = nuke.Boolean_Knob("bg_render", "Render in background") 201 self._state.setKnob(self._bgRender, False) 202 self._bgRender.setFlag(nuke.STARTLINE) 203 self.addKnob(self._bgRender) 204 self._numThreads = nuke.Int_Knob("num_threads", "Thread limit") 205 self._numThreads.setVisible(self._bgRender.value()) 206 self._state.setKnob(self._numThreads, max(nuke.NUM_CPUS / 2, 1)) 207 self.addKnob(self._numThreads) 208 self._maxMem = nuke.String_Knob("max_memory", "Memory limit") 209 self._state.setKnob(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M") 210 self._maxMem.setVisible(self._bgRender.value()) 211 self.addKnob(self._maxMem)
212 213
214 - def _getBackgroundLimits(self):
215 return { 216 "maxThreads": self._numThreads.value(), 217 "maxCache": self._maxMem.value() }
218
219 - def knobChanged( self, knob ):
220 ExecuteDialog.knobChanged(self, knob) 221 222 if (knob == self._bgRender): 223 self._numThreads.setVisible(self._bgRender.value()) 224 self._maxMem.setVisible(self._bgRender.value())
225
226 - def isBackgrounded(self):
227 """Return whether the backgroun rendering option is enabled.""" 228 return self._bgRender.value()
229
230 - def run(self):
231 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(',')) 232 views = self._selectedViews() 233 rootProxyMode = nuke.root().proxy() 234 try: 235 nuke.Undo().disable() 236 nuke.root().setProxy(self._useProxy.value()) 237 if (self.isBackgrounded()): 238 nuke.executeBackgroundNuke(nuke.EXE_PATH, self._nodeSelection, 239 frame_ranges, views, self._getBackgroundLimits(), continueOnError = self._continueOnError.value()) 240 else: 241 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value()) 242 except RuntimeError, e: 243 if self._exceptOnError or e.args[0][0:9] != "Cancelled": # TO DO: change this to an exception type 244 raise 245 finally: 246 nuke.root().setProxy(rootProxyMode) 247 nuke.Undo().enable()
248
249 -class FlipbookDialog( RenderDialog ):
250 - def _titleString( self ):
251 return "Flipbook"
252
253 - def _idString( self ):
254 return "uk.co.thefoundry.FlipbookDialog"
255
256 - def __init__(self, dialogState, groupContext, node, takeNodeSettings):
257 # Init attributes 258 self._node = node 259 self._takeNodeSettings = takeNodeSettings 260 self._customKnobs = [] 261 262 # init super 263 RenderDialog.__init__(self, dialogState, groupContext) 264 265 # Override the initial frame range value 266 self._state.setKnob(self._rangeEnum, "input") 267 self._setFrameRangeFromSource(self._rangeEnum.value()) 268 269 if self._takeNodeSettings: 270 self._viewerForSettings.setValue(node.name()) 271 self.knobChanged(self._viewerForSettings)
272
273 - def _addPreKnobs( self ):
274 self._flipbookEnum = nuke.Enumeration_Knob( "flipbook", "Flipbook", flipbooking.gFlipbookFactory.getNames() ) 275 self._state.setKnob(self._flipbookEnum, "FrameCycler") 276 self.addKnob( self._flipbookEnum ) 277 self._viewerForSettings = nuke.Enumeration_Knob("viewer_settings", "Take settings from", ["-"] + self._viewers.keys()) 278 if not self._takeNodeSettings: 279 self._viewerForSettings.setValue("-") 280 self.addKnob(self._viewerForSettings) 281 282 self._defaultValues = nuke.PyScript_Knob("default", "Defaults") 283 self.addKnob(self._defaultValues) 284 285 # Region of Interest knobs 286 self._useRoi = nuke.Boolean_Knob("use_roi", "Enable ROI") 287 self._useRoi.setFlag(nuke.STARTLINE) 288 self._state.setKnob(self._useRoi, False) 289 self.addKnob(self._useRoi) 290 self._roi = nuke.BBox_Knob("roi", "Region of Interest") 291 self._state.setKnob(self._roi, (0, 0, 0, 0)) 292 self.addKnob(self._roi) 293 self._roi.setVisible(self._useRoi.value()) 294 295 # Channel knobs 296 self._channels = nuke.Channel_Knob( "channels_knob", "Channels") 297 if self._node.Class() == "Write": 298 self._channels.setValue(self._node.knob("channels").value()) 299 else: 300 self._state.setKnob(self._channels, "rgba") 301 self._channels.setFlag(nuke.STARTLINE | nuke.NO_CHECKMARKS) 302 self.addKnob( self._channels )
303
304 - def _addPostKnobs( self ):
305 super(FlipbookDialog, self)._addPostKnobs() 306 # Misc knobs 307 self._cleanup = nuke.Boolean_Knob("cleanup", "Delete existing temporary files") 308 self._cleanup.setFlag(nuke.STARTLINE) 309 self._state.setKnob(self._cleanup, True) 310 self.addKnob(self._cleanup) 311 312 # LUT knobs 313 self._luts = nuke.Enumeration_Knob("lut", "LUT", nuke.ViewerProcess.registeredNames()) 314 if self._takeNodeSettings: 315 self._state.setKnob(self._luts, self._lutFromViewer(self._viewerForSettings.value())) 316 else: 317 self._state.setKnob(self._luts, self._lutFromViewer()) 318 self.addKnob(self._luts) 319 320 self._burnInLUT = nuke.Boolean_Knob("burnin", "Burn in the LUT") 321 self._state.setKnob(self._burnInLUT, False) 322 self.addKnob(self._burnInLUT) 323 324 # Audio knobs 325 audioList = [] 326 audioList.append( "None" ) 327 for node in nuke.allNodes("AudioRead"): 328 audioList.append( node.name() ) 329 self._audioSource = nuke.Enumeration_Knob( "audio", "Audio", audioList ) 330 self.addKnob( self._audioSource )
331
332 - def _addTrailingKnobs(self):
333 self.flipbookKnobs()
334
335 - def flipbookKnobs(self):
336 try: 337 beforeKnobs = self.knobs() 338 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 339 flipbookToRun.dialogKnobs(self) 340 afterKnobs = self.knobs() 341 self._customKnobs = list(set(beforeKnobs.values()) ^ set(afterKnobs.values())) 342 except NotImplementedError: 343 pass
344
345 - def _getDefaultViews(self):
346 return nuke.activeViewer().view()
347
348 - def _addViewKnob(self):
349 oc = nuke.OutputContext() 350 self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())] 351 if (oc.viewcount() > 2): 352 supportedViews = self._selectedFlipbook().capabilities()["maximumViews"] 353 if (int(supportedViews) > 1): 354 self._viewSelection = nuke.MultiView_Knob("views", "Views") 355 else: 356 self._viewSelection = nuke.OneView_Knob("views", "View", self._views) 357 activeView = nuke.activeViewer().view() 358 if activeView == "": 359 activeView = self._views[0] 360 self._state.setKnob(self._viewSelection, activeView) 361 self.addKnob(self._viewSelection) 362 self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
363
364 - def _selectedFlipbook(self):
365 return flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value())
366
367 - def _lutFromViewer(self, viewerName = ""):
368 try: 369 if viewerName == "": 370 return nuke.ViewerProcess.node().knob("current").value() 371 else: 372 return nuke.ViewerProcess.node(viewer=viewerName).knob("current").value() 373 except AttributeError: 374 return "None"
375
376 - def _isViewerSettingKnob(self, knob):
377 return knob == self._useRoi or knob == self._roi or knob == self._channels or knob == self._useProxy or knob == self._frameRange or knob == self._rangeEnum or knob == self._luts
378
379 - def _setKnobAndStore(self, knob, val):
380 knob.setValue(val) 381 self._state.save(knob)
382
383 - def knobChanged(self, knob):
384 RenderDialog.knobChanged(self, knob) 385 if knob == self._defaultValues: 386 self._setKnobAndStore(self._useRoi, False) 387 self._setKnobAndStore(self._roi, (0, 0, 0, 0)) 388 self._roi.setVisible(False) 389 self._maxMem.setVisible(False) 390 self._numThreads.setVisible(False) 391 self._setKnobAndStore(self._viewerForSettings, "-") 392 self._setKnobAndStore(self._channels, "rgba") 393 self._setKnobAndStore(self._useProxy, False) 394 self._setKnobAndStore(self._frameRange, str(nuke.root().frameRange())) 395 self._setKnobAndStore(self._rangeEnum, "input") 396 self._setKnobAndStore(self._continueOnError, True) 397 self._setKnobAndStore(self._bgRender, False) 398 self._setKnobAndStore(self._luts, "sRGB") 399 self._setKnobAndStore(self._burnInLUT, False) 400 self._setKnobAndStore(self._cleanup, True) 401 self._setKnobAndStore(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M") 402 self._setKnobAndStore(self._numThreads, max(nuke.NUM_CPUS / 2, 1)) 403 elif (knob == self._viewerForSettings): 404 if self._viewerForSettings.value() != "-": 405 viewer = self._viewers[self._viewerForSettings.value()] 406 self._setKnobAndStore(self._useRoi, viewer.roiEnabled()) 407 roi = viewer.roi() 408 if roi != None: 409 self._roi.fromDict(roi) 410 self._state.save(self._roi) 411 self._channels.fromScript(viewer.knob("channels").toScript()) 412 self._state.save(self._channels) 413 self._setKnobAndStore(self._useProxy, nuke.root().proxy()) 414 self._frameRangeFromViewer(viewer.name()) 415 self._state.save(self._frameRange) 416 self._setKnobAndStore(self._rangeEnum, viewer.name()) 417 self._roi.setVisible(self._useRoi.value()) 418 self._setKnobAndStore(self._luts, self._lutFromViewer(viewer.name())) 419 elif (knob == self._useRoi): 420 self._roi.setVisible(self._useRoi.value()) 421 elif self._isViewerSettingKnob(knob): 422 self._viewerForSettings.setValue("-") 423 self._state.save(self._viewerForSettings) 424 elif knob == self._luts: 425 self._burnInLUT.setEnabled(self._luts.value() != "None") 426 427 if knob == self._flipbookEnum: 428 for k in self._customKnobs: 429 self.removeKnob(k) 430 self.removeKnob(self.okButton) 431 self.removeKnob(self.cancelButton) 432 self._customKnobs = [] 433 self.flipbookKnobs() 434 self._makeOkCancelButton() 435 elif knob in self._customKnobs: 436 try: 437 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 438 flipbookToRun.dialogKnobChanged(self, knob) 439 except NotImplementedError: 440 pass
441
442 - def _deleteTemporaries(self):
443 """Delete all the files in the range to be rendered.""" 444 temporariesPath = self._getIntermediatePath() 445 temporariesPath = temporariesPath .replace("%V", "%s") 446 for r in nuke.FrameRanges(self._frameRange.value().split(',')): 447 deleteRange = xrange(r.minFrame(), r.maxFrame() + 1) 448 449 for v in self._selectedViews(): 450 for i in deleteRange: 451 if len(self._selectedViews()) > 1: 452 f = temporariesPath % (i, v,) 453 else: 454 f = temporariesPath % i 455 456 if os.access(f, os.F_OK): 457 os.remove(f)
458
459 - def _getIntermediateFileType(self):
460 return _gFlipbookDialogState.getValue('intermediateFormat', 'exr')
461
462 - def _getIntermediatePath(self):
463 """Get the path for the temporary files. May be filled in using printf syntax.""" 464 flipbooktmp="" 465 if flipbooktmp == "": 466 try: 467 flipbooktmp = self._selectedFlipbook().cacheDir() 468 except: 469 try: 470 flipbooktmp = os.environ["NUKE_DISK_CACHE"] 471 except: 472 flipbooktmp = nuke.value("preferences.DiskCachePath") 473 474 if len(self._selectedViews()) > 1: 475 flipbookFileNameTemp = "nuke_tmp_flip.%04d.%V." + self._getIntermediateFileType() 476 else: 477 flipbookFileNameTemp = "nuke_tmp_flip.%04d." + self._getIntermediateFileType() 478 flipbooktmpdir = os.path.join(flipbooktmp, "flipbook") 479 if not os.path.exists(flipbooktmpdir): 480 os.mkdir(flipbooktmpdir) 481 482 if not os.path.isdir(flipbooktmpdir): 483 raise RuntimeError("%s already exists and is not a directory, please delete before flipbooking again" % flipbooktmpdir) 484 flipbooktmp = os.path.join(flipbooktmpdir, flipbookFileNameTemp) 485 486 if nuke.env['WIN32']: 487 flipbooktmp = re.sub(r"\\", "/", str(flipbooktmp)) 488 return flipbooktmp
489
490 - def _requireIntermediateNode(self):
491 if self._node.Class() == "Read" or self._node.Class() == "Write": 492 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 493 flipbookCapabilities = flipbookToRun.capabilities() 494 495 # Check if we can read it in directly.. 496 filePath = nuke.filename(self._node) 497 # There might be a prefix that overrides the extension, if so, this will 498 # confuse the flipbook probably, so just create a render. 499 if ':' in filePath: 500 readerPrefix = filePath.split(':')[0] 501 if len(readerPrefix) > 1: # 1 is a drive letter 502 return True 503 fileExtension = os.path.splitext(filePath)[1].lower()[1:] 504 flipbookSupportsFileType = fileExtension in flipbookCapabilities.get("fileTypes", []) 505 if not flipbookSupportsFileType: 506 return True 507 508 # Not all flipbooks can handle weird channels 509 flipbookSupportsArbitraryChannels = flipbookCapabilities.get("arbitraryChannels", False) 510 if self._channels.value() not in set(["rgb", "rgba", "alpha"]) and not flipbookSupportsArbitraryChannels: 511 return True 512 channelKnob = self._node.knob("channels") 513 if channelKnob != None and channelKnob.value() != self._channels.value(): 514 return True 515 516 if self._burnInLUT.value() and self._burnInLUT.enabled(): 517 return True 518 519 return False 520 else: 521 return True
522
523 - def _createIntermediateNode(self):
524 """Create a write node to render out the current node so that output may be used for flipbooking.""" 525 flipbooktmp = self._getIntermediatePath() 526 527 fieldname = "file" 528 if self._useProxy.value(): 529 fieldname = "proxy" 530 531 fixup = nuke.createNode("Group", "tile_color 0xff000000", inpanel = False) 532 with fixup: 533 fixup.setName("Flipbook") 534 inputNode = nuke.createNode("Input", inpanel = False) 535 shuffle = nuke.createNode("Shuffle", inpanel = False) 536 shuffle.knob("in").setValue(self._channels.value()) 537 write = nuke.createNode("Write", fieldname+" {"+flipbooktmp+"}", inpanel = False) 538 write.knob('file_type').setValue(self._getIntermediateFileType()) 539 write.knob('views').fromScript(" ".join(self._selectedViews())) 540 541 if self._getIntermediateFileType() == "exr": 542 write.knob('compression').setValue("B44") 543 if self._burnInLUT.value(): 544 lut = self._getLUT() 545 if lut != "None": 546 write.knob('colorspace').setValue(lut) 547 outputNode = nuke.createNode("Output", inpanel = False) 548 #If called on a Viewer connect fixup node to the one immediately above if exists. 549 if self._node.Class() == "Viewer": 550 fixup.setInput(0, self._node.input(int(nuke.knob(self._node.fullName()+".input_number")))) 551 else: 552 fixup.setInput(0, self._node) 553 554 try: 555 # Throws exception on render failure 556 if (self.isBackgrounded()): 557 nuke.executeBackgroundNuke(nuke.EXE_PATH, [write], 558 nuke.FrameRanges(self._frameRange.value().split(',')), self._selectedViews(), 559 self._getBackgroundLimits(), self._continueOnError.value(), 560 self._flipbookEnum.value(), self._getOptions(write)) 561 else: 562 nuke.executeMultiple((write,), 563 nuke.FrameRanges(self._frameRange.value().split(',')), self._selectedViews(), 564 self._continueOnError.value()) 565 except RuntimeError, msg: 566 if msg.args[0][0:9] == "Cancelled": 567 splitMsg = string.split(msg.args[0]) 568 569 msg = """Render did not complete, do you want to show the completed range? 570 Frame range %s contains %s frames but only %s finished.""" % (self._frameRange.value(), splitMsg[3], splitMsg[1]) 571 if nuke.ask(msg) == False: 572 nuke.delete(fixup) 573 fixup = None 574 else: 575 nuke.delete(fixup) 576 fixup = None 577 nuke.message("Flipbook render failed:\n%s" % (msg.args[0],)) 578 # except BaseException, be: 579 # print be.__class__.__name__ 580 # traceback.print_exc() 581 finally: 582 return fixup
583
584 - def _getLUT(self):
585 return self._luts.value()
586
587 - def _getAudio(self):
588 nukeNode = nuke.toNode( self._audioSource.value() ) 589 ret = "" 590 if nukeNode != None: 591 ret = nukeNode["file"].getEvaluatedValue() 592 593 # if the platform is not windows and we have spaces in the audio name then we cant use audio 594 # as framecycler does not support spaces in the name 595 if nuke.env['WIN32'] == False: 596 if ret != "": 597 # check if we have spaces 598 if (' ' in ret) == True : 599 nuke.message("Framecycler does not currently support spaces in the audio file name, to enable audio please ensure the audio file contains no spaces.") 600 ret = "" 601 return ret
602
603 - def _getOptions(self, nodeToFlipbook):
604 options = { 605 } 606 607 try: 608 options['pixelAspect'] = float(nuke.value(nodeToFlipbook.name()+".pixel_aspect")) 609 except: 610 pass 611 612 try: 613 f = nodeToFlipbook.format() 614 options['dimensions'] = { 'width' : f.width(), 'height' : f.height() } 615 except: 616 pass 617 618 # LUT 619 if not self._burnInLUT.value(): 620 inputColourspace = "linear" 621 outputColourspace = "linear" 622 # Check if we have a different than linear input 623 if self._node.Class() == "Read" or self._node.Class() == "Write": 624 lut = self._node.knob("colorspace").value() 625 # Might be in the format of "default (foo)", if so, get at "foo". 626 if lut[:7] == "default": 627 lut = lut[9:-1] 628 inputColourspace = lut 629 630 # Check our output 631 lut = self._getLUT() 632 if lut != "None": 633 outputColourspace = lut 634 635 if inputColourspace == outputColourspace: 636 options["lut"] = inputColourspace 637 else: 638 options["lut"] = inputColourspace + "-" + outputColourspace 639 # AUDIO 640 audioTrack = self._getAudio() 641 if audioTrack != "": 642 options["audio"] = audioTrack 643 644 # ROI 645 if self._useRoi.value(): 646 roi = self._roi.toDict() 647 if (roi["r"] - roi["x"] > 0) and (roi["t"] - roi["y"] > 0): 648 options["roi"] = bboxToTopLeft(int(nuke.value(nodeToFlipbook.name()+".actual_format.height")), roi) 649 650 return options
651
652 - def run(self):
653 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 654 if (flipbookToRun): 655 if not os.access(flipbookToRun.path(), os.X_OK): 656 raise RuntimeError("%s cannot be executed (%s)." % (flipbookToRun.name(), flipbookToRun.path(),) ) 657 658 nodeToFlipbook = None 659 rootProxyMode = nuke.root().proxy() 660 try: 661 # Need this to prevent Bug 5295 662 nuke.Undo().disable() 663 nuke.root().setProxy(self._useProxy.value()) 664 665 if self._cleanup.value(): 666 self._deleteTemporaries() 667 668 calledOnNode = self._node 669 if self._node.Class() == "Viewer": 670 self._node = self._node.input(int(self._node.knob("input_number").value())) 671 672 runFlipbook = False 673 # In many cases we need to create a temporary node and render that. 674 if not self._requireIntermediateNode(): 675 nodeToFlipbook = self._node 676 runFlipbook = True 677 else: 678 nodeToFlipbook = self._createIntermediateNode() 679 runFlipbook = not self._bgRender.value() 680 681 if nodeToFlipbook and runFlipbook: 682 filename = nuke.filename(nodeToFlipbook) 683 if filename is None or filename == "": 684 raise RuntimeError("Cannot run a flipbook on '%s', expected to find a filename and there was none." % (nodeToFlipbook.fullName(),)) 685 flipbookToRun.run(filename, 686 nuke.FrameRanges(self._frameRange.value().split(',')), 687 self._selectedViews(), self._getOptions(nodeToFlipbook)) 688 finally: 689 if self._node != nodeToFlipbook: 690 nuke.delete(nodeToFlipbook) 691 nuke.root().setProxy(rootProxyMode) 692 nuke.Undo().enable() 693 else: 694 raise RuntimeError("No flipbook called " + self._flipbookEnum.value() + " found. Was it deregistered while the dialog was open?")
695
696 -class ViewerCaptureDialog( FlipbookDialog ):
697 - def _titleString( self ):
698 return "Capture"
699
700 - def _idString( self ):
701 return "uk.co.thefoundry.ViewerCaptureDialog"
702
703 - def __init__(self, dialogState, groupContext, node):
704 705 # init super 706 FlipbookDialog.__init__(self, dialogState, groupContext, node, True) 707 708 self._bgRender.setVisible(False) 709 self._useProxy.setVisible(False) 710 self._continueOnError.setVisible(False) 711 712 self._viewerForSettings.setVisible(False) 713 self._defaultValues.setVisible(False) 714 715 self._useRoi.setVisible(False) 716 self._roi.setVisible(False) 717 718 self._channels.setVisible(False) 719 self._luts.setVisible(False) 720 721 self._audioSource.setVisible(False) 722 self._burnInLUT.setVisible(False) 723 724 try: 725 ## this may not exist, just ignore if not present 726 self._viewSelection.setVisible(False) 727 except: 728 pass 729 730 customWriteActive = node['file'].getValue() != self._getIntermediatePath() and node['file'].getValue() != '' 731 self._customWrite = nuke.Boolean_Knob( 'custom', 'Customise write path' ) 732 self._customWrite.setValue( customWriteActive ) 733 self.addKnob( self._customWrite ) 734 735 self._noFlipbook = nuke.Boolean_Knob( 'write', 'No flipbook' ) 736 self._noFlipbook.setFlag( nuke.STARTLINE ) 737 self._noFlipbook.setVisible( customWriteActive ) 738 self._noFlipbook.setValue( self._state.get( self._noFlipbook, False ) ) 739 self.addKnob( self._noFlipbook ) 740 741 self._file = nuke.File_Knob( 'file', 'Write path' ) 742 defaultPath = self._node['file'].value() 743 if defaultPath == self._getIntermediatePath(): 744 defaultPath = '' 745 self._file.setValue ( self._state.get(self._file, defaultPath ) ) 746 self._file.setVisible( customWriteActive ) 747 748 self.addKnob( self._file )
749
750 - def knobChanged( self, knob ):
751 try: 752 FlipbookDialog.knobChanged(self, knob) 753 if (knob == self._customWrite): 754 self._noFlipbook.setVisible( self._customWrite.value() ) 755 self._file.setVisible( self._customWrite.value() ) 756 if ( not self._customWrite.value() ): 757 self._node['file'].setValue( self._getIntermediatePath() ) 758 elif( knob == self._noFlipbook ): 759 self._flipbookEnum.setEnabled( not self._noFlipbook.value() ) 760 except: 761 pass
762
763 - def _getIntermediateFileType(self):
764 return 'jpg'
765
766 - def captureViewer(self):
767 """ Return an instance of a CaptureViewer class, which when executed captures the viewer. 768 """ 769 flipbook = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 770 if flipbook and not os.access(flipbook.path(), os.X_OK): 771 raise RuntimeError("%s cannot be executed (%s)." % (flipbook.name(), flipbook.path(),) ) 772 773 # build up the args 774 frameRange = self._frameRange.value() 775 viewer = self._node 776 selectedViews = self._selectedViews() 777 defaultWritePath = self._getIntermediatePath() 778 customWritePath = self._file.value() if self._customWrite.value() else "" 779 doFlipbook = not self._noFlipbook.value() 780 doCleanup = self._cleanup.value() 781 782 return captureViewer.CaptureViewer(flipbook, frameRange, viewer, selectedViews, defaultWritePath, customWritePath, doFlipbook, doCleanup)
783
784 -def showExecuteDialog(nodesToExecute, exceptOnError = True):
785 """Present a dialog that executes the given list of nodes.""" 786 groupContext = nuke.root() 787 d = ExecuteDialog(_gRenderDialogState, groupContext, nodesToExecute, exceptOnError) 788 if d.showModalDialog() == True: 789 d.run() 790
791 -def showRenderDialog(nodesToRender, exceptOnError = True):
792 """Present a dialog that renders the given list of nodes.""" 793 groupContext = nuke.root() 794 d = RenderDialog(_gRenderDialogState, groupContext, nodesToRender, exceptOnError) 795 if d.showModalDialog() == True: 796 d.run() 797
798 -def showFlipbookDialog(node, takeNodeSettings = False):
799 """Present a dialog that flipbooks the given node.""" 800 if node is None: 801 raise RuntimeError("Can't launch flipbook, require a node."); 802 if node.Class() == "Viewer" and node.inputs() == 0: 803 raise RuntimeError("Can't launch flipbook, there is nothing connected to the viewed input."); 804 805 if not (nuke.canCreateNode("Write")): 806 nuke.message("Flipbooking is not permitted in Nuke Assist") 807 return 808 809 groupContext = nuke.root() 810 811 e = FlipbookDialog(_gFlipbookDialogState, groupContext, node, takeNodeSettings) 812 if (e.showModalDialog() == True): 813 e.run()
814 815 # because the capture button could have been triggered via a progress bar in update_handles 816 # we defer the capture run until the main event loop is pumped
817 -class ViewerCaptureDialogThread(Thread):
818 - def __init__(self, captureViewer):
821
822 - def run(self):
823 ## only runs the dialog capture function when we are outside update_handles 824 utils.executeInMainThreadWithResult( self.captureViewer, )
825
826 -def showViewerCaptureDialog(node):
827 if node is None: 828 raise RuntimeError("Can't launch flipbook, requires a viewer node."); 829 if node.Class() != "Viewer" and node.inputs() == 0: 830 raise RuntimeError("Can't launch flipbook, this is not a viewer node."); 831 832 if not (nuke.canCreateNode("Write")): 833 nuke.message("Viewer capture is not permitted in Nuke Assist") 834 return 835 836 groupContext = nuke.root() 837 e = ViewerCaptureDialog(_gViewerCaptureDialogState, groupContext, node) 838 if (e.showModalDialog() == True): 839 # Bug 38516 - Be careful about what gets passed to the ViewerCaptureDialogThread, since anything 840 # created here will be destroyed in a different thread. This can cause problems, such as crashes, 841 # if a Qt widget gets passed. 842 captureViewer = e.captureViewer() 843 thread = ViewerCaptureDialogThread(captureViewer) 844 thread.start()
845
846 -def showFlipbookDialogForSelected():
847 """Present a dialog that flipbooks the currently selected node.""" 848 try: 849 showFlipbookDialog(nuke.selectedNode()) 850 except ValueError, ve: 851 raise RuntimeError("Can't launch flipbook, %s." % (ve.args[0]))
852
853 -def bboxToTopLeft(height, roi):
854 """Convert the roi passed from a origin at the bottom left to the top left. 855 Also replaces the r and t keys with w and h keys. 856 @param height: the height used to determine the top. 857 @param roi: the roi with a bottom left origin, must have x, y, r & t keys. 858 @result dict with x, y, w & h keys""" 859 topLeftRoi = { 860 "x": roi["x"], 861 "y": height - roi["y"] - (roi["t"] - roi["y"]), 862 "w": roi["r"] - roi["x"], 863 "h": roi["t"] - roi["y"] } 864 return topLeftRoi
865
866 -def setRenderDialogDefaultOption(name, value):
867 """ Set a particular option to the given value. The type of the value differs per option, giving the wrong value may result in exceptions. The options are read every time the dialog is opened, though not every knob in the dialog has it's value stored.""" 868 _gRenderDialogState.saveValue(name, value)
869
870 -def setFlipbookDefaultOption(name, value):
871 """ Set a particular option to the given value. The type of the value differs per option, giving the wrong value may result in exceptions. The options are read every time the dialog is opened, though not every knob in the dialog has it's value stored.""" 872 _gFlipbookDialogState.saveValue(name, value)
873