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 from threading import Thread
14 from nukescripts import utils, sys, os, captureViewer
15
16
17
18
19
20
21
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):
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
54
56 return "uk.co.thefoundry.ExecuteDialog"
57
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
67 """Add knobs that must appear at the very end."""
68 return
69
74
83
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
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
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
141
155
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
169
172
187
191
193 return "uk.co.thefoundry.RenderDialog"
194
195 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
197
198 - def _addPostKnobs(self):
199
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
215 return {
216 "maxThreads": self._numThreads.value(),
217 "maxCache": self._maxMem.value() }
218
225
227 """Return whether the backgroun rendering option is enabled."""
228 return self._bgRender.value()
229
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":
244 raise
245 finally:
246 nuke.root().setProxy(rootProxyMode)
247 nuke.Undo().enable()
248
252
254 return "uk.co.thefoundry.FlipbookDialog"
255
256 - def __init__(self, dialogState, groupContext, node, takeNodeSettings):
272
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
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
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
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
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
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
334
344
347
363
366
375
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
382
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
458
461
489
522
583
585 return self._luts.value()
586
588 nukeNode = nuke.toNode( self._audioSource.value() )
589 ret = ""
590 if nukeNode != None:
591 ret = nukeNode["file"].getEvaluatedValue()
592
593
594
595 if nuke.env['WIN32'] == False:
596 if ret != "":
597
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
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
619 if not self._burnInLUT.value():
620 inputColourspace = "linear"
621 outputColourspace = "linear"
622
623 if self._node.Class() == "Read" or self._node.Class() == "Write":
624 lut = self._node.knob("colorspace").value()
625
626 if lut[:7] == "default":
627 lut = lut[9:-1]
628 inputColourspace = lut
629
630
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
640 audioTrack = self._getAudio()
641 if audioTrack != "":
642 options["audio"] = audioTrack
643
644
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
695
699
701 return "uk.co.thefoundry.ViewerCaptureDialog"
702
703 - def __init__(self, dialogState, groupContext, node):
749
762
765
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
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
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
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
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
816
825
845
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
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
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
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