Trees | Indices | Help |
|
---|
|
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 from fnFlipbookRenderer import getFlipbookRenderer 16 17 #import traceback 18 19 ############################################################################## 20 # Constants for the module 21 ############################################################################## 22 23 _USE_SETTINGS_FROM_CUSTOM = 'Custom' 24 _FRAME_RANGE_GLOBAL = 'global' 25 _FRAME_RANGE_INPUT = 'input' 26 _FRAME_RANGE_INOUT = 'in-out' 27 _FRAME_RANGE_VISIBLE = 'visible' 28 _FRAME_RANGE_CUSTOM = 'custom' 29 30 31 ############################################################################## 32 # Dialogs 33 ############################################################################## 343859 60 _gRenderDialogState = DialogState() 61 _gFlipbookDialogState = DialogState() 62 _gViewerCaptureDialogState = DialogState() 6340 """Return the given knob's stored last state value. 41 If none exists, defaultValue is returned. 42 Values are stored in a dict referenced by knob name, so names must be unique!""" 43 return self.getValue(knob.name(), defaultValue)4446 """Store the knob's current value as the 'last state' for the next time the dialog is opened. 47 Values are stored in a dict referenced by knob name, so names must be unique!""" 48 self.saveValue(knob.name(), knob.value())4951 """Convenience method for setting a value straight on a knob.""" 52 knob.setValue(self.get(knob, defaultValue))57 """Recalls the value. If it was not set before, it will return the defaultValue.""" 58 return self._state.get(id, defaultValue)67 70 74 78 82 8621988 oc = nuke.OutputContext() 89 allViews = [oc.viewname(i) for i in xrange(1, oc.viewcount())] 90 return " ".join(allViews)9193 """Add knobs for view selection.""" 94 oc = nuke.OutputContext() 95 if (oc.viewcount() > 2): 96 self._viewSelection = nuke.MultiView_Knob("multi_view", "Views") 97 self._viewSelection.fromScript(self._state.get(self._viewSelection, self._getDefaultViews())) 98 self.addKnob(self._viewSelection) 99 self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)100102 """Add the knob and make sure it cannot be animated.""" 103 knob.setFlag(nuke.NO_ANIMATION | nuke.NO_MULTIVIEW) 104 super(ExecuteDialog, self).addKnob(knob)105107 self._state = dialogState 108 self._nodeSelection = nodeSelection 109 self._exceptOnError = exceptOnError 110 self._dialogKnobs = None 111 112 113 nukescripts.PythonPanel.__init__(self, self._titleString(), self._idString(), False) 114 115 self._viewers = {} 116 for n in nuke.allNodes("Viewer", groupContext): 117 self._viewers[n.name()] = n 118 119 self._addKnobs()120122 self._dialogKnobs = [] 123 beforeKnobs = self.knobs() 124 self._addLeadingKnobs() 125 126 self._addPreKnobs() 127 128 # Frame range knobs 129 specialRanges = [_FRAME_RANGE_GLOBAL, _FRAME_RANGE_INPUT, _FRAME_RANGE_CUSTOM] 130 for viewer in self._viewers.keys(): 131 specialRanges.append(viewer + '/' + _FRAME_RANGE_INOUT) 132 specialRanges.append(viewer + '/' + _FRAME_RANGE_VISIBLE) 133 134 self._rangeEnum = nuke.CascadingEnumeration_Knob( "frame_range", "Frame range", specialRanges ) 135 self._rangeEnum.setTooltip("Select the frame range for the flipbook") 136 self._state.setKnob(self._rangeEnum, _FRAME_RANGE_INPUT) 137 self.addKnob( self._rangeEnum ) 138 139 self._frameRange = nuke.String_Knob( "frame_range_string", "") 140 self._frameRange.setTooltip("Custom frame range") 141 self._frameRange.clearFlag(nuke.STARTLINE) 142 if self._rangeEnum.value() == _FRAME_RANGE_CUSTOM: 143 self._state.setKnob(self._frameRange, str(nuke.root().frameRange())) 144 else: 145 self._setFrameRangeFromSource(self._rangeEnum.value()) 146 147 self.addKnob(self._frameRange) 148 149 self._addPostKnobs() 150 151 self._addViewKnob() 152 153 self._addTrailingKnobs() 154 155 self._continueOnError = nuke.Boolean_Knob("continue", "Continue on error") 156 self._continueOnError.setTooltip("Continue on error") 157 self._state.setKnob(self._continueOnError, True) 158 self._continueOnError.setFlag(nuke.STARTLINE) 159 self.addKnob(self._continueOnError) 160 161 self._dialogKnobs = set(beforeKnobs.values()) ^ set(self.knobs().values())162 163165 self._state.save(knob) 166 if (knob == self._frameRange): 167 self._rangeEnum.setValue("custom") 168 self._state.save(self._rangeEnum) 169 self._state.saveValue("customRange", knob.value()) 170 if (knob == self._rangeEnum): 171 self._setFrameRangeFromSource(knob.value()) 172 self._state.save(self._frameRange)173175 if (source == _FRAME_RANGE_INPUT): 176 try: 177 activeInput = nuke.activeViewer().activeInput() 178 self._frameRange.setValue(str(nuke.activeViewer().node().upstreamFrameRange(activeInput))) 179 except: 180 self._frameRange.setValue(str(nuke.root().frameRange())) 181 elif (source == _FRAME_RANGE_GLOBAL): 182 self._frameRange.setValue(str(nuke.root().frameRange())) 183 elif (source == _FRAME_RANGE_CUSTOM): 184 customRange = self._state.getValue("customRange", None) 185 if customRange: 186 self._frameRange.setValue(str(customRange)) 187 else: 188 self._frameRangeFromViewer(*source.split('/'));189191 """Set the framerange knob to have the framerange from the given viewer.""" 192 if frameRange == _FRAME_RANGE_VISIBLE: 193 viewerRange = str(self._viewers[viewer].visibleRange()) 194 else: 195 viewerRange = str(self._viewers[viewer].playbackRange()) 196 self._frameRange.setValue(viewerRange)197199 try: 200 return self._viewSelection.value().split() 201 except AttributeError: 202 # If we didn't add the view selection knob, there should be just the one view. 203 return [nuke.OutputContext().viewname(1)]204 207209 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(',')) 210 views = self._selectedViews() 211 try: 212 nuke.Undo().disable() 213 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value()) 214 except RuntimeError, e: 215 if self._exceptOnError or e.args[0][0:9] != "Cancelled": # TO DO: change this to an exception type 216 raise 217 finally: 218 nuke.Undo().enable()221 deprecatedWarningShown = False 222 shouldShowBGRender = False 223 ShowWarning = True 226 227 230550231 - def __init__(self, 232 dialogState, 233 groupContext, 234 nodeSelection = [], 235 exceptOnError = True, 236 allowFrameServer = True):237 self._allowFrameServer = allowFrameServer 238 ExecuteDialog.__init__(self, dialogState, groupContext, nodeSelection, exceptOnError)239241 if self.isTimelineWrite(): 242 self._timelineRender = nuke.Boolean_Knob("timeline_render", "Render to timeline" ) 243 self._state.setKnob( self._timelineRender, True) 244 self._timelineRender.setFlag(nuke.STARTLINE) 245 self.addKnob(self._timelineRender)246 247249 if not RenderDialog.deprecatedWarningShown: 250 RenderDialog.deprecatedWarningShown = True; 251 nuke.tprint("Render in Background option functionality has been deprecated and replaced with the Frame Server.")252254 # Proxy 255 self._useProxy = nuke.Boolean_Knob("use_proxy", "Use proxy") 256 self._useProxy.setTooltip("Use proxy") 257 self._useProxy.setFlag(nuke.STARTLINE) 258 self._state.setKnob(self._useProxy, nuke.root().proxy()) 259 self.addKnob(self._useProxy) 260 261 self._frameserverRender = nuke.Boolean_Knob("frameserver_render", "Render using frame server") 262 self._frameserverRender.setTooltip("Render using frame server") 263 select_frame_server = nuke.toNode("preferences").knob("RenderWithFrameServer").getValue() 264 self._state.setKnob(self._frameserverRender, select_frame_server) 265 self._frameserverRender.setVisible(self.frameserverRenderAvailable()) 266 self._frameserverRender.setFlag(nuke.STARTLINE) 267 self.addKnob(self._frameserverRender) 268 269 self._bgRender = nuke.Boolean_Knob("bg_render", "Render in background") 270 self._state.setKnob(self._bgRender, False) 271 self._bgRender.setVisible(self.backgroundRenderAvailable()) 272 self._bgRender.setFlag(nuke.STARTLINE) 273 self.addKnob(self._bgRender) 274 275 self._numThreads = nuke.Int_Knob("num_threads", "Thread limit") 276 self._numThreads.setVisible(self.isBackgrounded()) 277 self._state.setKnob(self._numThreads, max(nuke.NUM_CPUS / 2, 1)) 278 self.addKnob(self._numThreads) 279 self._maxMem = nuke.String_Knob("max_memory", "Memory limit") 280 self._state.setKnob(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M") 281 self._maxMem.setVisible(self.isBackgrounded()) 282 self.addKnob(self._maxMem) 283 if self.isBackgrounded(): 284 self._showDeprecatedWarningMessage()285287 #Deprecated 288 return { 289 "maxThreads": self._numThreads.value(), 290 "maxCache": self._maxMem.value() }291293 ExecuteDialog.knobChanged(self, knob) 294 295 timelineRender = False 296 try: 297 timelineRender = self._timelineRender.value() 298 except: 299 pass 300 301 bgRenderVisible = not timelineRender and self.backgroundRenderAvailable() 302 showBGRenderOptions = bgRenderVisible and self.isBackgrounded() 303 self._bgRender.setVisible(bgRenderVisible) 304 self._numThreads.setVisible(showBGRenderOptions) 305 self._maxMem.setVisible(showBGRenderOptions) 306 #if knob changed is the bgRender, set it visible 307 if knob is self._bgRender: 308 self._showDeprecatedWarningMessage() 309 310 311 if timelineRender and self.isTimelineWrite(): 312 self._rangeEnum.setValue( _FRAME_RANGE_GLOBAL ) 313 self._setFrameRangeFromSource(self._rangeEnum.value()) 314 self._rangeEnum.setEnabled( False ) 315 self._frameRange.setEnabled( False ) 316 self._frameserverRender.setVisible(False) 317 self._useProxy.setVisible( False ) 318 self._continueOnError.setVisible( False ) 319 else: 320 self._rangeEnum.setEnabled( True ) 321 self._frameRange.setEnabled( True ) 322 if self._allowFrameServer: 323 self._frameserverRender.setVisible(self.frameserverRenderAvailable()) 324 self._useProxy.setVisible( True ) 325 self._continueOnError.setVisible( True )326 327329 """Return whether the background rendering option is enabled.""" 330 #Deprecated 331 return self._bgRender.value() and self.backgroundRenderAvailable()332 333335 """Return whether the frame server option is enabled.""" 336 return self._frameserverRender.value() and self.frameserverRenderAvailable()337 338340 """Return whether background rendering should be allowed for this render""" 341 return RenderDialog.shouldShowBGRender or self.renderContainsContainers()342 343345 return self._allowFrameServer and not self.renderContainsContainers()346 347349 containerWriteNodes = [] 350 nonContainerWriteNodes = [] 351 #extract mov nodes from the rest 352 for node in nodeSelection: 353 knob = node.knobs().get("file_type",None) 354 if knob: 355 fileType = knob.value() 356 if fileType in ("mov", "mov32", "mov64", "ffmpeg", "mxf"): 357 containerWriteNodes.append(node) 358 else: 359 nonContainerWriteNodes.append(node) 360 return (nonContainerWriteNodes, containerWriteNodes)361 362364 365 if not nuke.env['studio']: 366 return False 367 368 if len(self._nodeSelection) > 1 or len(self._nodeSelection) < 1: 369 return False 370 371 write = self._nodeSelection[0] 372 373 if write == nuke.root(): 374 ## must be a render of all 'write' nodes, this is tricky as there may be other executable nodes apart from write nodes 375 ## lets assume the write nodes are write, writegeo, particlecache, and diskcache 376 377 # there is a bug here however as there may be groups they are executable which will be skipped right now 378 379 writeNodes = nuke.allNodes( 'Write' ) 380 writeNodes.extend( nuke.allNodes( 'WriteGeo') ) 381 writeNodes.extend( nuke.allNodes( 'ParticleCache') ) 382 writeNodes.extend( nuke.allNodes( 'DiskCache') ) 383 384 if len(writeNodes) > 1: 385 return False 386 387 if len(writeNodes) > 0: 388 write = writeNodes[0] 389 390 timelineWriteNode = None 391 392 try: 393 from foundry.frameserver.nuke.workerapplication import GetWriteNode 394 timelineWriteNode = GetWriteNode() 395 except: 396 pass 397 398 if not timelineWriteNode: 399 return False 400 401 if timelineWriteNode.fullName() != write.fullName(): 402 return False 403 404 ## double check that this script is actually in a timeline 405 try: 406 from hiero.ui import isInAnyProject 407 return isInAnyProject( nuke.scriptName() ) 408 except: 409 pass 410 411 return False412414 import datetime 415 now = datetime.datetime.now() 416 timestamp = now.strftime('%H%M_%S.%f_%d-%m-%Y') 417 418 if nuke.env['nc']: 419 nukeExt = ".nknc" 420 else: 421 nukeExt = ".nk" 422 423 wasSaved = False 424 #if file is unsaved 425 if nuke.Root().name() == 'Root': 426 fileName = "%s.%s%s"%(prefix,timestamp, nukeExt) 427 filePath = "/".join([os.environ["NUKE_TEMP_DIR"], fileName]) 428 nuke.scriptSaveToTemp(filePath) 429 wasSaved = True 430 else: 431 originalPath = nuke.scriptName() 432 #if file is saved but not up to date 433 if nuke.Root().modified() == True or forceSaveNew: 434 extensionIndex = originalPath.rfind(nukeExt) 435 noExt = originalPath[:extensionIndex] if extensionIndex>=0 else originalPath 436 head, tail = os.path.split(noExt) 437 fileName = "%s.%s.%s%s"%(prefix,tail,timestamp,nukeExt) 438 filePath = "/".join([head,fileName]) 439 try: 440 nuke.scriptSaveToTemp(filePath) 441 wasSaved = True 442 except RuntimeError: 443 nuke.tprint("Exception when saving script to: %s. Saving to NUKE_TEMP_DIR"%filePath) 444 fileName = originalPath.split()[-1] 445 filePath = "/".join([os.environ["NUKE_TEMP_DIR"], fileName]) 446 nuke.scriptSaveToTemp(filePath) 447 wasSaved = True 448 #if file is saved 449 else: 450 filePath = originalPath 451 return (filePath, wasSaved)452454 nodeSelection = self._nodeSelection 455 nodesToRenderCount= len(nodeSelection) 456 if nodesToRenderCount==1: 457 if nodeSelection[0] == nuke.root(): 458 nodeSelection = nuke.allNodes("Write") 459 nodeSelection.extend(nuke.allNodes("DeepWrite")) 460 return nodeSelection461463 (_, containerNodesToRender) = self.extractContainerNodes(self.getNodeSelection()) 464 if containerNodesToRender: 465 return True 466 return False467469 nodeSelection = self.getNodeSelection() 470 (nodesToRender, containerNodesToRender) = self.extractContainerNodes(nodeSelection) 471 472 #check views and frame pading 473 for node in nodeSelection: 474 path = node["file"].getText() 475 needsPadding = frame_ranges.getRange(0).frames()>1 476 hasPadding = nuke.filename( node, nuke.REPLACE ) != path or node["file_type"].value()=="mov" 477 if needsPadding and not hasPadding: 478 nuke.message("%s cannot be executed for multiple frames."%node.fullName()) 479 return 480 #there's no way to find if writer can write multiple views per file in python 481 needsViews = (len(views)!=1 or views[0] != "main" ) 482 hasViews = path.find("%v")!=-1 or path.find("%V")!=-1 or node["file_type"].value()=="exr" 483 if needsViews and not hasViews: 484 nuke.message("%s cannot be executed for multiple views."%node.fullName()) 485 return 486 487 #if there's any container to be rendered, show a warning, render synchronously later 488 if containerNodesToRender: 489 if RenderDialog.ShowWarning: 490 from PySide2.QtWidgets import (QMessageBox, QCheckBox) 491 message = "It is currently not possible to render container formats using the frame server. Select Continue to render in the current Nuke session.\n\nPlease see the user guide for more information." 492 messageBox = QMessageBox(QMessageBox.Warning, "Warning", message, QMessageBox.Cancel) 493 messageBox.addButton("Continue",QMessageBox.AcceptRole) 494 dontShowCheckBox = QCheckBox("Don't show this message again") 495 dontShowCheckBox.blockSignals(True) 496 messageBox.addButton(dontShowCheckBox, QMessageBox.ResetRole) 497 result = messageBox.exec_() 498 if result != QMessageBox.AcceptRole: 499 return 500 if dontShowCheckBox.isChecked(): 501 RenderDialog.ShowWarning = False 502 503 import hiero.ui.nuke_bridge.FnNsFrameServer as FrameServer 504 sortRenderOrder = lambda w : w.knobs()["render_order"].getValue() 505 if nodesToRender: 506 nodesToRender.sort(key = sortRenderOrder) 507 name, wasSaved = self.saveFileToRender("tmp_unsaved",False) 508 try: 509 for node in nodesToRender: 510 FrameServer.renderFrames( 511 name, 512 frame_ranges, 513 node.fullName(), 514 self._selectedViews()) 515 finally: 516 if wasSaved: 517 os.unlink(name) 518 519 if containerNodesToRender: 520 containerNodesToRender.sort(key = sortRenderOrder) 521 nuke.executeMultiple(containerNodesToRender, frame_ranges, views, continueOnError = self._continueOnError.value())522 523525 ##this will render the full framerange of the script 526 if self.isTimelineWrite() and self._timelineRender.value(): 527 from hiero.ui.nuke_bridge.nukestudio import scriptSaveAndReRender 528 scriptSaveAndReRender() 529 return 530 531 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(',')) 532 views = self._selectedViews() 533 rootProxyMode = nuke.root().proxy() 534 try: 535 nuke.Undo().disable() 536 nuke.root().setProxy(self._useProxy.value()) 537 if self.isFrameserverEnabled(): 538 self.renderToFrameServer(frame_ranges,views) 539 elif self.isBackgrounded(): 540 nuke.executeBackgroundNuke(nuke.EXE_PATH, self._nodeSelection, 541 frame_ranges, views, self._getBackgroundLimits(), continueOnError = self._continueOnError.value()) 542 else: 543 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value()) 544 except RuntimeError, e: 545 if self._exceptOnError or e.args[0][0:9] != "Cancelled": # TO DO: change this to an exception type 546 raise 547 finally: 548 nuke.root().setProxy(rootProxyMode) 549 nuke.Undo().enable()554 5571041559 # Init attributes 560 self._node = node 561 self._takeNodeSettings = takeNodeSettings 562 self._customKnobs = [] 563 564 # init super 565 RenderDialog.__init__(self, dialogState, groupContext) 566 567 # Override the initial frame range value 568 self._state.setKnob(self._rangeEnum, _FRAME_RANGE_INPUT) 569 self._setFrameRangeFromSource(self._rangeEnum.value()) 570 571 if self._takeNodeSettings: 572 self._viewerForSettings.setValue(node.name()) 573 self.knobChanged(self._viewerForSettings)574576 flipbookNames = flipbooking.gFlipbookFactory.getNames() 577 self._flipbookEnum = nuke.Enumeration_Knob( "flipbook", "Flipbook", flipbookNames ) 578 self._flipbookEnum.setTooltip("Select Flipbook Player") 579 defaultFlipbook = nuke.toNode('preferences').knob('defaultFlipbook').getValue() 580 if not defaultFlipbook or not defaultFlipbook in flipbookNames: 581 defaultFlipbook = flipbookNames[0] 582 self._state.setKnob(self._flipbookEnum, defaultFlipbook) 583 self.addKnob( self._flipbookEnum ) 584 585 self._viewerForSettings = nuke.Enumeration_Knob("viewer_settings", "Use Settings From", self._viewers.keys() + [_USE_SETTINGS_FROM_CUSTOM]) 586 self._viewerForSettings.setTooltip("Select your viewer setting for the flipbook") 587 if not self._takeNodeSettings: 588 self._viewerForSettings.setValue(_USE_SETTINGS_FROM_CUSTOM) 589 self.addKnob(self._viewerForSettings)590592 # Region of Interest knobs 593 self._useRoi = nuke.Boolean_Knob("use_roi", "Enable ROI") 594 self._useRoi.setTooltip("Use Region of Interest (ROI)") 595 self._useRoi.setFlag(nuke.STARTLINE) 596 self._state.setKnob(self._useRoi, False) 597 self.addKnob(self._useRoi) 598 self._roi = nuke.BBox_Knob("roi", "Region of Interest") 599 self._state.setKnob(self._roi, (0, 0, 0, 0)) 600 self.addKnob(self._roi) 601 self._roi.setVisible(self._useRoi.value()) 602 603 # Channel knobs 604 self._channels = nuke.Channel_Knob( "channels_knob", "Channels") 605 self._channels.setTooltip("Select channels for the flipbook") 606 if self._node.Class() == "Write": 607 self._channels.setValue(self._node.knob("channels").value()) 608 else: 609 self._state.setKnob(self._channels, "rgba") 610 self._channels.setFlag(nuke.STARTLINE | nuke.NO_CHECKMARKS) 611 self.addKnob( self._channels )612614 # LUT knobs 615 self._luts = nuke.Enumeration_Knob("lut", "LUT", nuke.ViewerProcess.registeredNames()) 616 self._luts.setTooltip("Select LUT for the flipbook") 617 if self._takeNodeSettings: 618 self._state.setKnob(self._luts, self._lutFromViewer(self._viewerForSettings.value())) 619 else: 620 self._state.setKnob(self._luts, self._lutFromViewer()) 621 self.addKnob(self._luts) 622 623 self._burnInLUT = nuke.Boolean_Knob("burnin", "Burn in the LUT") 624 self._burnInLUT.setTooltip("Burn in the LUT") 625 self._state.setKnob(self._burnInLUT, False) 626 self.addKnob(self._burnInLUT) 627 628 # Audio knobs 629 audioList = [] 630 audioList.append( "None" ) 631 for node in nuke.allNodes("AudioRead"): 632 audioList.append( node.name() ) 633 self._audioSource = nuke.Enumeration_Knob( "audio", "Audio", audioList ) 634 self._audioSource.setTooltip("Include audio to flipbook") 635 self._state.setKnob(self._audioSource, audioList[0] ) 636 self.addKnob( self._audioSource ) 637 638 super(FlipbookDialog, self)._addPostKnobs() 639 640 self.flipbookKnobs()641643 try: 644 beforeKnobs = self.knobs() 645 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 646 flipbookToRun.dialogKnobs(self) 647 afterKnobs = self.knobs() 648 self._customKnobs = list(set(beforeKnobs.values()) ^ set(afterKnobs.values())) 649 except NotImplementedError: 650 pass651 654656 oc = nuke.OutputContext() 657 self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())] 658 if (oc.viewcount() > 2): 659 supportedViews = self._selectedFlipbook().capabilities()["maximumViews"] 660 if (int(supportedViews) > 1): 661 self._viewSelection = nuke.MultiView_Knob("views", "Views") 662 else: 663 self._viewSelection = nuke.OneView_Knob("views", "View", self._views) 664 activeView = nuke.activeViewer().view() 665 if activeView == "": 666 activeView = self._views[0] 667 668 # Retrieve previous view selection or default to selecting all available views 669 previousViews = self._state.getValue(self._viewSelection.name(), " ".join(self._views)).split() 670 # Get the intersection of the previous selection and the available views 671 viewsToRestore = set(self._views).intersection(previousViews) 672 if viewsToRestore: 673 self._viewSelection.setValue(" ".join(viewsToRestore)) 674 else: 675 self._viewSelection.setValue(activeView) 676 self.addKnob(self._viewSelection) 677 self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)678 681683 try: 684 if viewerName == "": 685 return nuke.ViewerProcess.node().knob("current").value() 686 else: 687 return nuke.ViewerProcess.node(viewer=viewerName).knob("current").value() 688 except AttributeError: 689 return "None"690692 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._luts693 697699 RenderDialog.knobChanged(self, knob) 700 if (knob == self._viewerForSettings): 701 if self._viewerForSettings.value() != _USE_SETTINGS_FROM_CUSTOM: 702 viewer = self._viewers[self._viewerForSettings.value()] 703 self._setKnobAndStore(self._useRoi, viewer.roiEnabled()) 704 roi = viewer.roi() 705 if roi != None: 706 self._roi.fromDict(roi) 707 self._state.save(self._roi) 708 self._channels.fromScript(viewer.knob("channels").toScript()) 709 self._state.save(self._channels) 710 self._setKnobAndStore(self._useProxy, nuke.root().proxy()) 711 self._frameRangeFromViewer(viewer.name(), _FRAME_RANGE_INOUT) 712 self._state.save(self._frameRange) 713 self._setKnobAndStore(self._rangeEnum, viewer.name() + '/' + _FRAME_RANGE_INOUT) 714 self._roi.setVisible(self._useRoi.value()) 715 self._setKnobAndStore(self._luts, self._lutFromViewer(viewer.name())) 716 elif (knob == self._useRoi): 717 self._roi.setVisible(self._useRoi.value()) 718 elif self._isViewerSettingKnob(knob): 719 self._viewerForSettings.setValue(_USE_SETTINGS_FROM_CUSTOM) 720 self._state.save(self._viewerForSettings) 721 elif knob == self._luts: 722 self._burnInLUT.setEnabled(self._luts.value() != "None") 723 724 if knob == self._flipbookEnum: 725 for k in self._dialogKnobs: 726 self.removeKnob(k) 727 self.removeKnob(self.okButton) 728 self.removeKnob(self.cancelButton) 729 self._customKnobs = [] 730 self._addKnobs() 731 self._makeOkCancelButton() 732 elif knob in self._customKnobs: 733 try: 734 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 735 flipbookToRun.dialogKnobChanged(self, knob) 736 except NotImplementedError: 737 pass738 741743 """Get the path for the temporary files. May be filled in using printf syntax.""" 744 flipbooktmp="" 745 if flipbooktmp == "": 746 try: 747 flipbooktmp = self._selectedFlipbook().cacheDir() 748 except: 749 try: 750 flipbooktmp = os.environ["NUKE_DISK_CACHE"] 751 except: 752 flipbooktmp = nuke.value("preferences.DiskCachePath") 753 754 if len(self._selectedViews()) > 1: 755 flipbookFileNameTemp = "nuke_tmp_flip.%04d.%V." + self._getIntermediateFileType() 756 else: 757 flipbookFileNameTemp = "nuke_tmp_flip.%04d." + self._getIntermediateFileType() 758 flipbooktmpdir = os.path.join(flipbooktmp, "flipbook") 759 if not os.path.exists(flipbooktmpdir): 760 os.mkdir(flipbooktmpdir) 761 762 if not os.path.isdir(flipbooktmpdir): 763 raise RuntimeError("%s already exists and is not a directory, please delete before flipbooking again" % flipbooktmpdir) 764 flipbooktmp = os.path.join(flipbooktmpdir, flipbookFileNameTemp) 765 766 if nuke.env['WIN32']: 767 flipbooktmp = re.sub(r"\\", "/", str(flipbooktmp)) 768 return flipbooktmp769771 if nodeToTest.Class() == "Read" or nodeToTest.Class() == "Write": 772 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 773 flipbookCapabilities = flipbookToRun.capabilities() 774 775 # Check if we can read it in directly.. 776 filePath = nuke.filename(nodeToTest) 777 # There might be a prefix that overrides the extension, if so, this will 778 # confuse the flipbook probably, so just create a render. 779 if ':' in filePath: 780 readerPrefix = filePath.split(':')[0] 781 if len(readerPrefix) > 1: # 1 is a drive letter 782 return True 783 fileExtension = os.path.splitext(filePath)[1].lower()[1:] 784 785 # Check if the flipbook supports the file extension. Allow a wildcard to 786 # indicate 'all files' (such as for the internal flipbook functionality) 787 supportedFileTypes = flipbookCapabilities.get("fileTypes", []) 788 flipbookSupportsFileType = (supportedFileTypes == ["*"]) or (fileExtension in supportedFileTypes) 789 if not flipbookSupportsFileType: 790 return True 791 792 # Not all flipbooks can handle weird channels 793 flipbookSupportsArbitraryChannels = flipbookCapabilities.get("arbitraryChannels", False) 794 if self._channels.value() not in set(["rgb", "rgba", "alpha"]) and not flipbookSupportsArbitraryChannels: 795 return True 796 channelKnob = nodeToTest.knob("channels") 797 if channelKnob != None and channelKnob.value() != self._channels.value(): 798 return True 799 800 ## if flipbook doesn't support roi and the roi option is on we need the intermediate node because we're going to insert a crop 801 if self._useRoi.value() and self._useRoi.enabled(): 802 if not flipbookCapabilities.get("roi", False): 803 return True 804 805 if self._burnInLUT.value() and self._burnInLUT.enabled(): 806 return True 807 808 # Separate view files 809 # TODO Temporary workaround to deal with MediaSource not being aware of 810 # the %V notation for specifiying separate view files. 811 if "%V" in filePath or "%v" in filePath: 812 return True 813 814 return False 815 else: 816 return True817819 """Helper function to get the appropriate colorspace to set on the Write node when burning the 820 viewer color transform into the render.""" 821 822 writeColorspace = None 823 824 lut = self._getLUT() 825 826 # Determine whether we're using original Nuke, rather than OCIO, color management. 827 usingNukeColorspaces = False 828 rootNode = nuke.root() 829 if rootNode: 830 colorManagementKnob = rootNode.knob("colorManagement") 831 if colorManagementKnob: 832 usingNukeColorspaces = (colorManagementKnob.value() == "Nuke") # Note: Must use value() rather than getValue(). 833 834 if usingNukeColorspaces: 835 836 # We're using Nuke colorspace management so the our lut knob will correspond to the appropriate 837 # colorspace name, except for rec1886, which we need to map to Gamma2.4. 838 # If the lut is the special case of None then don't set writeColorspace (to match the original behaviour). 839 # (The rec1886 -> Gamma2.4 mapping matches what's done in register_default_viewer_processes, in 840 # NukeScripts/src/ViewerProcess.py - I suppose we could consider adding something into 841 # nuke/src/Python/PythonObjects/ViewerProcess.cpp to allow the python code to look-up into ViewerProcessMap 842 # so we could parse the registered args to obtain the colorspace but that seems like overkill and not much 843 # less fragile.) 844 if lut == "rec1886": 845 writeColorspace = "Gamma2.4" 846 elif lut != "None": 847 writeColorspace = lut 848 849 else: 850 851 # We're using OCIO color management so we expect our lut string to contain a view name 852 # followed by a single space and a display name in parantheses. 853 # For example, the aces 1.0.1 config has lots of views but all for the display called ACES, 854 # hence here we might get lut set to, for example, 855 # DCDM P3 gamut clip (ACES) 856 # As another example, the spi-vfx config has views for two displays, DCIP3 and sRGB, so we might get 857 # Film (DCIP3) 858 # or 859 # Film (sRGB) 860 # etc. 861 # The nuke-default config has a single display called 'default' so we get lut set to 862 # None (default) 863 # or 864 # sRGB (default) 865 # etc. The nuke-default case is a bit confusing because the _view_ names almost match colorspace names 866 # and also correspond to legacy Nuke colorspace managament options. 867 # 868 # Anyway, what we actually need to return is the actual colorspace the particualr combination of 869 # view and display name map to, as defined in the relevant OCIO config file. 870 871 displayName = "" 872 viewName = "" 873 874 NUKE_LUT_FORMAT = '(.*) \((.*)\)$' 875 matchResult = re.match( NUKE_LUT_FORMAT , lut) 876 if matchResult is not None: 877 878 viewName = matchResult.group(1) 879 displayName = matchResult.group(2) 880 881 if rootNode: 882 writeColorspace = rootNode.getOCIOColorspaceFromViewTransform(displayName, viewName) 883 884 return writeColorspace885 886888 """Create a write node to render out the current node so that output may be used for flipbooking.""" 889 flipbooktmp = self._getIntermediatePath() 890 891 fieldname = "file" 892 if self._useProxy.value(): 893 fieldname = "proxy" 894 895 fixup = nuke.createNode("Group", "tile_color 0xff000000", inpanel = False) 896 with fixup: 897 fixup.setName("Flipbook") 898 inputNode = nuke.createNode("Input", inpanel = False) 899 shuffle = nuke.createNode("Shuffle", inpanel = False) 900 shuffle.knob("in").setValue(self._channels.value()) 901 if self._useRoi.value(): 902 crop = nuke.createNode( "Crop", inpanel = False ) 903 crop['box'].fromScript( self._roi.toScript() ) 904 write = nuke.createNode("Write", fieldname+" {"+flipbooktmp+"}", inpanel = False) 905 write.knob('file_type').setValue(self._getIntermediateFileType()) 906 selectedViews = self._selectedViews() 907 write.knob('views').fromScript(" ".join(selectedViews)) 908 909 if self._getIntermediateFileType() == "exr": 910 write.knob('compression').setValue("B44") 911 # Set the 'heroview' to be the first of the selected views. If we don't 912 # do this then then 'heroview' is by default set to be 1 which may not 913 # be a valid view for this clip. The 'heroview' is used as a fallback if 914 # no view has been set on the reader. This assumes the user has selected 915 # sensible views if they haven't then the write may still fail. 916 if len(selectedViews) > 0: 917 firstView = nuke.OutputContext().viewFromName(selectedViews[0]) 918 write.knob('heroview').setValue(firstView) 919 920 writeColorspace = "" 921 922 if self._burnInLUT.value(): 923 # The user has chosen to burn the viewer transform into the intermedate render so set the colorspace 924 # on the Write node appropriately. 925 writeColorspace = self._getBurninWriteColorspace() 926 else: 927 # The viewer transform is not being burnt into the intermediate render, set the Write node's colorspace 928 # to whatever the current working space is - when reading the file back in the flipbook we'll ssume 929 # the media was written out in the working space. 930 rootNode = nuke.root() 931 if rootNode: 932 workingSpaceKnob = rootNode.knob("workingSpaceLUT") 933 if workingSpaceKnob: 934 writeColorspace = workingSpaceKnob.value() 935 936 if writeColorspace: 937 write.knob('colorspace').setValue(writeColorspace) 938 939 outputNode = nuke.createNode("Output", inpanel = False) 940 #If called on a Viewer connect fixup node to the one immediately above if exists. 941 if self._node.Class() == "Viewer": 942 fixup.setInput(0, self._node.input(int(nuke.knob(self._node.fullName()+".input_number")))) 943 else: 944 fixup.setInput(0, self._node) 945 946 return (fixup, write)947949 return self._luts.value()950952 nukeNode = nuke.toNode( self._audioSource.value() ) 953 ret = "" 954 if nukeNode != None: 955 ret = nukeNode["file"].getEvaluatedValue() 956 957 return ret958960 options = { 961 } 962 963 try: 964 options['pixelAspect'] = float(nuke.value(nodeToFlipbook.name()+".pixel_aspect")) 965 except: 966 pass 967 968 try: 969 f = nodeToFlipbook.format() 970 options['dimensions'] = { 'width' : f.width(), 'height' : f.height() } 971 except: 972 pass 973 974 # LUT 975 if not self._burnInLUT.value(): 976 inputColourspace = "linear" 977 outputColourspace = "linear" 978 # Check if we have a different than linear input 979 if self._node.Class() == "Read" or self._node.Class() == "Write": 980 lut = self._node.knob("colorspace").value() 981 # Might be in the format of "default (foo)", if so, get at "foo". 982 if lut[:7] == "default": 983 lut = lut[9:-1] 984 inputColourspace = lut 985 986 # Check our output 987 lut = self._getLUT() 988 if lut != "None": 989 outputColourspace = lut 990 991 if inputColourspace == outputColourspace: 992 options["lut"] = inputColourspace 993 else: 994 options["lut"] = inputColourspace + "-" + outputColourspace 995 # AUDIO 996 audioTrack = self._getAudio() 997 if audioTrack != "": 998 options["audio"] = audioTrack 999 1000 # ROI 1001 if self._useRoi.value(): 1002 roi = self._roi.toDict() 1003 if (roi["r"] - roi["x"] > 0) and (roi["t"] - roi["y"] > 0): 1004 options["roi"] = bboxToTopLeft(int(nuke.value(nodeToFlipbook.name()+".actual_format.height")), roi) 1005 1006 1007 return options10081010 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 1011 if (flipbookToRun): 1012 if not os.access(flipbookToRun.path(), os.X_OK): 1013 raise RuntimeError("%s cannot be executed (%s)." % (flipbookToRun.name(), flipbookToRun.path(),) ) 1014 1015 nodeToFlipbook = None 1016 rootProxyMode = nuke.root().proxy() 1017 try: 1018 # Need this to prevent Bug 5295 1019 nuke.Undo().disable() 1020 nuke.root().setProxy(self._useProxy.value()) 1021 1022 calledOnNode = self._node 1023 if self._node.Class() == "Viewer": 1024 self._node = self._node.input(int(self._node.knob("input_number").value())) 1025 1026 renderer = getFlipbookRenderer(self, flipbookToRun) 1027 renderer.doFlipbook() 1028 1029 except Exception, e: 1030 import traceback 1031 traceback.print_exc(file=sys.stdout) 1032 print "exception ",e 1033 finally: 1034 #if an intermediate node was created, delete it 1035 if self._node != renderer._nodeToFlipbook: 1036 nuke.delete(renderer._nodeToFlipbook) 1037 nuke.root().setProxy(rootProxyMode) 1038 nuke.Undo().enable() 1039 else: 1040 raise RuntimeError("No flipbook called " + self._flipbookEnum.value() + " found. Was it deregistered while the dialog was open?")1045 104811291050 1051 # init super 1052 FlipbookDialog.__init__(self, dialogState, groupContext, node, True) 1053 self._frameserverRender.setVisible(False) 1054 self._bgRender.setVisible(False) 1055 self._useProxy.setVisible(False) 1056 self._continueOnError.setVisible(False) 1057 1058 self._viewerForSettings.setVisible(False) 1059 1060 self._useRoi.setVisible(False) 1061 self._roi.setVisible(False) 1062 1063 self._channels.setVisible(False) 1064 self._luts.setVisible(False) 1065 1066 self._audioSource.setVisible(False) 1067 self._burnInLUT.setVisible(False) 1068 1069 try: 1070 ## this may not exist, just ignore if not present 1071 self._viewSelection.setVisible(False) 1072 except: 1073 pass 1074 1075 customWriteActive = node['file'].getValue() != self._getIntermediatePath() and node['file'].getValue() != '' 1076 self._customWrite = nuke.Boolean_Knob( 'custom', 'Customise write path' ) 1077 self._customWrite.setValue( customWriteActive ) 1078 self.addKnob( self._customWrite ) 1079 1080 self._noFlipbook = nuke.Boolean_Knob( 'write', 'No flipbook' ) 1081 self._noFlipbook.setFlag( nuke.STARTLINE ) 1082 self._noFlipbook.setVisible( customWriteActive ) 1083 self._noFlipbook.setValue( self._state.get( self._noFlipbook, False ) ) 1084 self.addKnob( self._noFlipbook ) 1085 1086 self._file = nuke.File_Knob( 'file', 'Write path' ) 1087 defaultPath = self._node['file'].value() 1088 if defaultPath == self._getIntermediatePath(): 1089 defaultPath = '' 1090 self._file.setValue ( self._state.get(self._file, defaultPath ) ) 1091 self._file.setVisible( customWriteActive ) 1092 1093 self.addKnob( self._file )10941096 try: 1097 FlipbookDialog.knobChanged(self, knob) 1098 self._frameserverRender.setVisible(False) 1099 if (knob == self._customWrite): 1100 self._noFlipbook.setVisible( self._customWrite.value() ) 1101 self._file.setVisible( self._customWrite.value() ) 1102 if ( not self._customWrite.value() ): 1103 self._node['file'].setValue( self._getIntermediatePath() ) 1104 elif( knob == self._noFlipbook ): 1105 self._flipbookEnum.setEnabled( not self._noFlipbook.value() ) 1106 except: 1107 pass1108 11111113 """ Return an instance of a CaptureViewer class, which when executed captures the viewer. 1114 """ 1115 flipbook = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value()) 1116 if flipbook and not os.access(flipbook.path(), os.X_OK): 1117 raise RuntimeError("%s cannot be executed (%s)." % (flipbook.name(), flipbook.path(),) ) 1118 1119 # build up the args 1120 frameRange = self._frameRange.value() 1121 viewer = self._node 1122 selectedViews = self._selectedViews() 1123 defaultWritePath = self._getIntermediatePath() 1124 customWritePath = self._file.value() if self._customWrite.value() else "" 1125 doFlipbook = not self._noFlipbook.value() 1126 doCleanup = False 1127 1128 return captureViewer.CaptureViewer(flipbook, frameRange, viewer, selectedViews, defaultWritePath, customWritePath, doFlipbook, doCleanup)1131 """ Shows the with showModalDialog() and then calls dialog.run() if it returns True """ 1132 # If there is a viewer playing, stop it, it interferes with updating knobs on the dialog 1133 if nuke.activeViewer(): 1134 nuke.activeViewer().stop() 1135 1136 if (dialog.showModalDialog() == True): 1137 dialog.run()1138 1140 """Present a dialog that executes the given list of nodes.""" 1141 groupContext = nuke.root() 1142 d = ExecuteDialog(_gRenderDialogState, groupContext, nodesToExecute, exceptOnError) 1143 _showDialog(d) 11441146 """Present a dialog that renders the given list of nodes.""" 1147 groupContext = nuke.root() 1148 d = RenderDialog(_gRenderDialogState, groupContext, nodesToRender, exceptOnError, allowFrameServer) 1149 _showDialog(d)11501152 """Returns the flipbook dialog object created when flipbooking node""" 1153 if node is None: 1154 raise RuntimeError("Can't launch flipbook, require a node."); 1155 if node.Class() == "Viewer" and node.inputs() == 0: 1156 raise RuntimeError("Can't launch flipbook, there is nothing connected to the viewed input."); 1157 1158 if not (nuke.canCreateNode("Write")): 1159 nuke.message("Flipbooking is not permitted in Nuke Assist") 1160 return 1161 1162 groupContext = nuke.root() 1163 1164 e = FlipbookDialog(_gFlipbookDialogState, groupContext, node, takeNodeSettings) 1165 return e11661168 """Present a dialog that flipbooks the given node.""" 1169 e = _getFlipbookDialog( node, takeNodeSettings ) 1170 _showDialog(e)1171 1172 # because the capture button could have been triggered via a progress bar in update_handles 1173 # we defer the capture run until the main event loop is pumped117811821180 ## only runs the dialog capture function when we are outside update_handles 1181 utils.executeInMainThreadWithResult( self.captureViewer, )1184 if node is None: 1185 raise RuntimeError("Can't launch flipbook, requires a viewer node."); 1186 if node.Class() != "Viewer" and node.inputs() == 0: 1187 raise RuntimeError("Can't launch flipbook, this is not a viewer node."); 1188 1189 if not (nuke.canCreateNode("Write")): 1190 nuke.message("Viewer capture is not permitted in Nuke Assist") 1191 return 1192 1193 groupContext = nuke.root() 1194 e = ViewerCaptureDialog(_gViewerCaptureDialogState, groupContext, node) 1195 if (e.showModalDialog() == True): 1196 # Bug 38516 - Be careful about what gets passed to the ViewerCaptureDialogThread, since anything 1197 # created here will be destroyed in a different thread. This can cause problems, such as crashes, 1198 # if a Qt widget gets passed. 1199 captureViewer = e.captureViewer() 1200 thread = ViewerCaptureDialogThread(captureViewer) 1201 thread.start()12021204 """Present a dialog that flipbooks the currently selected node.""" 1205 try: 1206 showFlipbookDialog(nuke.selectedNode()) 1207 except ValueError, ve: 1208 raise RuntimeError("Can't launch flipbook, %s." % (ve.args[0]))12091211 """Convert the roi passed from a origin at the bottom left to the top left. 1212 Also replaces the r and t keys with w and h keys. 1213 @param height: the height used to determine the top. 1214 @param roi: the roi with a bottom left origin, must have x, y, r & t keys. 1215 @result dict with x, y, w & h keys""" 1216 topLeftRoi = { 1217 "x": roi["x"], 1218 "y": height - roi["y"] - (roi["t"] - roi["y"]), 1219 "w": roi["r"] - roi["x"], 1220 "h": roi["t"] - roi["y"] } 1221 return topLeftRoi12221224 """ 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.""" 1225 _gRenderDialogState.saveValue(name, value)12261228 """ 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.""" 1229 _gFlipbookDialogState.saveValue(name, value)1230
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Fri Feb 14 13:53:19 2020 | http://epydoc.sourceforge.net |