Call a method of a non-MPxCommand plugin


#1

I created a plugin of type MPxHwShaderNode. I would like to call from a (shelf) script one of the object (my derived class) methods to perform some operation on on this specific object instance, e.g to export some data. Unfortunately, the class exposes to maya only member variables through attributes. Options that come to mind:

  1. Save a pointer to the object in an attribute. Write an MPxCommand, and pass the pointer as an argument. The command in turn, would access the object and execute a method.

  2. Create an MFnEnumAttribute of operations. Whenever the user selects an operation, the plugin would detect it on compute, run the operation, and reset the attribute.

How would you go about this?


#2

I’d go with the first option. From the same plugin you can derive the pointer to the class with dependNode.userNode().

MyNode *node = dynamic_cast<MyNode*>(depNodeFn.userNode(&stat));
node->makeSomethingVeryCool();

So if you know the mobject of your node, you can access it directly and there is no need to save a pointer.


#3

I usually go one of two ways about it depending on needs:
I have a singleton style stack for when I need to do work that’s aware of multiple instances, or if there is no such need I just keep the handle around and use userNode() like Haggi also suggested.


#4

The userNode solution seems elegant.
Thanks


#5

Now I wonder if I can call the method from python. I assume at least using ctypes, I can load the .dll and run the method which is exported with dllexport (and pass it the dependNode.userNode).


#6

I wasn’t sure how to pass the userNode from python, but the following worked:

C++ side

MStatus SpaceHWDeformerNode::initialize()
{   
    MStatus stat = MS::kSuccess;
    MFnNumericAttribute cpointerAttr;
    mCPointerAttr = cpointerAttr.create("CPointer" ,"CPointer", MFnNumericData::kInt64, 0, &stat);
    CHECK_MSTATUS(addAttribute(mCPointerAttr));
}

MStatus SpaceHWDeformerNode::compute(const MPlug& outputPlug, MDataBlock& dataBlock)
{
    MStatus stat = MS::kSuccess;
    MDataHandle handle = dataBlock.outputValue(mCPointerAttr, &stat);
    handle.setInt64((long long)this);
}

void SpaceHWDeformerNode::hello()
{
    Log.println("Hi from SpaceHWDeformerNode");
    Log << mHarmonicConvex.mIsP2P << endl;
}

extern "C" __declspec(dllexport) void hello()
{
    Log.println("Hello");
}

extern "C" __declspec(dllexport) void hello2(void *node)
{
    Log.println("pointer %d", (int)node);
    SpaceHWDeformerNode *hw = (SpaceHWDeformerNode *)node;
    hw->hello();
}

Python side


import pymel.core as pm
import ctypes

# get shader
hw = pm.ls(type='SpaceHWDeformer', fl=1)
if len(hw) != 1:
    print "There are %d SpaceHWDeformer nodes" % len(hw)
node = pm.PyNode(hw[0])
cpointer = node.getAttr('CPointer')

# load library
libh = ctypes.cdll.LoadLibrary('SpaceDeformation2D.mll')
lib = ctypes.WinDLL(None, handle=libh)

# run static function
libh.hello()

# run function with a plugin object as parameter
#dep = om.MFnDependencyNode(node.__apimobject__())
#cobj = dep.userNode()
libh.hello2(ctypes.c_void_p(cpointer))

# release library
del lib
ctypes.windll.kernel32.FreeLibrary(ctypes.c_int(libh._handle))


#7

Just wanted to say thanks for your continued contributions to the forums. It’s always good to see people feeding back into the community as much or more as they had in response to the original question, please do keep at it :slight_smile:


#8

And I’d like to thank everyone who helps and contributes to the forum, making it so productive :slight_smile: