import maya.api.OpenMaya as om # necessary because new api doesn't have iterators import maya.OpenMaya as oldOm import maya.api.OpenMayaRender as omr import maya.api.OpenMayaAnim as oma import maya.api.OpenMayaUI as omui import pymel.core as pm import os import inspect import traceback import collections """ This code is a render override for displaying onion skin overlays in the 3D viewport, which i will refer to as onions in further comments. It uses render targets to store the rendered onions. Unfortunately as of now it doesn't interactively update the onions on the fly. Instead it just saves the onion of the current frame and displays a saved onion from a different frame if available. Since I am not really a programmer and I think it helps understanding the code, further comments will follow a story: You are a little kid preparing a vegetable plate for your Mom. Your Mom, which I will refer to as M, sometimes wants you to show her certain onions from these veggies. You have to manage a sequence of these onions, and if requested display a certain number of them """ """ Constants When M is so unhappy with your work that it refuses it, start here to see whats wrong """ kDebugAll = False kDebugRenderOverride = False kDebugSceneRender = False kDebugQuadRender = False kPluginName = "Onion Skin Renderer" """ Tell M that you are using the new tools """ def maya_useNewAPI(): pass """ Initialize the plugin This tells M your name and that you are available for work """ # globally available instance of renderer viewRenderOverrideInstance = None # init def initializeOverride(): if kDebugAll: print 'initialize Renderer' try: # register the path to the plugin omr.MRenderer.getShaderManager().addShaderPath(os.path.dirname(os.path.abspath(inspect.stack()[0][1]))) global viewRenderOverrideInstance viewRenderOverrideInstance = viewRenderOverride("onionSkinRenderer") viewRenderOverrideInstance.createCallbacks() omr.MRenderer.registerOverride(viewRenderOverrideInstance) except Exception as e: traceback.print_exc() raise Exception("Failed to register plugin %s" %kPluginName) # un-init def uninitializeOverride(): if kDebugAll: print 'unitiliazide Renderer' try: global viewRenderOverrideInstance if viewRenderOverrideInstance is not None: omr.MRenderer.deregisterOverride(viewRenderOverrideInstance) viewRenderOverrideInstance.deleteCallbacks() viewRenderOverrideInstance = None except Exception as e: traceback.print_exc() raise Exception("Failed to unregister plugin %s" % kPluginName) """ If M requires your help, you start your work here. This is a custom vegetable preparation workstation, but fortunately you didn't need to create it from scratch. It basically extends the standard workstation, but modifies it for onion management. In the workstation there is a sequence of onions, which are labeled with numbers that correspond to a certain place in time """ class viewRenderOverride(omr.MRenderOverride): # constructor def __init__(self, name): if kDebugAll or kDebugRenderOverride: print ("Initializing viewRenderOverride") #omr.MRenderOverride.__init__(self, name) super(viewRenderOverride, self).__init__(name) # name in the renderer dropdown menu self.mUIName = kPluginName # everytime you are preparing a plate, # you have to count which step you are on # this is reset when you start a new plate self.mOperation = 0 # label for the onion # current frame, used for setting the onion target key self.mCurrentFrame = 0 # holds all avaialable onions # the key to the target is its frame number self.mOnionBuffer = {} # save the order in which onions where added self.mOnionBufferQueue = collections.deque() # max buffer size self.mMaxOnionBufferSize = 200 # sometimes M doesn't want to see onions, # thats when this should be False self.mEnableBlend = False # save the relative Onions self.mRelativeOnions = {} # only display every nth relative onion self.mRelativeStep = 1 # save the absolute onions self.mAbsoluteOnions = {} # buffer onion objects to make adding sets possible self.mOnionObjectBuffer = om.MSelectionList() # save all the objects to display in a list self.mOnionObjectList = om.MSelectionList() # store the render operations that combine onions in a list self.mRenderOperations = [] # the tints for onions self.mRelativeFutureTint = [255,0,0] self.mRelativePastTint = [0,255,0] self.mAbsoluteTint = [0,0,255] # tint strengths, 1 is full tint self.mRelativeTintStrength = 1.0 self.mAbsoluteTintStrength = 1.0 self.mGlobalOpacity = 1.0 # If this is True, we will show onions on the next keyticks # e.g. if mRelativeOnions has 1 and 3 in it, it will draw # the next and the 3rd frame with a tick on the timeslider self.mRelativeKeyDisplay = True self.mCallbackId = 0 self.mCameraMovedCallbackIds = [] self.mAutoClearBuffer = True # Passes self.mStandardPass = viewRenderSceneRender( "standardPass", omr.MClearOperation.kClearAll ) self.mRenderOperations.append(self.mStandardPass) self.mOnionPass = viewRenderSceneRender( "onionPass", omr.MClearOperation.kClearAll ) self.mOnionPass.setSceneFilter(omr.MSceneRender.kRenderShadedItems) self.mOnionPass.setDrawSelectionFilter(True) self.mRenderOperations.append(self.mOnionPass) self.mHUDPass = viewRenderHUDRender() self.mRenderOperations.append(self.mHUDPass) self.mPresentTarget = viewRenderPresentTarget("presentTarget") self.mRenderOperations.append(self.mPresentTarget) # TARGETS # standard target is what will be displayed. all but onion render to this target self.mStandardTargetDescr = omr.MRenderTargetDescription() self.mStandardTargetDescr.setName("standardTarget") self.mStandardTargetDescr.setRasterFormat(omr.MRenderer.kR8G8B8A8_UNORM) # onion target will be blended over standard target self.mOnionTargetDescr = omr.MRenderTargetDescription() self.mOnionTargetDescr.setName("onionTarget") self.mOnionTargetDescr.setRasterFormat(omr.MRenderer.kR8G8B8A8_UNORM) # Set the targets that don't change self.mTargetMgr = omr.MRenderer.getRenderTargetManager() self.mStandardTarget = self.mTargetMgr.acquireRenderTarget(self.mStandardTargetDescr) self.mStandardPass.setRenderTarget(self.mStandardTarget) self.mHUDPass.setRenderTarget(self.mStandardTarget) self.mPresentTarget.setRenderTarget(self.mStandardTarget) # destructor def __del__(self): if kDebugAll or kDebugRenderOverride: print ("Deleting viewRenderOverride") self.mStandardPass = None self.mHUDPass = None self.mPresentTarget = None self.mRenderOperations = None # delete the targets, otherwise the target manager might # return None when asked for a target that already exists self.rotOnions() self.mTargetMgr.releaseRenderTarget(self.mStandardTarget) self.mTargetMgr = None self.mOnionObjectList = None self.mAnim = None # ----------------- # RENDER FUNCTIONS # specify that only openGl is supported. But it doesn't do anything def supportedDrawAPIs(self): return omr.MRenderer.kAllDevices # before sorting veggies on your plate, prepare your workspace def setup(self, destination): if kDebugAll or kDebugRenderOverride: print ("Starting setup") # set the size of the target, so when the viewport scales, # the targets remain a 1:1 pixel size targetSize = omr.MRenderer.outputTargetSize() self.mStandardTargetDescr.setWidth(targetSize[0]) self.mStandardTargetDescr.setHeight(targetSize[1]) self.mOnionTargetDescr.setWidth(targetSize[0]) self.mOnionTargetDescr.setHeight(targetSize[1]) # update the standard target to the just set size self.mStandardTarget.updateDescription(self.mStandardTargetDescr) # update the onion target to a new name, because targetMgr will return None # if the name already exists self.mCurrentFrame = oma.MAnimControl.currentTime().value onionTargetName = "onionTarget%s" % self.mCurrentFrame self.mOnionTargetDescr.setName(onionTargetName) # if the onion is not buffered do so, otherwise update the buffered if self.mCurrentFrame not in self.mOnionBuffer: self.mOnionBuffer[self.mCurrentFrame] = self.mTargetMgr.acquireRenderTarget(self.mOnionTargetDescr) self.mOnionBufferQueue.append(self.mCurrentFrame) if len(self.mOnionBufferQueue) > self.mMaxOnionBufferSize: self.rotOldestOnion() else: self.mOnionBuffer.get(self.mCurrentFrame).updateDescription(self.mOnionTargetDescr) # then set the render target to the appropriate onion self.mOnionPass.setRenderTarget(self.mOnionBuffer.get(self.mCurrentFrame)) # set the filter list to the onion renderer self.mOnionPass.setObjectFilterList(self.mOnionObjectList) # setting targets to relative blend passes for blend in self.mRelativeOnions: blendPass = self.mRelativeOnions[blend] targetFrame = 1 if self.mRelativeKeyDisplay: targetFrame = blendPass.mFrame else: targetFrame = blendPass.mFrame * self.mRelativeStep + self.mCurrentFrame if targetFrame in self.mOnionBuffer: if not self.mRelativeKeyDisplay: blendPass.setActive(True) blendPass.setInputTargets(self.mStandardTarget, self.mOnionBuffer[targetFrame]) # future tint if targetFrame > self.mCurrentFrame: blendPass.setTint(( (self.mRelativeFutureTint[0]/255.0) / self.lerp(1.0, self.mRelativeFutureTint[0]/255.0, self.mRelativeTintStrength), self.mRelativeFutureTint[1]/255.0 / self.lerp(1.0, self.mRelativeFutureTint[1]/255.0, self.mRelativeTintStrength), self.mRelativeFutureTint[2]/255.0 / self.lerp(1.0, self.mRelativeFutureTint[2]/255.0, self.mRelativeTintStrength), 1.0)) # past tint else: blendPass.setTint(( self.mRelativePastTint[0]/255.0 / self.lerp(1.0, self.mRelativePastTint[0]/255.0, self.mRelativeTintStrength), self.mRelativePastTint[1]/255.0 / self.lerp(1.0, self.mRelativePastTint[1]/255.0, self.mRelativeTintStrength), self.mRelativePastTint[2]/255.0 / self.lerp(1.0, self.mRelativePastTint[2]/255.0, self.mRelativeTintStrength), 1.0)) else: #pass blendPass.setActive(False) # setting targets to absolute blendPasses for blend in self.mAbsoluteOnions: blendPass = self.mAbsoluteOnions[blend] if blendPass.mFrame in self.mOnionBuffer: blendPass.setActive(True) blendPass.setInputTargets(self.mStandardTarget, self.mOnionBuffer[blendPass.mFrame]) blendPass.setTint(( self.mAbsoluteTint[0]/255.0 / self.lerp(1.0, self.mAbsoluteTint[0]/255.0, self.mAbsoluteTintStrength), self.mAbsoluteTint[1]/255.0 / self.lerp(1.0, self.mAbsoluteTint[1]/255.0, self.mAbsoluteTintStrength), self.mAbsoluteTint[2]/255.0 / self.lerp(1.0, self.mAbsoluteTint[2]/255.0, self.mAbsoluteTintStrength) )) else: blendPass.setActive(False) # called by maya to start iterating through passes def startOperationIterator(self): self.mOperation = 0 return True # called by maya to define which pass to calculate # the order specified here defines the draw order def renderOperation(self): return self.mRenderOperations[self.mOperation] # advance to the next pass or return false if # all are calculated def nextRenderOperation(self): self.mOperation = self.mOperation + 1 return self.mOperation < len(self.mRenderOperations) # ----------------- # UTILITY FUNCTIONS # reducing code duplicates by merging both add onion functions def addOnion(self, frame, opacity, targetDict): if frame not in targetDict: targetDict[frame] = viewRenderQuadRender( 'blendPass%s' % frame, omr.MClearOperation.kClearNone, int(frame) ) targetDict[frame].setOpacity(opacity/100.0) targetDict[frame].setShader(viewRenderQuadRender.kSceneBlend) targetDict[frame].setRenderTarget(self.mStandardTarget) # insert operation after onion pass self.mRenderOperations.insert( self.mRenderOperations.index(self.mOnionPass) + 1, targetDict[frame] ) omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # called by absolute and relative remove def removeOnion(self, frame, targetDict): if frame in targetDict: renderPass = targetDict.pop(frame, None) self.mRenderOperations.remove(renderPass) omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # called by maya. Sets the name in the "Renderers" dropdown def uiName(self): return self.mUIName # def rotOnions(self, refresh = True): if self.mTargetMgr is not None: for target in self.mOnionBuffer: self.mTargetMgr.releaseRenderTarget(self.mOnionBuffer.get(target)) self.mOnionBuffer.clear() self.mOnionBufferQueue.clear() if refresh: omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def rotOldestOnion(self): frame = self.mOnionBufferQueue.popleft() if self.mTargetMgr is not None: self.mTargetMgr.releaseRenderTarget(self.mOnionBuffer[frame]) self.mOnionBuffer.pop(frame) # def lerp(self, start, end, factor): if factor < 1 and factor > 0: return (factor * start) + ((1-factor) * end) else: return start # change the frame display to the right keys def setRelativeFrames(self, value): if not self.mRelativeKeyDisplay: return nextKeys = [] pastKeys = [] nextKey = pm.findKeyframe(ts=True, w="next") pastKey = pm.findKeyframe(ts=True, w="previous") # add next keys to list bufferKey = pm.getCurrentTime() for i in range(4): if nextKey <= bufferKey: break nextKeys.append(nextKey) bufferKey = nextKey nextKey = pm.findKeyframe(t=bufferKey, ts=True, w="next") # add prev keys to list bufferKey = pm.getCurrentTime() for i in range(4): if pastKey >= bufferKey: break pastKeys.append(pastKey) bufferKey = pastKey pastKey = pm.findKeyframe(t=bufferKey, ts=True, w="previous") pastKeys = list(reversed(pastKeys)) for frameIndex in self.mRelativeOnions: blendPass = self.mRelativeOnions[frameIndex] if frameIndex < 0: # past if pastKeys and len(pastKeys) >= frameIndex*-1: blendPass.setActive(True) blendPass.setFrame(pastKeys[frameIndex]) else: blendPass.setActive(False) else: # future if nextKeys and len(nextKeys) >= frameIndex: blendPass.setActive(True) blendPass.setFrame(nextKeys[frameIndex-1]) else: blendPass.setActive(False) # def flattenSelectionList(self, selList): flatList = om.MSelectionList() selIter = om.MItSelectionList(selList) while not selIter.isDone(): obj = selIter.getDependNode() # if its a DAG node if selIter.itemType() == 0: if selIter.hasComponents(): flatList.add(selIter.getComponent()) # just add it to the list if it's a dag object elif obj.hasFn(om.MFn.kDagNode): flatList.add(selIter.getDagPath()) # if its a set recursive call with set contents elif obj.hasFn(om.MFn.kSet): flatList.merge(self.flattenSelectionList(om.MFnSet(obj).getMembers(False))) selIter.next() return flatList # attached to all cameras found on plugin launch, removes onions when the camera moves # but only on user input. animated cameras are not affected def cameraMovedCB(self, msg, plug1, plug2, payload): if (msg == 2056 and self.mAutoClearBuffer and (self.isPlugInteresting(plug1, 'translate') or self.isPlugInteresting(plug1, 'rotate'))): self.rotOnions(False) # checks if the plug matches the given string def isPlugInteresting(self, plug, targetPlug): mfn_dep = oldOm.MFnDependencyNode(plug.node()) return plug == mfn_dep.findPlug(targetPlug, True) # ---------------- # INTERFACE FUNCTIONS # add a frame to display relative to current time slider position def addRelativeOnion(self, frame, opacity): self.addOnion(int(frame), opacity, self.mRelativeOnions) # def removeRelativeOnion(self, frame): self.removeOnion(int(frame), self.mRelativeOnions) def setRelativeKeyDisplay(self, value): self.mRelativeKeyDisplay = value if value: self.setRelativeFrames(1) else: for frameIndex in self.mRelativeOnions: blendPass = self.mRelativeOnions[frameIndex] blendPass.setFrame(frameIndex) omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # add a frame that is always displayed on the current position def addAbsoluteOnion(self, frame, opacity): self.addOnion(int(frame), opacity, self.mAbsoluteOnions) # def removeAbsoluteOnion(self, frame): self.removeOnion(int(frame), self.mAbsoluteOnions) # def clearAbsoluteOnions(self): for onion in self.mAbsoluteOnions: self.mRenderOperations.remove(self.mAbsoluteOnions[onion]) self.mAbsoluteOnions.clear() omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def absoluteOnionExists(self, frame): return frame in self.mAbsoluteOnions # def getAbsoluteOpacity(self, frame): if frame in self.mAbsoluteOnions: return self.mAbsoluteOnions[frame].mOpacity * 100 return 50 # def setTint(self, rgba, target): if target == 'relative_futureTint_btn': self.mRelativeFutureTint = rgba elif target == 'relative_pastTint_btn': self.mRelativePastTint = rgba elif target == 'absolute_tint_btn': self.mAbsoluteTint = rgba omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def setRelativeTintStrength(self, strength): self.mRelativeTintStrength = strength / 100.0 omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def setAbsoluteTintStrength(self, strength): self.mAbsoluteTintStrength = strength / 100.0 omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def setRelativeOpacity(self, frame, opacity): if int(frame) in self.mRelativeOnions: self.mRelativeOnions[int(frame)].setOpacity(opacity/100.0) omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) def setGlobalOpacity(self, opacity): self.mGlobalOpacity = opacity/100.0 omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def setAbsoluteOpacity(self, frame, opacity): if frame in self.mAbsoluteOnions: self.mAbsoluteOnions[frame].setOpacity(opacity/100.0) omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # adding objects to the selectionList # works recursively if a set is found def addSelectedOnion(self): selList = om.MGlobal.getActiveSelectionList() if not selList.isEmpty(): self.mOnionObjectBuffer.merge(selList) self.mOnionObjectList = self.flattenSelectionList(self.mOnionObjectBuffer) self.rotOnions() # def removeSelectedOnion(self): selList = om.MGlobal.getActiveSelectionList() if not selList.isEmpty(): self.mOnionObjectBuffer.merge(selList, om.MSelectionList.kRemoveFromList) self.mOnionObjectList = self.flattenSelectionList(self.mOnionObjectBuffer) self.rotOnions() # def removeOnionObject(self, dagPath): tmpList = om.MSelectionList() tmpList.add(dagPath) self.mOnionObjectBuffer.merge(tmpList, om.MSelectionList.kRemoveFromList) self.mOnionObjectList = self.flattenSelectionList(self.mOnionObjectBuffer) self.rotOnions() # def clearOnionObjects(self): self.mOnionObjectList = om.MSelectionList() self.mOnionObjectBuffer = om.MSelectionList() self.rotOnions() # adding callbacks to the scene def createCallbacks(self): # frame changed callback # needed for changing the relative keyframe display self.mTimeCallbackId = om.MEventMessage.addEventCallback('timeChanged', self.setRelativeFrames) # iterate over all cameras add the callback # using old api because new doesn't include iterator over dep nodes dgit = oldOm.MItDependencyNodes(oldOm.MFn.kCamera) while not dgit.isDone(): t = oldOm.MFnDagNode(dgit.thisNode()).parent(0) if t is not None: self.mCameraMovedCallbackIds.append( oldOm.MNodeMessage.addAttributeChangedCallback(t, self.cameraMovedCB)) dgit.next() # removing them when the ui is closed def deleteCallbacks(self): om.MEventMessage.removeCallback(self.mTimeCallbackId) for id in self.mCameraMovedCallbackIds: oldOm.MMessage.removeCallback(id) self.mCameraMovedCallbackIds = [] # define if the buffer should be cleared when the camera moves def setAutoClearBuffer(self, value): self.mAutoClearBuffer = value # def setMaxBuffer(self, value): self.mMaxOnionBufferSize = value while len(self.mOnionBufferQueue) > self.mMaxOnionBufferSize: self.rotOldestOnion() omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) # def getMaxBuffer(self): return self.mMaxOnionBufferSize # def setRelativeStep(self, value): self.mRelativeStep = value omui.M3dView.refresh(omui.M3dView.active3dView(), all=True) """ This is the main tool of your workstation. In your workstation, you have TWO versions of that tool. The first version displays the ENTIRE vegetable heap. The second version ONLY displays the onions in that heap. It's like a super cool xRay to show your M how neatly you arranged those onions """ class viewRenderSceneRender(omr.MSceneRender): def __init__(self, name, clearMask): if kDebugAll or kDebugSceneRender: print ("Initializing viewRenderSceneRender") omr.MSceneRender.__init__(self, name) self.mClearMask = clearMask self.mPanelName = "" self.mDrawSelectionFilter = False self.mOnionObjectList = om.MSelectionList() self.mTarget = None self.mSceneFilter = omr.MSceneRender.kNoSceneFilterOverride def __del__(self): if kDebugAll or kDebugSceneRender: print ("Deleting viewRenderSceneRender") self.mSelectionList = None self.mTarget = None # draw only selected objects if mDrawSelectionFilter is True def objectSetOverride(self): if self.mDrawSelectionFilter: return self.mOnionObjectList return None # called from viewRenderOverride which manages the list def setObjectFilterList(self, selectionList): self.mOnionObjectList = selectionList # sets the clear mask def clearOperation(self): # setOverridesColors(False) doesn't work in 2016 bg = pm.general.displayRGBColor('background', q=True) self.mClearOperation.setClearColor((bg[0], bg[1], bg[2], 0.0)) self.mClearOperation.setMask(self.mClearMask) return self.mClearOperation # allows setting the draw selection filter which will only # draw selected objects def setDrawSelectionFilter(self, flag): self.mDrawSelectionFilter = flag def setRenderTarget(self, target): self.mTarget = target def targetOverrideList(self): if self.mTarget is not None: if kDebugAll or kDebugSceneRender: print ("Returning target %s" % self.mTarget) return [self.mTarget] return None def setSceneFilter(self, filter): self.mSceneFilter = filter def renderFilterOverride(self): return self.mSceneFilter """ M doesn't want to see only onions, but also the surrounding veggies. With this tool, you can combine displays so you can show them at the same time """ class viewRenderQuadRender(omr.MQuadRender): kEffectNone = 0 kSceneBlend = 1 kFileExtension = { omr.MRenderer.kOpenGL:'.cgfx', omr.MRenderer.kOpenGLCoreProfile: '.ogsfx', omr.MRenderer.kDirectX11: '.fx' } def __init__(self, name, clearMask, frame): if kDebugAll or kDebugQuadRender: print ("Initializing viewRenderQuadRender") omr.MQuadRender.__init__(self, name) self.mShaderInstance = None self.mClearMask = clearMask self.mTarget = None self.mInputTarget = [None, None] self.mShader = self.kEffectNone self.mFrame = frame self.mActive = True self.mTint = [1,1,1,1] self.mOpacity = 0.5 def __del__(self): if kDebugAll or kDebugQuadRender: print ("Deleting viewRenderQuadRender") if self.mShaderInstance is not None: shaderMgr = omr.MRenderer.getShaderManager() if shaderMgr is not None: shaderMgr.releaseShader(self.mShaderInstance) self.mShaderInstance = None self.mTarget = None self.mInputTarget = None def shader(self): if kDebugAll or kDebugQuadRender: print ("Setting up shader") if not self.mActive: return None if self.mShaderInstance is None: shaderMgr = omr.MRenderer.getShaderManager() if self.mShader == self.kSceneBlend: self.mShaderInstance = shaderMgr.getEffectsFileShader( "onionSkinShader%s"%self.kFileExtension[omr.MRenderer.drawAPI()], "Main", useEffectCache = not kDebugQuadRender ) if self.mShaderInstance is not None: if kDebugAll or kDebugQuadRender: print ("Blend target 1: %s" % self.mInputTarget[0]) print ("Blend target 2: %s" % self.mInputTarget[1]) self.mShaderInstance.setParameter("gSourceTex", self.mInputTarget[0]) self.mShaderInstance.setParameter("gSourceTex2", self.mInputTarget[1]) self.mShaderInstance.setParameter("gBlendSrc", self.mOpacity*viewRenderOverrideInstance.mGlobalOpacity) self.mShaderInstance.setParameter("gTint", self.mTint) return self.mShaderInstance def targetOverrideList(self): if self.mTarget is not None: return [self.mTarget] return None def setRenderTarget(self, target): self.mTarget = target def clearOperation(self): self.mClearOperation.setMask(self.mClearMask) return self.mClearOperation def setShader(self, shader): self.mShader = shader def setInputTargets(self, target1, target2): self.mInputTarget[0] = target1 self.mInputTarget[1] = target2 def setActive(self, flag): self.mActive = flag def setTint(self, tint): self.mTint = tint def setOpacity(self, opacity): self.mOpacity = opacity def setFrame(self, frame): self.mFrame = frame """ Adding the last fancy doodads to your plate """ class viewRenderHUDRender(omr.MHUDRender): def __init__(self): omr.MHUDRender.__init__(self) self.mTarget = None def __del__(self): self.mTarget = None def targetOverrideList(self): if self.mTarget is not None: return [self.mTarget] return None def setRenderTarget(self, target): self.mTarget = target """ Turn around and hope M is happy with the result """ class viewRenderPresentTarget(omr.MPresentTarget): def __init__(self, name): omr.MPresentTarget.__init__(self, name) self.mTarget = None def __del__(self): self.mTarget = None def targetOverrideList(self): if self.mTarget is not None: if kDebugAll: print ("Returning present target: %s" % self.mTarget) return [self.mTarget] return None def setRenderTarget(self, target): self.mTarget = target