C++ API Reference
viewRenderOverride/viewRenderOverride.cpp
//-
// Copyright 2015 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license agreement
// provided at the time of installation or download, or which otherwise
// accompanies this software in either electronic or hard copy form.
//+
#include <stdio.h>
#include <maya/MString.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MRenderTargetManager.h>
#include "viewRenderOverride.h"
/*
Sample custom render override class.
By default the plugin will perform a number of operations
in order to:
1) Draw a procedurally generated background
2) Draw the non-UI parts of the scene
3) Threshold the scene
4) Blur the thresholded output
5) Combine the thresholded output with the original scene (resulting
in a "glow")
6) Draw the UI parts of the scene.
7) Draw the 2D HUD
8) 'Present' the final output
A number of intermediate render targets are created to hold contents
which are passed from operation to operation.
*/
/*
Constructor
*/
viewRenderOverride::viewRenderOverride( const MString & name )
: MRenderOverride( name )
// This is the UI name which will appear in the "Renderer" menu
// in a 3D viewport panel. Any valid ascii string name can be
// used here.
, mUIName("Sample VP2 Renderer Override")
, mRendererChangeCB(0)
, mRenderOverrideChangeCB(0)
{
for (unsigned int i=0; i<kNumberOfOps; i++)
mRenderOperations[i] = NULL;
mCurrentOperation = -1;
// Init target information for the override
unsigned int sampleCount = 1; // no multi-sampling
// There are 3 render targets used for the entire override:
// 1. Color
// 2. Depth
// 3. Intermediate target to perform target blurs
//
mTargetOverrideNames[kMyColorTarget] = MString("__viewRenderOverrideCustomColorTarget__");
mTargetDescriptions [kMyColorTarget] = new MHWRender::MRenderTargetDescription(mTargetOverrideNames[kMyColorTarget], 256, 256, sampleCount, colorFormat, 0, false);
mTargets [kMyColorTarget] = NULL;
mTargetSupportsSRGBWrite[kMyColorTarget] = false;
mTargetOverrideNames[kMyDepthTarget] = MString("__viewRenderOverrideCustomDepthTarget__");
mTargetDescriptions [kMyDepthTarget] = new MHWRender::MRenderTargetDescription(mTargetOverrideNames[kMyDepthTarget], 256, 256, sampleCount, depthFormat, 0, false);
mTargets [kMyDepthTarget] = NULL;
mTargetSupportsSRGBWrite[kMyDepthTarget] = false;
mTargetOverrideNames[kMyBlurTarget] = MString("__viewRenderOverrideBlurTarget__");
mTargetDescriptions [kMyBlurTarget]= new MHWRender::MRenderTargetDescription(mTargetOverrideNames[kMyBlurTarget], 256, 256, sampleCount, colorFormat, 0, false);
mTargets [kMyBlurTarget] = NULL;
mTargetSupportsSRGBWrite[kMyBlurTarget] = false;
// Set to true to split UI and non-UI draw
mSplitUIDraw = false;
// For debugging
mDebugOverride = false;
// Default do full effects
mSimpleRendering = false;
mPanelName.clear();
}
/*
Destructor. Make sure to clean up any resources allocated for this override
*/
viewRenderOverride::~viewRenderOverride()
{
const MHWRender::MRenderTargetManager* targetManager = theRenderer ? theRenderer->getRenderTargetManager() : NULL;
// Delete any targets created
for(unsigned int targetId = 0; targetId < kTargetCount; ++targetId)
{
if (mTargetDescriptions[targetId])
{
delete mTargetDescriptions[targetId];
mTargetDescriptions[targetId] = NULL;
}
if (mTargets[targetId])
{
if (targetManager)
{
targetManager->releaseRenderTarget(mTargets[targetId]);
}
mTargets[targetId] = NULL;
}
}
cleanup();
// Delete all the operations. This will release any
// references to other resources user per operation
//
for (unsigned int i=0; i<kNumberOfOps; i++)
{
if (mRenderOperations[i])
{
delete mRenderOperations[i];
mRenderOperations[i] = NULL;
}
}
// Clean up callbacks
//
if (mRendererChangeCB)
{
MMessage::removeCallback(mRendererChangeCB);
}
if (mRenderOverrideChangeCB)
{
MMessage::removeCallback(mRenderOverrideChangeCB);
}
}
/*
Return that this plugin supports both GL and DX draw APIs
*/
viewRenderOverride::supportedDrawAPIs() const
{
}
/*
Initialize "iterator". We keep a list of operations indexed
by mCurrentOperation. Set to 0 to point to the first operation.
*/
bool
viewRenderOverride::startOperationIterator()
{
mCurrentOperation = 0;
return true;
}
/*
Return an operation indicated by mCurrentOperation
*/
viewRenderOverride::renderOperation()
{
if (mCurrentOperation >= 0 && mCurrentOperation < kNumberOfOps)
{
while(!mRenderOperations[mCurrentOperation])
{
mCurrentOperation++;
if (mCurrentOperation >= kNumberOfOps)
{
return NULL;
}
}
if (mRenderOperations[mCurrentOperation])
{
if (mDebugOverride)
{
printf("\t%s : Queue render operation[%d] = (%s)\n",
mName.asChar(),
mCurrentOperation,
mRenderOperations[mCurrentOperation]->name().asChar());
}
return mRenderOperations[mCurrentOperation];
}
}
return NULL;
}
/*
Advance "iterator" to next operation
*/
bool
viewRenderOverride::nextRenderOperation()
{
mCurrentOperation++;
if (mCurrentOperation < kNumberOfOps)
{
return true;
}
return false;
}
/*
Update the render targets that are required for the entire override.
References to these targets are set on the individual operations as
required so that they will send their output to the appropriate location.
*/
bool viewRenderOverride::updateRenderTargets()
{
if (mDebugOverride)
{
printf("\t%s : Set output render target overrides: color=%s, depth=%s\n",
mName.asChar(),
mTargetDescriptions[0]->name().asChar(), mTargetDescriptions[1]->name().asChar());
}
// Get the current output target size as specified by the
// renderer. If it has changed then the targets need to be
// resized to match.
unsigned int targetWidth = 0;
unsigned int targetHeight = 0;
if( theRenderer )
{
theRenderer->outputTargetSize( targetWidth, targetHeight );
}
if (mTargetDescriptions[0]->width() != targetWidth ||
mTargetDescriptions[1]->height() != targetHeight)
{
// A resize occured
}
// Note that the render target sizes could be set to be
// smaller than the size used by the renderer. In this case
// a final present will generally stretch the output.
// Update size value for all target descriptions kept
for(unsigned int targetId = 0; targetId < kTargetCount; ++targetId)
{
mTargetDescriptions[targetId]->setWidth( targetWidth );
mTargetDescriptions[targetId]->setHeight( targetHeight );
}
// Keep track of whether the main color target can support sRGB write
bool colorTargetSupportsSGRBWrite = false;
// Uncomment this to debug if targets support sRGB write.
static const bool sDebugSRGBWrite = false;
// Enable to testing unordered write access
static const bool testUnorderedWriteAccess = false;
// Either acquire a new target if it didn't exist before, resize
// the current target.
const MHWRender::MRenderTargetManager *targetManager = theRenderer ? theRenderer->getRenderTargetManager() : NULL;
if (targetManager)
{
if (sDebugSRGBWrite)
{
if ( theRenderer->drawAPI() != MHWRender::kOpenGL)
{
// Sample code to scan all available targetgs for sRGB write support
for (unsigned int i=0; i<MHWRender::kNumberOfRasterFormats; i++)
{
printf("Format %d supports SRGBwrite\n", i);
}
}
}
for(unsigned int targetId = 0; targetId < kTargetCount; ++targetId)
{
// Check to see if the format supports sRGB write.
// Set unordered write access flag if test enabled.
bool supportsSRGBWrite = false;
if ( theRenderer->drawAPI() != MHWRender::kOpenGL)
{
mTargetSupportsSRGBWrite[targetId] = supportsSRGBWrite =
targetManager->formatSupportsSRGBWrite( mTargetDescriptions[targetId]->rasterFormat() );
}
mTargetDescriptions[targetId]->setAllowsUnorderedAccess( testUnorderedWriteAccess );
// Keep track of whether the main color target can support sRGB write
if (targetId == kMyColorTarget)
colorTargetSupportsSGRBWrite = supportsSRGBWrite;
if (sDebugSRGBWrite)
{
if (targetId == kMyColorTarget || targetId == kMyBlurTarget)
{
printf("Color target %d supports sRGB write = %d\n", targetId, supportsSRGBWrite );
}
// This would be expected to fail.
if (targetId == kMyDepthTarget)
{
printf("Depth target supports sRGB write = %d\n", supportsSRGBWrite );
}
}
// Create a new target
if (!mTargets[targetId])
{
mTargets[targetId] = targetManager->acquireRenderTarget( *( mTargetDescriptions[targetId]) );
}
// "Update" using a description will resize as necessary
else
{
mTargets[targetId]->updateDescription( *( mTargetDescriptions[targetId]) );
}
if (testUnorderedWriteAccess && mTargets[targetId])
{
(mTargets[targetId])->targetDescription(returnDesc);
mTargetDescriptions[targetId]->setAllowsUnorderedAccess( returnDesc.allowsUnorderedAccess() );
printf("Acquire target[%s] with unordered access = %d. Should fail if attempting with depth target = %d\n",
returnDesc.name().asChar(), returnDesc.allowsUnorderedAccess(),
targetId == kMyDepthTarget);
}
}
}
// Update the render targets on the individual operations
//
// Set the targets on the operations. For simplicity just
// passing over the set of all targets used for the frame
// to each operation.
//
viewRenderQuadRender *quadOp = (viewRenderQuadRender *)mRenderOperations[kBackgroundBlit];
if (quadOp)
quadOp->setRenderTargets(mTargets);
viewRenderSceneRender *sceneOp = (viewRenderSceneRender *)mRenderOperations[kMaya3dSceneRender];
if (sceneOp)
{
sceneOp->setRenderTargets(mTargets);
sceneOp->setEnableSRGBWriteFlag( colorTargetSupportsSGRBWrite );
}
viewRenderSceneRender *opaqueSceneOp = (viewRenderSceneRender *)mRenderOperations[kMaya3dSceneRenderOpaque];
if (opaqueSceneOp)
{
opaqueSceneOp->setRenderTargets(mTargets);
opaqueSceneOp->setEnableSRGBWriteFlag( colorTargetSupportsSGRBWrite );
}
viewRenderSceneRender *transparentSceneOp = (viewRenderSceneRender *)mRenderOperations[kMaya3dSceneRenderTransparent];
if (transparentSceneOp)
{
transparentSceneOp->setRenderTargets(mTargets);
transparentSceneOp->setEnableSRGBWriteFlag( colorTargetSupportsSGRBWrite );
}
viewRenderSceneRender *uiSceneOp = (viewRenderSceneRender *)mRenderOperations[kMaya3dSceneRenderUI];
if (uiSceneOp)
{
uiSceneOp->setRenderTargets(mTargets);
uiSceneOp->setEnableSRGBWriteFlag( false ); // Don't enable sRGB write for UI
}
viewRenderQuadRender *quadOp2 = (viewRenderQuadRender *)mRenderOperations[kPostOperation1];
if (quadOp2)
quadOp2->setRenderTargets(mTargets);
viewRenderQuadRender *quadOp3 = (viewRenderQuadRender *)mRenderOperations[kPostOperation2];
if (quadOp3)
quadOp3->setRenderTargets(mTargets);
viewRenderUserOperation *userOp = (viewRenderUserOperation *) mRenderOperations[kUserOpNumber];
if (userOp)
{
userOp->setRenderTargets(mTargets);
userOp->setEnableSRGBWriteFlag( colorTargetSupportsSGRBWrite ); // Enable sRGB write for user ops
}
viewRenderPresentTarget *presentOp = (viewRenderPresentTarget *) mRenderOperations[kPresentOp];
if (presentOp)
presentOp->setRenderTargets(mTargets);
viewRenderQuadRender *thresholdOp = (viewRenderQuadRender *)mRenderOperations[kThresholdOp];
if (thresholdOp)
thresholdOp->setRenderTargets(mTargets);
viewRenderQuadRender *horizBlur = (viewRenderQuadRender *)mRenderOperations[kHorizBlurOp];
if (horizBlur)
horizBlur->setRenderTargets(mTargets);
viewRenderQuadRender *vertBlur = (viewRenderQuadRender *)mRenderOperations[kVertBlurOp];
if (vertBlur)
vertBlur->setRenderTargets(mTargets);
viewRenderQuadRender *blendOp = (viewRenderQuadRender *)mRenderOperations[kBlendOp];
if (blendOp)
blendOp->setRenderTargets(mTargets);
viewRenderHUDOperation *hudOp = (viewRenderHUDOperation *)mRenderOperations[kHUDBlit];
if (hudOp)
hudOp->setRenderTargets(mTargets);
return (mTargets[kMyColorTarget] && mTargets[kMyDepthTarget] && mTargets[kMyBlurTarget]);
}
/*
"Setup" will be called for each frame update.
Here we set up the render loop logic and allocate any necessary resources.
The render loop logic setup is done by setting up a list of
render operations which will be returned by the "iterator" calls.
*/
viewRenderOverride::setup( const MString & destination )
{
if (mDebugOverride)
{
printf("%s : Perform setup with panel [%s]\n",
mName.asChar(), destination.asChar() );
}
// As an example, we keep track of the active 3d viewport panel
// if any exists. This information is passed to the operations
// in case they require accessing the current 3d view (M3dView).
mPanelName.set( destination.asChar() );
// Track changes to the renderer and override for this viewport (nothing
// will be printed unless mDebugOverride is true)
if (!mRendererChangeCB)
{
mRendererChangeCB = MUiMessage::add3dViewRendererChangedCallback(destination, sRendererChangeFunc, (void*)mDebugOverride);
}
if (!mRenderOverrideChangeCB)
{
mRenderOverrideChangeCB = MUiMessage::add3dViewRenderOverrideChangedCallback(destination, sRenderOverrideChangeFunc, (void*)mDebugOverride);
}
if (mRenderOperations[kPresentOp] == NULL)
{
// Sample of a "simple" render loop.
// "Simple" means a scene draw + HUD + present to viewport
if (mSimpleRendering)
{
mSplitUIDraw = false;
mRenderOperations[kBackgroundBlit] = NULL;
mRenderOperationNames[kMaya3dSceneRender] = "__MySimpleSceneRender";
simpleViewRenderSceneRender *sceneOp = new simpleViewRenderSceneRender( mRenderOperationNames[kMaya3dSceneRender] );
mRenderOperations[kMaya3dSceneRender] = sceneOp;
// NULL out any additional opertions used for the "complex" render looop
mRenderOperations[kMaya3dSceneRenderOpaque] = NULL;
mRenderOperations[kMaya3dSceneRenderTransparent] = NULL;
mRenderOperations[kThresholdOp] = NULL;
mRenderOperations[kHorizBlurOp] = NULL;
mRenderOperations[kVertBlurOp] = NULL;
mRenderOperations[kPostOperation1] = NULL;
mRenderOperations[kPostOperation2] = NULL;
mRenderOperations[kMaya3dSceneRenderUI] = NULL;
mRenderOperations[kUserOpNumber] = NULL;
mRenderOperations[kHUDBlit] = new viewRenderHUDOperation();
mRenderOperationNames[kHUDBlit] = (mRenderOperations[kHUDBlit])->name();
mRenderOperationNames[kPresentOp] = "__MyPresentTarget";
mRenderOperations[kPresentOp] = new viewRenderPresentTarget( mRenderOperationNames[kPresentOp] );
mRenderOperationNames[kPresentOp] = (mRenderOperations[kPresentOp])->name();
}
// Sample which performs the full "complex" render loop
//
else
{
rect[0] = 0.0f;
rect[1] = 0.0f;
rect[2] = 1.0f;
rect[3] = 1.0f;
// Pre scene quad render to render a procedurally drawn background
//
mRenderOperationNames[kBackgroundBlit] = "__MyPreQuadRender";
viewRenderQuadRender *quadOp = new viewRenderQuadRender( mRenderOperationNames[kBackgroundBlit] );
quadOp->setShader( viewRenderQuadRender::kPre_MandelBrot ); // We use a shader override to render the background
quadOp->setViewRectangle(rect);
mRenderOperations[kBackgroundBlit] = quadOp;
// Set up scene draw operations
//
// This flag indicates that we wish to split up the scene draw into
// opaque, transparent, and UI passes.
//
// When we don't split up the UI from the opaque and transparent,
// the UI will have the "glow" effect applied to it. Instead
// splitting up will allow the UI to draw after the "glow" effect
// has been applied.
//
mSplitUIDraw = true;
mRenderOperations[kMaya3dSceneRender] = NULL;
mRenderOperations[kMaya3dSceneRenderOpaque] = NULL;
mRenderOperations[kMaya3dSceneRenderTransparent] = NULL;
mRenderOperations[kMaya3dSceneRenderUI] = NULL;
if (mSplitUIDraw)
{
// opaque
viewRenderSceneRender* sceneOp = NULL;
static const bool sDrawOpaque = true; // can disable if desired
if (sDrawOpaque)
{
mRenderOperationNames[kMaya3dSceneRenderOpaque] = "__MyStdSceneRenderOpaque";
sceneOp = new viewRenderSceneRender(
mRenderOperationNames[kMaya3dSceneRenderOpaque],
sceneOp->setViewRectangle(rect);
mRenderOperations[kMaya3dSceneRenderOpaque] = sceneOp;
}
// transparent, clear nothing since needs to draw on top of opaque
static const bool sDrawTransparent = true; // can disable if desired
if (sDrawTransparent)
{
mRenderOperationNames[kMaya3dSceneRenderTransparent] = "__MyStdSceneRenderTransparent";
sceneOp = new viewRenderSceneRender(
mRenderOperationNames[kMaya3dSceneRenderTransparent],
sDrawOpaque
sceneOp->setViewRectangle(rect);
mRenderOperations[kMaya3dSceneRenderTransparent] = sceneOp;
}
// ui, don't clear depth since we need it for drawing ui correctly
mRenderOperationNames[kMaya3dSceneRenderUI] = "__MyStdSceneRenderUI";
sceneOp = new viewRenderSceneRender(
mRenderOperationNames[kMaya3dSceneRenderUI],
MHWRender::MSceneRender::kRenderUIItems,
sDrawOpaque || sDrawTransparent
sceneOp->setViewRectangle(rect);
mRenderOperations[kMaya3dSceneRenderUI] = sceneOp;
}
else
{
// will draw all of opaque, transparent and ui at once
mRenderOperationNames[kMaya3dSceneRender] = "__MyStdSceneRender";
viewRenderSceneRender* sceneOp = new viewRenderSceneRender(
mRenderOperationNames[kMaya3dSceneRender],
MHWRender::MSceneRender::kNoSceneFilterOverride,
sceneOp->setViewRectangle(rect);
mRenderOperations[kMaya3dSceneRender] = sceneOp;
}
// Set up operations which will perform a threshold and a blur on the thresholded
// render target. Also included is an operation to blend the non-UI scene
// render target with the output of this set of operations (thresholded blurred scene)
//
mRenderOperationNames[kThresholdOp] = "__ThresholdColor";
viewRenderQuadRender *quadThreshold = new viewRenderQuadRender( mRenderOperationNames[kThresholdOp] );
quadThreshold->setShader( viewRenderQuadRender::kScene_Threshold ); // Use threshold shader
quadThreshold->setViewRectangle(rect);
mRenderOperations[kThresholdOp] = quadThreshold;
mRenderOperationNames[kHorizBlurOp] = "__HorizontalBlur";
viewRenderQuadRender *quadHBlur = new viewRenderQuadRender( mRenderOperationNames[kHorizBlurOp] );
quadHBlur->setShader( viewRenderQuadRender::kScene_BlurHoriz ); // Use horizontal blur shader
quadHBlur->setViewRectangle(rect);
mRenderOperations[kHorizBlurOp] = quadHBlur;
mRenderOperationNames[kVertBlurOp] = "__VerticalBlur";
viewRenderQuadRender *quadVBlur = new viewRenderQuadRender( mRenderOperationNames[kVertBlurOp] );
quadVBlur->setShader( viewRenderQuadRender::kScene_BlurVert ); // Use vertical blur shader
quadVBlur->setViewRectangle(rect);
mRenderOperations[kVertBlurOp] = quadVBlur;
mRenderOperationNames[kBlendOp] = "__SceneBlurBlend";
viewRenderQuadRender *quadBlend = new viewRenderQuadRender( mRenderOperationNames[kBlendOp] );
quadBlend->setShader( viewRenderQuadRender::kSceneBlur_Blend ); // Use color blend shader
quadBlend->setViewRectangle(rect);
mRenderOperations[kBlendOp] = quadBlend;
// Sample custom operation which will peform a custom "scene render"
//
mRenderOperationNames[kUserOpNumber] = "__MyCustomSceneRender";
viewRenderUserOperation *userOp = new viewRenderUserOperation( mRenderOperationNames[kUserOpNumber] );
userOp->setViewRectangle(rect);
mRenderOperations[kUserOpNumber] = userOp;
bool wantPostQuadOps = false;
// Some sample post scene quad render operations
// a. Monochrome quad render with custom shader
mRenderOperationNames[kPostOperation1] = "__PostOperation1";
viewRenderQuadRender *quadOp2 = new viewRenderQuadRender( mRenderOperationNames[kPostOperation1] );
quadOp2->setShader( viewRenderQuadRender::kPost_EffectMonochrome );
quadOp2->setViewRectangle(rect);
if (wantPostQuadOps)
mRenderOperations[kPostOperation1] = quadOp2;
else
mRenderOperations[kPostOperation1] = NULL;
// b. Invert quad render with custom shader
mRenderOperationNames[kPostOperation2] = "__PostOperation2";
viewRenderQuadRender *quadOp3 = new viewRenderQuadRender( mRenderOperationNames[kPostOperation2] );
quadOp3->setShader( viewRenderQuadRender::kPost_EffectInvert );
quadOp3->setViewRectangle(rect);
if (wantPostQuadOps)
mRenderOperations[kPostOperation2] = quadOp3;
else
mRenderOperations[kPostOperation2] = NULL;
// "Present" opertion which will display the target for viewports.
// Operation is a no-op for batch rendering as there is no on-screen
// buffer to send the result to.
mRenderOperationNames[kPresentOp] = "__MyPresentTarget";
mRenderOperations[kPresentOp] = new viewRenderPresentTarget( mRenderOperationNames[kPresentOp] );
mRenderOperationNames[kPresentOp] = (mRenderOperations[kPresentOp])->name();
// A preset 2D HUD render operation
mRenderOperations[kHUDBlit] = new viewRenderHUDOperation();
mRenderOperationNames[kHUDBlit] = (mRenderOperations[kHUDBlit])->name();
}
}
bool gotTargets = true;
if (!mSimpleRendering)
{
// Update any of the render targets which will be required
gotTargets = updateRenderTargets();
// Set the name of the panel on operations which may use the panel
// name to find out the associated M3dView.
if (mRenderOperations[kMaya3dSceneRender])
((viewRenderSceneRender * )mRenderOperations[kMaya3dSceneRender])->setPanelName( mPanelName );
if (mRenderOperations[kMaya3dSceneRenderOpaque])
((viewRenderSceneRender * )mRenderOperations[kMaya3dSceneRenderOpaque])->setPanelName( mPanelName );
if (mRenderOperations[kMaya3dSceneRenderTransparent])
((viewRenderSceneRender * )mRenderOperations[kMaya3dSceneRenderTransparent])->setPanelName( mPanelName );
if (mRenderOperations[kMaya3dSceneRenderUI])
((viewRenderSceneRender * )mRenderOperations[kMaya3dSceneRenderUI])->setPanelName( mPanelName );
if (mRenderOperations[kUserOpNumber])
((viewRenderUserOperation *)mRenderOperations[kUserOpNumber])->setPanelName( mPanelName );
}
mCurrentOperation = -1;
return (gotTargets ? MStatus::kSuccess : MStatus::kFailure );
}
/*
End of frame cleanup. For now just clears out any data on operations which may
change from frame to frame (render target, output panel name etc)
*/
viewRenderOverride::cleanup()
{
if (mDebugOverride)
{
printf("%s : Perform cleanup. panelname=%s\n", mName.asChar(), mPanelName.asChar());
}
viewRenderQuadRender *quadOp = (viewRenderQuadRender *) mRenderOperations[kPostOperation1];
if (quadOp)
{
quadOp->setRenderTargets(NULL);
}
quadOp = (viewRenderQuadRender *) mRenderOperations[kPostOperation2];
if (quadOp)
{
quadOp->setRenderTargets(NULL);
}
// Reset the active view
mPanelName.clear();
// Reset current operation
mCurrentOperation = -1;
}
// Callback for tracking renderer changes
void viewRenderOverride::sRendererChangeFunc(
const MString& panelName,
const MString& oldRenderer,
const MString& newRenderer,
void* clientData)
{
if (clientData)
{
printf("Renderer changed for panel '%s'. New renderer is '%s', old was '%s'.\n",
panelName.asChar(), newRenderer.asChar(), oldRenderer.asChar());
}
}
// Callback for tracking render override changes
void viewRenderOverride::sRenderOverrideChangeFunc(
const MString& panelName,
const MString& oldOverride,
const MString& newOverride,
void* clientData)
{
if (clientData)
{
printf("Render override changed for panel '%s'. New override is '%s', old was '%s'.\n",
panelName.asChar(), newOverride.asChar(), oldOverride.asChar());
}
}