diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp index dde4c93c8b..87bb796045 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp @@ -112,7 +112,6 @@ void DataProducerSceneIndexDataBase::_CreateSceneIndexChainForDataProducerSceneI HdSceneIndexBaseRefPtr DataProducerSceneIndexDataBase::_CreateUsdStageSceneIndexChain(HdSceneIndexBaseRefPtr const & inputStageSceneIndex) { _CreateSceneIndexChainForDataProducerSceneIndexWithDCCNode(inputStageSceneIndex); - UpdateHydraTransformFromParentPath();//Update the transform, this is useful when deleting the node and undoing it return _lastSceneIndexChain; } @@ -136,6 +135,7 @@ void DataProducerSceneIndexDataBase::_CreateSceneIndexChainForDataProducerSceneI { _rootOverridesSceneIndex = UsdImagingRootOverridesSceneIndex::New(inputSceneIndex); _lastSceneIndexChain = _rootOverridesSceneIndex; + UpdateHydraTransformFromParentPath();//Update the transform, this is useful when deleting the node and undoing it } void DataProducerSceneIndexDataBase::_CreateSceneIndexChainForDataProducerSceneIndexWithoutDCCNode(HdSceneIndexBaseRefPtr const & inputSceneIndex) diff --git a/lib/mayaHydra/flowViewportAPIExamples/CMakeLists.txt b/lib/mayaHydra/flowViewportAPIExamples/CMakeLists.txt index f05a524afd..6acc46c69a 100644 --- a/lib/mayaHydra/flowViewportAPIExamples/CMakeLists.txt +++ b/lib/mayaHydra/flowViewportAPIExamples/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(flowViewportAPIMayaLocator) +add_subdirectory(flowViewportAPILocator) diff --git a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/CMakeLists.txt similarity index 97% rename from lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt rename to lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/CMakeLists.txt index 1f93f3e196..fe55272271 100644 --- a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt +++ b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/CMakeLists.txt @@ -1,4 +1,4 @@ -set(TARGET_NAME flowViewportAPIMayaLocator) +set(TARGET_NAME mayaHydraFlowViewportAPILocator) add_library(${TARGET_NAME} SHARED) @@ -7,7 +7,7 @@ add_library(${TARGET_NAME} SHARED) # ----------------------------------------------------------------------------- target_sources(${TARGET_NAME} PRIVATE - flowViewportAPIMayaLocator.cpp + mhFlowViewportAPILocator.cpp ) set(HEADERS diff --git a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/mhFlowViewportAPILocator.cpp similarity index 67% rename from lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp rename to lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/mhFlowViewportAPILocator.cpp index d5cf868ab9..a0bacb4833 100644 --- a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp +++ b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPILocator/mhFlowViewportAPILocator.cpp @@ -38,22 +38,32 @@ #include #include #include - +#include +#include +#include +#include //We use a locator node to deal with creating and filtering hydra primitives as an example. //But you could use another kind of maya plugin. /*To create an instance of this node in maya, please use the following MEL command : -createNode("FlowViewportAPIMayaLocator") +createNode("MhFlowViewportAPILocator") */ +namespace { +void nodeAddedToModel(MObject& node, void* clientData); +void nodeRemovedFromModel(MObject& node, void* clientData); +} + PXR_NAMESPACE_USING_DIRECTIVE ///Maya Locator node subclass to create filtering and data producer scene indices example, to be used with the flow viewport API. -class FlowViewportAPIMayaLocator : public MPxLocatorNode +class MhFlowViewportAPILocator : public MPxLocatorNode { public: - ~FlowViewportAPIMayaLocator() override; + ~MhFlowViewportAPILocator() override; + + void postConstructor() override; MStatus compute( const MPlug& plug, MDataBlock& data ) override; @@ -63,8 +73,7 @@ class FlowViewportAPIMayaLocator : public MPxLocatorNode MStatus preEvaluation(const MDGContext& context, const MEvaluationNode& evaluationNode) override; void getCacheSetup(const MEvaluationNode& evalNode, MNodeCacheDisablingInfo& disablingInfo, MNodeCacheSetupInfo& cacheSetupInfo, MObjectArray& monitoredAttributes) const override; - void SetCubeGridParametersFromAttributes(); - void SetupFlowViewportInterfaces(); + void setCubeGridParametersFromAttributes(); //static members static void* creator(); @@ -82,82 +91,41 @@ class FlowViewportAPIMayaLocator : public MPxLocatorNode static MObject mCubeOpacity; static MObject mCubesUseInstancing; static MObject mCubesDeltaTrans; - static MObject mDummyInput;//Dummy input to trigger a call to compute - static MObject mDummyOutput;//Dummy output to trigger a call to compute ///3D Grid of cube mesh primitives creation parameters for the data producer scene index Fvp::DataProducerSceneIndexExample::CubeGridCreationParams _cubeGridParams; ///_hydraViewportDataProducerSceneIndexExample is what will inject the 3D grid of Hydra cube mesh primitives into the viewport Fvp::DataProducerSceneIndexExample _hydraViewportDataProducerSceneIndexExample; + // Callback when the footprint node is added to the model (create / + // undo-delete) + void addedToModelCb(); + // Callback when the footprint node is removed from model (delete) + void removedFromModelCb(); + protected: /// _hydraViewportFilteringSceneIndexClientExample is the filtering scene index example for a Hydra viewport scene index. std::shared_ptr _hydraViewportFilteringSceneIndexClientExample; /// _hydraViewportInformationClient is the viewport information example for a Hydra viewport. std::shared_ptr _hydraViewportInformationClient; ///To be used in hydra viewport API to pass the Maya node's MObject for setting callbacks for filtering and data producer scene indices - MObject _thisMObject; - ///To check if the MObject of this node has changed - MObject _oldMObject; + MObjectHandle _thisMObject; ///To hold the attributeChangedCallback Id to be able to react when the 3D grid creation parameters attributes from this node change. - MCallbackId _cbAttributeChangedId = 0; + MCallbackId _cbAttributeChangedId {0}; ///To hold the afterOpenCallback Id to be able to react when a File Open has happened. - MCallbackId _cbAfterOpenId = 0; - ///To hold the transformAttributeChangedCallback Id to be able to react when the transform matrix has changed. - MCallbackId _cbParentAttributeChangedId; - + MCallbackId _cbAfterOpenId {0}; + /// to hold the nodeAddedToModel callback id + MCallbackId _nodeAddedToModelCbId{0}; + /// to hold the nodeRemovedFromModel callback id + MCallbackId _nodeRemovedFromModelCbId{0}; + private: - // Private Constructor - FlowViewportAPIMayaLocator(); - /// Init flag to be able to do things only once for this node - bool _init = false; + /// Private Constructor + MhFlowViewportAPILocator() {} }; namespace { - //Get node inverse transform matrix (needed by instancing in a dataProducerSceneIndex) - MStatus GetNodeInverseTransform(MObject& mObj, GfMatrix4d& outInvTransform) - { - outInvTransform = outInvTransform.SetIdentity(); - - MStatus stat; - - //Try directly if the mObj is a transform node - MObject nodeToGetTransform = mObj; - if ( ! mObj.hasFn(MFn::kTransform)){ - //Try with the parent dag path from that node - MDagPath dagPath = MDagPath::getAPathTo(mObj, &stat); - CHECK_MSTATUS(stat); - dagPath.pop(); - nodeToGetTransform = dagPath.node(); - if ( ! nodeToGetTransform.hasFn(MFn::kTransform)){ - return MStatus::kInvalidParameter;//Stopping here - } - } - - MFnTransform transform(nodeToGetTransform, &stat); - CHECK_MSTATUS(stat); - if (MStatus::kSuccess != stat){ - return MStatus::kFailure; - } - - MMatrix transformMatrix = transform.transformationMatrix(&stat); - CHECK_MSTATUS(stat); - if (MStatus::kSuccess != stat){ - return MStatus::kFailure; - } - - MMatrix invTransform = transformMatrix.inverse(); - memcpy(outInvTransform.GetArray(), invTransform[0], sizeof(double) * 16);//convert from MMatrix to GfMatrix4d - - return MStatus::kSuccess; - } - - //Callback when an attribute of this Maya node changes - void transformAttributeChangedCallback(MNodeMessage::AttributeMessage msg, MPlug& plug, MPlug & otherPlug, void* dataProducerSceneIndexData) - { - } - //Callback when an attribute of this Maya node changes void attributeChangedCallback(MNodeMessage::AttributeMessage msg, MPlug& plug, MPlug & otherPlug, void* dataProducerSceneIndexData) { @@ -165,13 +133,9 @@ namespace return; } - FlowViewportAPIMayaLocator* flowViewportAPIMayaLocator = reinterpret_cast(dataProducerSceneIndexData); + MhFlowViewportAPILocator* flowViewportAPIMayaLocator = reinterpret_cast(dataProducerSceneIndexData); MPlug parentPlug = plug.parent(); - if (plug == flowViewportAPIMayaLocator->mDummyInput || plug == flowViewportAPIMayaLocator->mDummyOutput){ - return; //These attributes are not related to the cubes grid - } - if (plug == flowViewportAPIMayaLocator->mNumCubeLevelsX){ flowViewportAPIMayaLocator->_cubeGridParams._numLevelsX = plug.asInt(); }else @@ -263,47 +227,49 @@ namespace return; } - FlowViewportAPIMayaLocator* flowViewportAPIMayaLocator = reinterpret_cast(clientData); - flowViewportAPIMayaLocator->SetCubeGridParametersFromAttributes(); - flowViewportAPIMayaLocator->SetupFlowViewportInterfaces(); + MhFlowViewportAPILocator* flowViewportAPIMayaLocator = reinterpret_cast(clientData); + flowViewportAPIMayaLocator->setCubeGridParametersFromAttributes(); + flowViewportAPIMayaLocator->addedToModelCb(); } -}//end of anonymous namespace + void nodeAddedToModel(MObject& node, void* /* clientData */) + { + auto fpNode = reinterpret_cast(MFnDagNode(node).userNode()); + if (!TF_VERIFY(fpNode)) { + return; + } -//Initialization of static members -MTypeId FlowViewportAPIMayaLocator::id( 0x90517 ); -MString FlowViewportAPIMayaLocator::nodeClassification("hydraAPIExample/geometry/FlowViewportAPIMayaLocator"); - -MObject FlowViewportAPIMayaLocator::mNumCubeLevelsX; -MObject FlowViewportAPIMayaLocator::mNumCubeLevelsY; -MObject FlowViewportAPIMayaLocator::mNumCubeLevelsZ; -MObject FlowViewportAPIMayaLocator::mCubeHalfSize; -MObject FlowViewportAPIMayaLocator::mCubeInitalTransform; -MObject FlowViewportAPIMayaLocator::mCubeColor; -MObject FlowViewportAPIMayaLocator::mCubeOpacity; -MObject FlowViewportAPIMayaLocator::mCubesUseInstancing; -MObject FlowViewportAPIMayaLocator::mCubesDeltaTrans; -MObject FlowViewportAPIMayaLocator::mDummyInput; -MObject FlowViewportAPIMayaLocator::mDummyOutput; + fpNode->addedToModelCb(); + } -//Macro to create input attribute for the maya node -#define MAKE_INPUT(attr) \ - CHECK_MSTATUS(attr.setKeyable(true) ); \ - CHECK_MSTATUS(attr.setStorable(true) ); \ - CHECK_MSTATUS(attr.setReadable(true) ); \ - CHECK_MSTATUS(attr.setWritable(true) ); \ - CHECK_MSTATUS(attr.setAffectsAppearance(true) ); + void nodeRemovedFromModel(MObject& node, void* /* clientData */) + { + auto fpNode = reinterpret_cast(MFnDagNode(node).userNode()); + if (!TF_VERIFY(fpNode)) { + return; + } -//Macro to create output attribute for the maya node -#define MAKE_OUTPUT(attr) \ -CHECK_MSTATUS ( attr.setKeyable(false) ); \ -CHECK_MSTATUS ( attr.setStorable(false) ); \ -CHECK_MSTATUS ( attr.setReadable(true) ); \ -CHECK_MSTATUS ( attr.setWritable(false) ); + fpNode->removedFromModelCb(); + } +}//end of anonymous namespace -FlowViewportAPIMayaLocator::FlowViewportAPIMayaLocator() -{ +//Initialization of static members +MTypeId MhFlowViewportAPILocator::id( 0x58000086 ); +MString MhFlowViewportAPILocator::nodeClassification("hydraAPIExample/geometry/MhFlowViewportAPILocator"); + +MObject MhFlowViewportAPILocator::mNumCubeLevelsX; +MObject MhFlowViewportAPILocator::mNumCubeLevelsY; +MObject MhFlowViewportAPILocator::mNumCubeLevelsZ; +MObject MhFlowViewportAPILocator::mCubeHalfSize; +MObject MhFlowViewportAPILocator::mCubeInitalTransform; +MObject MhFlowViewportAPILocator::mCubeColor; +MObject MhFlowViewportAPILocator::mCubeOpacity; +MObject MhFlowViewportAPILocator::mCubesUseInstancing; +MObject MhFlowViewportAPILocator::mCubesDeltaTrans; + +void MhFlowViewportAPILocator::postConstructor() +{ //Get the flow viewport API hydra interfaces int majorVersion = 0; int minorVersion = 0; @@ -336,25 +302,21 @@ FlowViewportAPIMayaLocator::FlowViewportAPIMayaLocator() FvpViewportAPITokens->allRenderers, //We could set only Storm by using "GL" or only Arnold by using "Arnold" or both with "GL, Arnold" nullptr);//DCC node will be filled later + setCubeGridParametersFromAttributes(); + + MObject obj = thisMObject(); + _nodeAddedToModelCbId = MModelMessage::addNodeAddedToModelCallback(obj, nodeAddedToModel); + _nodeRemovedFromModelCbId = MModelMessage::addNodeRemovedFromModelCallback(obj, nodeRemovedFromModel); } //This is called only when our node is destroyed and the undo queue flushed. -FlowViewportAPIMayaLocator::~FlowViewportAPIMayaLocator() +MhFlowViewportAPILocator::~MhFlowViewportAPILocator() { //Remove the callbacks - if (_cbAttributeChangedId){ - CHECK_MSTATUS(MMessage::removeCallback(_cbAttributeChangedId)); - _cbAttributeChangedId = 0; - } - - if (_cbAfterOpenId){ - CHECK_MSTATUS(MSceneMessage::removeCallback(_cbAfterOpenId)); - _cbAfterOpenId = 0; - } - - if (_cbParentAttributeChangedId){ - CHECK_MSTATUS(MSceneMessage::removeCallback(_cbParentAttributeChangedId)); - _cbParentAttributeChangedId = 0; + for(auto cbId : {_cbAfterOpenId, _cbAttributeChangedId, _nodeAddedToModelCbId, _nodeRemovedFromModelCbId}) { + if (cbId) { + CHECK_MSTATUS(MMessage::removeCallback(cbId)); + } } //The DataProducerSceneIndexExample in its destructor removes itself by calling DataProducerSceneIndexExample::RemoveDataProducerSceneIndex() @@ -368,34 +330,34 @@ FlowViewportAPIMayaLocator::~FlowViewportAPIMayaLocator() informationInterface.UnregisterInformationClient(_hydraViewportInformationClient); } -void FlowViewportAPIMayaLocator::SetCubeGridParametersFromAttributes() +void MhFlowViewportAPILocator::setCubeGridParametersFromAttributes() { - const MObject mObj = thisMObject(); + MObject mObj = thisMObject(); if (mObj.isNull()){ return; } - GetAttributeValue(_cubeGridParams._numLevelsX, mObj, FlowViewportAPIMayaLocator::mNumCubeLevelsX); - GetAttributeValue(_cubeGridParams._numLevelsY, mObj, FlowViewportAPIMayaLocator::mNumCubeLevelsY); - GetAttributeValue(_cubeGridParams._numLevelsZ, mObj, FlowViewportAPIMayaLocator::mNumCubeLevelsZ); + GetAttributeValue(_cubeGridParams._numLevelsX, mObj, MhFlowViewportAPILocator::mNumCubeLevelsX); + GetAttributeValue(_cubeGridParams._numLevelsY, mObj, MhFlowViewportAPILocator::mNumCubeLevelsY); + GetAttributeValue(_cubeGridParams._numLevelsZ, mObj, MhFlowViewportAPILocator::mNumCubeLevelsZ); - GetAttributeValue(_cubeGridParams._halfSize, mObj, FlowViewportAPIMayaLocator::mCubeHalfSize); + GetAttributeValue(_cubeGridParams._halfSize, mObj, MhFlowViewportAPILocator::mCubeHalfSize); MMatrix mat; - GetMatrixAttributeValue(mat, mObj, FlowViewportAPIMayaLocator::mCubeInitalTransform); + GetMatrixAttributeValue(mat, mObj, MhFlowViewportAPILocator::mCubeInitalTransform); memcpy(_cubeGridParams._initalTransform.GetArray(), mat[0], sizeof(double) * 16);//convert from MMatrix to GfMatrix4d double3 color; - GetDouble3AttributeValue(color, mObj, FlowViewportAPIMayaLocator::mCubeColor); + GetDouble3AttributeValue(color, mObj, MhFlowViewportAPILocator::mCubeColor); _cubeGridParams._color.data()[0] = color[0];//Implicit conversion from double to float _cubeGridParams._color.data()[1] = color[1]; _cubeGridParams._color.data()[2] = color[2]; - GetAttributeValue(_cubeGridParams._opacity, mObj, FlowViewportAPIMayaLocator::mCubeOpacity); - GetAttributeValue(_cubeGridParams._useInstancing, mObj, FlowViewportAPIMayaLocator::mCubesUseInstancing); + GetAttributeValue(_cubeGridParams._opacity, mObj, MhFlowViewportAPILocator::mCubeOpacity); + GetAttributeValue(_cubeGridParams._useInstancing, mObj, MhFlowViewportAPILocator::mCubesUseInstancing); double3 deltaTrans; - GetDouble3AttributeValue(deltaTrans, mObj, FlowViewportAPIMayaLocator::mCubesDeltaTrans); + GetDouble3AttributeValue(deltaTrans, mObj, MhFlowViewportAPILocator::mCubesDeltaTrans); _cubeGridParams._deltaTrans.data()[0] = deltaTrans[0];//Implicit conversion from double to float _cubeGridParams._deltaTrans.data()[1] = deltaTrans[1]; _cubeGridParams._deltaTrans.data()[2] = deltaTrans[2]; @@ -403,83 +365,18 @@ void FlowViewportAPIMayaLocator::SetCubeGridParametersFromAttributes() _hydraViewportDataProducerSceneIndexExample.setCubeGridParams(_cubeGridParams); } -void FlowViewportAPIMayaLocator::SetupFlowViewportInterfaces() +MStatus MhFlowViewportAPILocator::compute( const MPlug& plug, MDataBlock& dataBlock) { - if (_thisMObject.isNull()){ - MObject currentMObj = thisMObject(); - if (_oldMObject.isNull() || _oldMObject != currentMObj){ - _thisMObject = currentMObj; - _oldMObject = _thisMObject; - } - - if(_thisMObject.isNull()){ - return; - } - } - - //Set the maya node as a parent for this data producer scene index so that when the node is hidden/deleted/moved it gets applied to the prims produced - GfMatrix4d nodeInvTransform; - GetNodeInverseTransform(_thisMObject, nodeInvTransform); - _hydraViewportDataProducerSceneIndexExample.setContainerNode(&_thisMObject); - _hydraViewportDataProducerSceneIndexExample.addDataProducerSceneIndex(); - - //Register a filtering scene index client - Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); - - - //Store the MObject* of the maya node in various classes - _hydraViewportFilteringSceneIndexClientExample->setDccNode(&_thisMObject); - - //Register this filtering scene index client, so it can append custom filtering scene indices to Hydra viewport scene indices - const bool bResult = filteringSceneIndexInterface.registerFilteringSceneIndexClient(_hydraViewportFilteringSceneIndexClientExample); - if(! bResult){ - perror("ERROR : filteringSceneIndexInterface.registerFilteringSceneIndexClient returned false"); - } -} - -MStatus FlowViewportAPIMayaLocator::compute( const MPlug& plug, MDataBlock& dataBlock) -{ - //Do it only once per call to this function per node - - if( ! _init){ - SetCubeGridParametersFromAttributes(); - - MObject currentMObj = thisMObject(); - //Add the callback when an attribute of this node changes - _cbAttributeChangedId = MNodeMessage::addAttributeChangedCallback(currentMObj, attributeChangedCallback, ((void*)this)); - - //Also monitor parent DAG node to be able to update the scene index if the parent transform is modified - MStatus stat; - MDagPath parentDagPath = MDagPath::getAPathTo(currentMObj, &stat); - CHECK_MSTATUS(stat); - parentDagPath.pop(); - MObject parentObj = parentDagPath.node(); - _cbParentAttributeChangedId = MNodeMessage::addAttributeChangedCallback(parentObj, transformAttributeChangedCallback, this); - - _init = true; - } - - //The MObject can change if the node gets deleted and deletion being undone, so always update it in our records - MObject currentMObj = thisMObject(); - if (_oldMObject.isNull() || _oldMObject != currentMObj){ - - _thisMObject = currentMObj; - _oldMObject = _thisMObject; - - SetupFlowViewportInterfaces(); - } - - return MS::kSuccess; } -bool FlowViewportAPIMayaLocator::isBounded() const +bool MhFlowViewportAPILocator::isBounded() const { return true; } //We return as a bounding box the bounding box of the data producer hydra data -MBoundingBox FlowViewportAPIMayaLocator::boundingBox() const +MBoundingBox MhFlowViewportAPILocator::boundingBox() const { float corner1X, corner1Y, corner1Z, corner2X, corner2Y, corner2Z; _hydraViewportDataProducerSceneIndexExample.getPrimsBoundingBox(corner1X, corner1Y, corner1Z, corner2X, corner2Y, corner2Z); @@ -487,23 +384,70 @@ MBoundingBox FlowViewportAPIMayaLocator::boundingBox() const } // Called before this node is evaluated by Evaluation Manager -MStatus FlowViewportAPIMayaLocator::preEvaluation( +MStatus MhFlowViewportAPILocator::preEvaluation( const MDGContext& context, const MEvaluationNode& evaluationNode) { return MStatus::kSuccess; } -void FlowViewportAPIMayaLocator::getCacheSetup(const MEvaluationNode& evalNode, MNodeCacheDisablingInfo& disablingInfo, MNodeCacheSetupInfo& cacheSetupInfo, MObjectArray& monitoredAttributes) const +void MhFlowViewportAPILocator::getCacheSetup(const MEvaluationNode& evalNode, MNodeCacheDisablingInfo& disablingInfo, MNodeCacheSetupInfo& cacheSetupInfo, MObjectArray& monitoredAttributes) const { MPxLocatorNode::getCacheSetup(evalNode, disablingInfo, cacheSetupInfo, monitoredAttributes); assert(!disablingInfo.getCacheDisabled()); cacheSetupInfo.setPreference(MNodeCacheSetupInfo::kWantToCacheByDefault, true); } -void* FlowViewportAPIMayaLocator::creator() +void* MhFlowViewportAPILocator::creator() +{ + static const MString errorMsg ("You need to load the mayaHydra plugin before creating this node"); + + int isMayaHydraLoaded = false; + // Validate that the mayaHydra plugin is loaded. + MGlobal::executeCommand( "pluginInfo -query -loaded mayaHydra", isMayaHydraLoaded ); + if( ! isMayaHydraLoaded){ + MGlobal::displayError(errorMsg); + return nullptr; + } + + return new MhFlowViewportAPILocator; +} + +void MhFlowViewportAPILocator::addedToModelCb() +{ + static const SdfPath noPrefix = SdfPath::AbsoluteRootPath(); + + //Add the callback when an attribute of this node changes + MObject obj = thisMObject(); + _cbAttributeChangedId = MNodeMessage::addAttributeChangedCallback(obj, attributeChangedCallback, ((void*)this)); + + _hydraViewportDataProducerSceneIndexExample.setContainerNode(&obj); + _hydraViewportDataProducerSceneIndexExample.addDataProducerSceneIndex(); + + //Store the MObject* of the maya node in various classes + _hydraViewportFilteringSceneIndexClientExample->setDccNode(&obj); + + //Register this filtering scene index client, so it can append custom filtering scene indices to Hydra viewport scene indices + Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + const bool bResult = filteringSceneIndexInterface.registerFilteringSceneIndexClient(_hydraViewportFilteringSceneIndexClientExample); + if(! bResult){ + perror("ERROR : filteringSceneIndexInterface.registerFilteringSceneIndexClient returned false"); + } +} + +void MhFlowViewportAPILocator::removedFromModelCb() { - return new FlowViewportAPIMayaLocator; + //Remove the callback + if (_cbAttributeChangedId){ + CHECK_MSTATUS(MMessage::removeCallback(_cbAttributeChangedId)); + _cbAttributeChangedId = 0; + } + + //Remove the data producer scene index. + _hydraViewportDataProducerSceneIndexExample.removeDataProducerSceneIndex(); + + Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + filteringSceneIndexInterface.unregisterFilteringSceneIndexClient(_hydraViewportFilteringSceneIndexClientExample); } //--------------------------------------------------------------------------- @@ -511,7 +455,22 @@ void* FlowViewportAPIMayaLocator::creator() // Plugin Registration //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -MStatus FlowViewportAPIMayaLocator::initialize() +//Macro to create input attribute for the maya node +#define MAKE_INPUT(attr) \ + CHECK_MSTATUS(attr.setKeyable(true) ); \ + CHECK_MSTATUS(attr.setStorable(true) ); \ + CHECK_MSTATUS(attr.setReadable(true) ); \ + CHECK_MSTATUS(attr.setWritable(true) ); \ + CHECK_MSTATUS(attr.setAffectsAppearance(true) ); + +//Macro to create output attribute for the maya node +#define MAKE_OUTPUT(attr) \ + CHECK_MSTATUS ( attr.setKeyable(false) ); \ + CHECK_MSTATUS ( attr.setStorable(false) ); \ + CHECK_MSTATUS ( attr.setReadable(true) ); \ + CHECK_MSTATUS ( attr.setWritable(false) ); + +MStatus MhFlowViewportAPILocator::initialize() { MStatus status; @@ -554,16 +513,6 @@ MStatus FlowViewportAPIMayaLocator::initialize() MAKE_INPUT(nAttr); CHECK_MSTATUS ( nAttr.setDefault(5.0, 5.0, 5.0) ); - //Create dummy output attribute to trigger a call to the compute function on demand. as it's in the compute fonction that we add our scene indices - mDummyInput = nAttr.create("dummyInput", "dI", MFnNumericData::kInt, 1.0, &status); - MAKE_INPUT(nAttr); - CHECK_MSTATUS ( nAttr.setDefault(1) ); - - //Create dummy output attribute to trigger a call to the compute function on demand. as it's in the compute fonction that we add our scene indices - mDummyOutput = nAttr.create("dummyOutput", "dO", MFnNumericData::kInt, 1.0, &status); - MAKE_OUTPUT(nAttr); - CHECK_MSTATUS ( nAttr.setDefault(1) ); - CHECK_MSTATUS ( addAttribute(mNumCubeLevelsX)); CHECK_MSTATUS ( addAttribute(mNumCubeLevelsY)); CHECK_MSTATUS ( addAttribute(mNumCubeLevelsZ)); @@ -573,11 +522,6 @@ MStatus FlowViewportAPIMayaLocator::initialize() CHECK_MSTATUS ( addAttribute(mCubeOpacity)); CHECK_MSTATUS ( addAttribute(mCubesUseInstancing)); CHECK_MSTATUS ( addAttribute(mCubesDeltaTrans)); - CHECK_MSTATUS ( addAttribute(mDummyInput)); - CHECK_MSTATUS ( addAttribute(mDummyOutput)); - - CHECK_MSTATUS ( attributeAffects(mDummyInput, mDummyOutput)); - return status; } @@ -589,12 +533,12 @@ MStatus initializePlugin( MObject obj ) MFnPlugin plugin( obj, PLUGIN_COMPANY, pluginVersion, "Any"); status = plugin.registerNode( - "FlowViewportAPIMayaLocator", - FlowViewportAPIMayaLocator::id, - &FlowViewportAPIMayaLocator::creator, - &FlowViewportAPIMayaLocator::initialize, + "MhFlowViewportAPILocator", + MhFlowViewportAPILocator::id, + &MhFlowViewportAPILocator::creator, + &MhFlowViewportAPILocator::initialize, MPxNode::kLocatorNode, - &FlowViewportAPIMayaLocator::nodeClassification); + &MhFlowViewportAPILocator::nodeClassification); if (!status) { status.perror("registerNode"); return status; @@ -608,7 +552,7 @@ MStatus uninitializePlugin( MObject obj) MStatus status; MFnPlugin plugin( obj ); - status = plugin.deregisterNode( FlowViewportAPIMayaLocator::id ); + status = plugin.deregisterNode( MhFlowViewportAPILocator::id ); if (!status) { status.perror("deregisterNode"); return status; diff --git a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py index f0a38ac2b9..b05d9845f5 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py +++ b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py @@ -41,41 +41,38 @@ class TestFlowViewportAPI(mtohUtils.MtohTestCase): #Subclassing mtohUtils.MtohTe def setupScene(self): self.setHdStormRenderer() + def tearDown(self): + #is called after each test : finish by a File New command to check that it's not crashing when cleaning up everything' + cmds.file(new=True, force=True) + #Test adding primitives def test_AddingPrimitives(self): self.setupScene() - with PluginLoaded('flowViewportAPIMayaLocator'): + with PluginLoaded('mayaHydraFlowViewportAPILocator'): #Create a maya sphere sphereNode, sphereShape = cmds.polySphere() cmds.refresh() - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName = cmds.createNode("FlowViewportAPIMayaLocator") - self.assertFalse(flowViewportNodeName == None) - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName + '.dummyInput', 2)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName = cmds.createNode("MhFlowViewportAPILocator") cmds.refresh() #Original images are located for example in maya-hydra\test\lib\mayaUsd\render\mayaToHydra\FlowViewportAPITest self.assertSnapshotClose("add_NodeCreated.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) #Move the transform node, the added prims (cube grid) should move as well - # Get the transform node of the FlowViewportAPIMayaLocator + # Get the transform node of the MhFlowViewportAPILocator transformNode = cmds.listRelatives(flowViewportNodeName, parent=True)[0] - self.assertFalse(transformNode == None) - #Select the transform node - cmds.select(transformNode) - # Move the selected node - cmds.move(10, 5, -5) + self.assertIsNotNone(transformNode) + cmds.move(10, 5, -5, transformNode) cmds.refresh() self.assertSnapshotClose("add_NodeMoved.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Hide the transform node, this should hide the FlowViewportAPIMayaLocator node and the added prims as well. + #Hide the transform node, this should hide the MhFlowViewportAPILocator node and the added prims as well. cmds.hide(transformNode) self.assertSnapshotClose("add_NodeHidden.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Unhide the transform node, this should unhide the FlowViewportAPIMayaLocator node and the added prims as well. + #Unhide the transform node, this should unhide the MhFlowViewportAPILocator node and the added prims as well. cmds.showHidden(transformNode) self.assertSnapshotClose("add_NodeUnhidden.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -96,9 +93,7 @@ def test_AddingPrimitives(self): self.assertSnapshotClose("add_NodeDeletedUndoAgain.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) #Move transform node again to see if it still updates the added prims transform - cmds.select(transformNode) - # Move the selected node - cmds.move(-20, -5, 0) + cmds.move(-20, -5, 0, transformNode) cmds.refresh() self.assertSnapshotClose("add_NodeMovedAfterDeletionAndUndo.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -108,36 +103,26 @@ def test_AddingPrimitives(self): self.setHdStormRenderer() self.assertSnapshotClose("add_VP2AndThenBackToStorm.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Finish by a File New command - cmds.file(new=True, force=True) - #Test filtering primitives def test_FilteringPrimitives(self): self.setupScene() - with PluginLoaded('flowViewportAPIMayaLocator'): + with PluginLoaded('mayaHydraFlowViewportAPILocator'): #Create a maya sphere sphereNode, sphereShape = cmds.polySphere() cmds.refresh() - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName = cmds.createNode("FlowViewportAPIMayaLocator") - self.assertFalse(flowViewportNodeName == None) - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName + '.dummyInput', 3)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName = cmds.createNode("MhFlowViewportAPILocator") cmds.refresh() #Original images are located for example in maya-hydra\test\lib\mayaUsd\render\mayaToHydra\FlowViewportAPITest self.assertSnapshotClose("filter_NodeCreated.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) #Move the transform node, the added prims (cube grid) should move as well - # Get the transform node of the FlowViewportAPIMayaLocator + # Get the transform node of the MhFlowViewportAPILocator transformNode = cmds.listRelatives(flowViewportNodeName, parent=True)[0] - self.assertFalse(transformNode == None) - #Select the transform node - cmds.select(transformNode) - # Move the selected node - cmds.move(15, 0, 0) + self.assertIsNotNone(transformNode) + cmds.move(15, 0, 0, transformNode) cmds.refresh() self.assertSnapshotClose("filter_NodeMoved.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -157,11 +142,11 @@ def test_FilteringPrimitives(self): cmds.refresh() self.assertSnapshotClose("filter_SphereFilteredAgain.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Hide the transform node, this should hide the FlowViewportAPIMayaLocator shape node and disable the filtering as well. + #Hide the transform node, this should hide the MhFlowViewportAPILocator shape node and disable the filtering as well. cmds.hide(transformNode) self.assertSnapshotClose("filter_NodeHidden.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Unhide the transform node, this should unhide the FlowViewportAPIMayaLocator node and enable the filtering as well. + #Unhide the transform node, this should unhide the MhFlowViewportAPILocator node and enable the filtering as well. cmds.showHidden(transformNode) self.assertSnapshotClose("filter_NodeUnhidden.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -193,22 +178,14 @@ def test_FilteringPrimitives(self): cmds.setAttr(sphereShape + '.subdivisionsAxis', 30) #Unfilter the prim cmds.refresh() self.assertSnapshotClose("filter_VP2AndThenBackToStorm_MovedSphereUnFiltered.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - - #Finish by a File New command - cmds.file(new=True, force=True) #Test Cube grids parameters def test_CubeGrid(self): self.setupScene() - with PluginLoaded('flowViewportAPIMayaLocator'): + with PluginLoaded('mayaHydraFlowViewportAPILocator'): - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName = cmds.createNode("FlowViewportAPIMayaLocator") - self.assertFalse(flowViewportNodeName == None) - - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName + '.dummyInput', 2)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName = cmds.createNode("MhFlowViewportAPILocator") self.assertSnapshotClose("cubeGrid_BeforeModifs.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) #Get the matrix and set a rotation of 70 degress around Y axis. @@ -250,21 +227,13 @@ def test_CubeGrid(self): self.setHdStormRenderer() self.assertSnapshotClose("cubeGrid_VP2AndThenBackToStorm.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Finish by a File New command - cmds.file(new=True, force=True) - #Test multiple nodes def test_MultipleNodes(self): self.setupScene() - with PluginLoaded('flowViewportAPIMayaLocator'): + with PluginLoaded('mayaHydraFlowViewportAPILocator'): - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName1 = cmds.createNode("FlowViewportAPIMayaLocator", n="nodeShape1") - self.assertFalse(flowViewportNodeName1 == None) - - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName1 + '.dummyInput', 2)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName1 + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName1 = cmds.createNode("MhFlowViewportAPILocator", n="nodeShape1") #Get the matrix and set a rotation of 70 degress around Y axis. matrix = cmds.getAttr(flowViewportNodeName1 + '.cubeInitalTransform') @@ -284,22 +253,14 @@ def test_MultipleNodes(self): cmds.refresh() #Move the transform node, the added prims (cube grid) should move as well - # Get the transform node of the FlowViewportAPIMayaLocator + # Get the transform node of the MhFlowViewportAPILocator transformNode1 = cmds.listRelatives(flowViewportNodeName1, parent=True)[0] - self.assertFalse(transformNode1 == None) - #Select the transform node - cmds.select(transformNode1) - # Move the selected node - cmds.move(-10, 0, 0) + self.assertIsNotNone(transformNode1) + cmds.move(-10, 0, 0, transformNode1) cmds.refresh() - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName2 = cmds.createNode("FlowViewportAPIMayaLocator", n="nodeShape2") - self.assertFalse(flowViewportNodeName2 == None) - - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName2 + '.dummyInput', 3)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName2 + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName2 = cmds.createNode("MhFlowViewportAPILocator", n="nodeShape2") #Get the matrix and set a rotation of 70 degress around Y axis. matrix = cmds.getAttr(flowViewportNodeName2 + '.cubeInitalTransform') @@ -319,13 +280,10 @@ def test_MultipleNodes(self): cmds.refresh() #Move the transform node, the added prims (cube grid) should move as well - # Get the transform node of the FlowViewportAPIMayaLocator + # Get the transform node of the MhFlowViewportAPILocator transformNode2 = cmds.listRelatives(flowViewportNodeName2, parent=True)[0] - self.assertFalse(transformNode2 == None) - #Select the transform node - cmds.select(transformNode2) - # Move the selected node - cmds.move(-30, 0, -30) + self.assertIsNotNone(transformNode2) + cmds.move(-30, 0, -30, transformNode2) cmds.refresh() self.assertSnapshotClose("multipleNodes_BeforeModifs.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -335,10 +293,9 @@ def test_MultipleNodes(self): cmds.setAttr(flowViewportNodeName2 + '.cubeOpacity', 0.1) # Apply transform on node #2 - cmds.select(transformNode2) - cmds.move(-30, 0, 0) - cmds.rotate(-30, 45, 0) - cmds.scale(2, 1, 1) + cmds.move(-30, 0, 0, transformNode2) + cmds.rotate(-30, 45, 0, transformNode2) + cmds.scale(2, 1, 1, transformNode2) cmds.refresh() self.assertSnapshotClose("multipleNodes_AfterModifs.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) @@ -360,12 +317,9 @@ def test_MultipleNodes(self): self.setHdStormRenderer() self.assertSnapshotClose("multipleNodes_VP2AndThenBackToStorm.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - #Finish by a File New command - cmds.file(new=True, force=True) - #Test multiple viewports def test_MultipleViewports(self): - with PluginLoaded('flowViewportAPIMayaLocator'): + with PluginLoaded('mayaHydraFlowViewportAPILocator'): #switch to 4 views mel.eval('FourViewLayout') #Set focus on persp view @@ -380,19 +334,11 @@ def test_MultipleViewports(self): #Create a maya sphere sphereNode, sphereShape = cmds.polySphere() - #Select the transform node - cmds.select(sphereNode) - # Move the selected node - cmds.move(15, 0, 0) + cmds.move(15, 0, 0, sphereNode) cmds.refresh() - #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index - flowViewportNodeName1 = cmds.createNode("FlowViewportAPIMayaLocator", n="nodeShape1") - self.assertFalse(flowViewportNodeName1 == None) - - #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute - cmds.setAttr(flowViewportNodeName1 + '.dummyInput', 2)#setting this will set dirty the dummyOutput attribute - cmds.getAttr(flowViewportNodeName1 + '.dummyOutput')#getting this value will trigger a call to compute + #Create a MhFlowViewportAPILocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName1 = cmds.createNode("MhFlowViewportAPILocator", n="nodeShape1") #Modify the cube grid parameters cmds.setAttr(flowViewportNodeName1 + '.numCubesX', 3) @@ -442,8 +388,6 @@ def test_MultipleViewports(self): cmds.setFocus ('modelPanel2') self.setHdStormRenderer() self.assertSnapshotClose("multipleViewports_VP2AndThenBackToStorm_modPan2.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) - - #Finish by a File New command - cmds.file(new=True, force=True) + if __name__ == '__main__': fixturesUtils.runTests(globals())