1
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
14
15
16
17
21
22 - def get(self, knob, defaultValue = None):
23 """Return the given knob's stored last state value.
24 If none exists, defaultValue is returned.
25 Values are stored in a dict referenced by knob name, so names must be unique!"""
26 return self.getValue(knob.name(), defaultValue)
27
28 - def save(self, knob):
29 """Store the knob's current value as the 'last state' for the next time the dialog is opened.
30 Values are stored in a dict referenced by knob name, so names must be unique!"""
31 self.saveValue(knob.name(), knob.value())
32
33 - def setKnob(self, knob, defaultValue = None):
37 """Stores the value with the given id."""
38 self._state[id] = value
39 - def getValue(self, id, defaultValue = None):
40 """Recalls the value. If it was not set before, it will return the defaultValue."""
41 return self._state.get(id, defaultValue)
42
43 _gRenderDialogState = DialogState()
44 _gFlipbookDialogState = DialogState()
45
49
51 return "uk.co.thefoundry.ExecuteDialog"
52
54 """Add knobs that must appear before the render knobs."""
55 return
56
57 - def _addPostKnobs(self):
58 """Add knobs that must appear after the render knobs."""
59 return
60
62 """Add knobs that must appear at the very end."""
63 return
64
69
78
83
84 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
85 self._state = dialogState
86 self._nodeSelection = nodeSelection
87 self._exceptOnError = exceptOnError
88
89 nukescripts.PythonPanel.__init__(self, self._titleString(), self._idString(), False)
90
91 self._viewers = {}
92 for n in nuke.allNodes("Viewer", groupContext):
93 self._viewers[n.name()] = n
94 self._specialRanges = ["input", "global", "custom"]
95
96 self._addPreKnobs()
97
98
99 self._rangeEnum = nuke.Enumeration_Knob( "frame_range", "Frame range", self._specialRanges + self._viewers.keys() )
100 self._state.setKnob(self._rangeEnum, "input")
101 self.addKnob( self._rangeEnum )
102 self._frameRange = nuke.String_Knob( "frame_range_string", "")
103 self._frameRange.clearFlag(nuke.STARTLINE)
104 if self._rangeEnum.value() == "custom":
105 self._state.setKnob(self._frameRange, str(nuke.root().frameRange()))
106 else:
107 self._setFrameRangeFromSource(self._rangeEnum.value())
108
109 self.addKnob(self._frameRange)
110
111
112 self._useProxy = nuke.Boolean_Knob("use_proxy", "Use proxy")
113 self._useProxy.setFlag(nuke.STARTLINE)
114 self._state.setKnob(self._useProxy, nuke.root().proxy())
115 self.addKnob(self._useProxy)
116
117 self._addPostKnobs()
118
119 self._continueOnError = nuke.Boolean_Knob("continue", "Continue on error")
120 self._state.setKnob(self._continueOnError, True)
121 self._continueOnError.setFlag(nuke.STARTLINE)
122 self.addKnob(self._continueOnError)
123
124 self._addViewKnob()
125
126 self._addTrailingKnobs()
127
136
150
152 """"Set the framerange knob to have the framerange from the given viewer."""
153 viewerRange = str(self._viewers[viewer].knob("frame_range").value())
154 if viewerRange == "":
155 viewerRange = str(self._viewers[viewer].playbackRange())
156 self._frameRange.setValue(viewerRange)
157
164
167
182
186
188 return "uk.co.thefoundry.RenderDialog"
189
190 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
192
193 - def _addPostKnobs(self):
194
195 self._bgRender = nuke.Boolean_Knob("bg_render", "Render in background")
196 self._state.setKnob(self._bgRender, False)
197 self._bgRender.setFlag(nuke.STARTLINE)
198 self.addKnob(self._bgRender)
199 self._numThreads = nuke.Int_Knob("num_threads", "Thread limit")
200 self._numThreads.setVisible(self._bgRender.value())
201 self._state.setKnob(self._numThreads, max(nuke.NUM_CPUS / 2, 1))
202 self.addKnob(self._numThreads)
203 self._maxMem = nuke.String_Knob("max_memory", "Memory limit")
204 self._state.setKnob(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M")
205 self._maxMem.setVisible(self._bgRender.value())
206 self.addKnob(self._maxMem)
207
208
210 return {
211 "maxThreads": self._numThreads.value(),
212 "maxCache": self._maxMem.value() }
213
220
222 """Return whether the backgroun rendering option is enabled."""
223 return self._bgRender.value()
224
226 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(','))
227 views = self._selectedViews()
228 rootProxyMode = nuke.root().proxy()
229 try:
230 nuke.Undo().disable()
231 nuke.root().setProxy(self._useProxy.value())
232 if (self.isBackgrounded()):
233 nuke.executeBackgroundNuke(nuke.EXE_PATH, self._nodeSelection,
234 frame_ranges, views, self._getBackgroundLimits(), continueOnError = self._continueOnError.value())
235 else:
236 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value())
237 except RuntimeError, e:
238 if self._exceptOnError or e.args[0][0:9] != "Cancelled":
239 raise
240 finally:
241 nuke.root().setProxy(rootProxyMode)
242 nuke.Undo().enable()
243
247
249 return "uk.co.thefoundry.FlipbookDialog"
250
251 - def __init__(self, dialogState, groupContext, node, takeNodeSettings):
267
269 self._flipbookEnum = nuke.Enumeration_Knob( "flipbook", "Flipbook", flipbooking.gFlipbookFactory.getNames() )
270 self._state.setKnob(self._flipbookEnum, "FrameCycler")
271 self.addKnob( self._flipbookEnum )
272 self._viewerForSettings = nuke.Enumeration_Knob("viewer_settings", "Take settings from", ["-"] + self._viewers.keys())
273 if not self._takeNodeSettings:
274 self._viewerForSettings.setValue("-")
275 self.addKnob(self._viewerForSettings)
276
277 self._defaultValues = nuke.PyScript_Knob("default", "Defaults")
278 self.addKnob(self._defaultValues)
279
280
281 self._useRoi = nuke.Boolean_Knob("use_roi", "Enable ROI")
282 self._useRoi.setFlag(nuke.STARTLINE)
283 self._state.setKnob(self._useRoi, False)
284 self.addKnob(self._useRoi)
285 self._roi = nuke.BBox_Knob("roi", "Region of Interest")
286 self._state.setKnob(self._roi, (0, 0, 0, 0))
287 self.addKnob(self._roi)
288 self._roi.setVisible(self._useRoi.value())
289
290
291 self._channels = nuke.Channel_Knob( "channels_knob", "Channels")
292 if self._node.Class() == "Write":
293 self._channels.setValue(self._node.knob("channels").value())
294 else:
295 self._state.setKnob(self._channels, "rgba")
296 self._channels.setFlag(nuke.STARTLINE | nuke.NO_CHECKMARKS)
297 self.addKnob( self._channels )
298
299 - def _addPostKnobs( self ):
300 super(FlipbookDialog, self)._addPostKnobs()
301
302 self._cleanup = nuke.Boolean_Knob("cleanup", "Delete existing temporary files")
303 self._cleanup.setFlag(nuke.STARTLINE)
304 self._state.setKnob(self._cleanup, True)
305 self.addKnob(self._cleanup)
306
307
308 self._luts = nuke.Enumeration_Knob("lut", "LUT", nuke.ViewerProcess.registeredNames())
309 if self._takeNodeSettings:
310 self._state.setKnob(self._luts, self._lutFromViewer(self._viewerForSettings.value()))
311 else:
312 self._state.setKnob(self._luts, self._lutFromViewer())
313 self.addKnob(self._luts)
314
315 self._burnInLUT = nuke.Boolean_Knob("burnin", "Burn in the LUT")
316 self._state.setKnob(self._burnInLUT, False)
317 self.addKnob(self._burnInLUT)
318
319
320 audioList = []
321 audioList.append( "None" )
322 for node in nuke.allNodes("AudioRead"):
323 audioList.append( node.name() )
324 self._audioSource = nuke.Enumeration_Knob( "audio", "Audio", audioList )
325 self.addKnob( self._audioSource )
326
329
339
342
358
361
370
372 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
373
377
379 RenderDialog.knobChanged(self, knob)
380 if knob == self._defaultValues:
381 self._setKnobAndStore(self._useRoi, False)
382 self._setKnobAndStore(self._roi, (0, 0, 0, 0))
383 self._roi.setVisible(False)
384 self._maxMem.setVisible(False)
385 self._numThreads.setVisible(False)
386 self._setKnobAndStore(self._viewerForSettings, "-")
387 self._setKnobAndStore(self._channels, "rgba")
388 self._setKnobAndStore(self._useProxy, False)
389 self._setKnobAndStore(self._frameRange, str(nuke.root().frameRange()))
390 self._setKnobAndStore(self._rangeEnum, "input")
391 self._setKnobAndStore(self._continueOnError, True)
392 self._setKnobAndStore(self._bgRender, False)
393 self._setKnobAndStore(self._luts, "sRGB")
394 self._setKnobAndStore(self._burnInLUT, False)
395 self._setKnobAndStore(self._cleanup, True)
396 self._setKnobAndStore(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M")
397 self._setKnobAndStore(self._numThreads, max(nuke.NUM_CPUS / 2, 1))
398 elif (knob == self._viewerForSettings):
399 if self._viewerForSettings.value() != "-":
400 viewer = self._viewers[self._viewerForSettings.value()]
401 self._setKnobAndStore(self._useRoi, viewer.roiEnabled())
402 roi = viewer.roi()
403 if roi != None:
404 self._roi.fromDict(roi)
405 self._state.save(self._roi)
406 self._channels.fromScript(viewer.knob("channels").toScript())
407 self._state.save(self._channels)
408 self._setKnobAndStore(self._useProxy, nuke.root().proxy())
409 self._frameRangeFromViewer(viewer.name())
410 self._state.save(self._frameRange)
411 self._setKnobAndStore(self._rangeEnum, viewer.name())
412 self._roi.setVisible(self._useRoi.value())
413 self._setKnobAndStore(self._luts, self._lutFromViewer(viewer.name()))
414 elif (knob == self._useRoi):
415 self._roi.setVisible(self._useRoi.value())
416 elif self._isViewerSettingKnob(knob):
417 self._viewerForSettings.setValue("-")
418 self._state.save(self._viewerForSettings)
419 elif knob == self._luts:
420 self._burnInLUT.setEnabled(self._luts.value() != "None")
421
422 if knob == self._flipbookEnum:
423 for k in self._customKnobs:
424 self.removeKnob(k)
425 self.removeKnob(self.okButton)
426 self.removeKnob(self.cancelButton)
427 self._customKnobs = []
428 self.flipbookKnobs()
429 self._makeOkCancelButton()
430 elif knob in self._customKnobs:
431 try:
432 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value())
433 flipbookToRun.dialogKnobChanged(self, knob)
434 except NotImplementedError:
435 pass
436
453
456
484
517
578
580 return self._luts.value()
581
583 nukeNode = nuke.toNode( self._audioSource.value() )
584 ret = ""
585 if nukeNode != None:
586 ret = nukeNode["file"].getEvaluatedValue()
587
588
589
590 if nuke.env['WIN32'] == False:
591 if ret != "":
592
593 if (' ' in ret) == True :
594 nuke.message("Framecycler does not currently support spaces in the audio file name, to enable audio please ensure the audio file contains no spaces.")
595 ret = ""
596 return ret
597
599 options = {
600 }
601
602 try:
603 options['pixelAspect'] = float(nuke.value(nodeToFlipbook.name()+".pixel_aspect"))
604 except:
605 pass
606
607 try:
608 f = nodeToFlipbook.format()
609 options['dimensions'] = { 'width' : f.width(), 'height' : f.height() }
610 except:
611 pass
612
613
614 if not self._burnInLUT.value():
615 inputColourspace = "linear"
616 outputColourspace = "linear"
617
618 if self._node.Class() == "Read" or self._node.Class() == "Write":
619 lut = self._node.knob("colorspace").value()
620
621 if lut[:7] == "default":
622 lut = lut[9:-1]
623 inputColourspace = lut
624
625
626 lut = self._getLUT()
627 if lut != "None":
628 outputColourspace = lut
629
630 if inputColourspace == outputColourspace:
631 options["lut"] = inputColourspace
632 else:
633 options["lut"] = inputColourspace + "-" + outputColourspace
634
635 audioTrack = self._getAudio()
636 if audioTrack != "":
637 options["audio"] = audioTrack
638
639
640 if self._useRoi.value():
641 roi = self._roi.toDict()
642 if (roi["r"] - roi["x"] > 0) and (roi["t"] - roi["y"] > 0):
643 options["roi"] = bboxToTopLeft(int(nuke.value(nodeToFlipbook.name()+".actual_format.height")), roi)
644
645 return options
646
689
691 """Present a dialog that executes the given list of nodes."""
692 groupContext = nuke.root()
693 d = ExecuteDialog(_gRenderDialogState, groupContext, nodesToExecute, exceptOnError)
694 if d.showModalDialog() == True:
695 d.run()
696
698 """Present a dialog that renders the given list of nodes."""
699 groupContext = nuke.root()
700 d = RenderDialog(_gRenderDialogState, groupContext, nodesToRender, exceptOnError)
701 if d.showModalDialog() == True:
702 d.run()
703
705 """Present a dialog that flipbooks the given node."""
706 if node is None:
707 raise RuntimeError("Can't launch flipbook, require a node.");
708 if node.Class() == "Viewer" and node.inputs() == 0:
709 raise RuntimeError("Can't launch flipbook, there is nothing connected to the viewed input.");
710
711 groupContext = nuke.root()
712
713 e = FlipbookDialog(_gFlipbookDialogState, groupContext, node, takeNodeSettings)
714 if (e.showModalDialog() == True):
715 e.run()
716
718 """Present a dialog that flipbooks the currently selected node."""
719 try:
720 showFlipbookDialog(nuke.selectedNode())
721 except ValueError, ve:
722 raise RuntimeError("Can't launch flipbook, %s." % (ve.args[0]))
723
725 """Convert the roi passed from a origin at the bottom left to the top left.
726 Also replaces the r and t keys with w and h keys.
727 @param height: the height used to determine the top.
728 @param roi: the roi with a bottom left origin, must have x, y, r & t keys.
729 @result dict with x, y, w & h keys"""
730 topLeftRoi = {
731 "x": roi["x"],
732 "y": height - roi["y"] - (roi["t"] - roi["y"]),
733 "w": roi["r"] - roi["x"],
734 "h": roi["t"] - roi["y"] }
735 return topLeftRoi
736
738 """ 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."""
739 _gRenderDialogState.saveValue(name, value)
740
742 """ 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."""
743 _gFlipbookDialogState.saveValue(name, value)
744