PDA

View Full Version : Passing MPointArray between nodes


ganzo
12-22-2010, 08:11 PM
SOLVED

Ok I edited the post to make it easier to understand..

I have two nodes:
1. An MPxNode that has an output attribute sending an MPointArray, the amount of points are brought in through an input attribute.

2. An MPxLocatorNode with an input attribute receiving the MPointArray from the other node and displaying the point data through its draw function.

Debug mode: I can create both nodes and connect the output to input manually and all works. I can change the amount of points and the point array is passed on successfully to the locatorNode and the draw function updates the points correctly.

Release: If I follow the same steps taken during debug mode...that is create both nodes via "createNode" and then connect the output to input through the connection editor, maya crashes with "unhandled exception".

I populated the code with breakpoints to step through it in debug mode and looked at the debug output and there are no c++ exceptions or errors in each breakpoint around the precompute function when I connect the output to input attribute.

There is a "DoesNotExistException at memory location" on the output of my debug, but that shows up when I select the MPxLocatorNode. Still, like I said...during debug mode..everything works...it crashes on release version.

Here is the code for the MPxNode, sorry about the amount of status checks:


MObject node::a_Points;
MObject node::a_Amount;

MStatus node::initialize()
{
//-----------------------------------------------------------------
//Create input attribute a_Amount to get number of points.
MFnNumericAttribute nAttr;

a_Amount = nAttr.create("amount","amt",MFnNumericData::kInt,30,&status);
status = addAttribute(a_Amount);
//-----------------------------------------------------------------
// Create Output attribute of type MPointArray
MFnTypedAttribute tAttr;
a_Points = tAttr.create("outPoints","opnt",MFnData::kPointArray,&status);
status = addAttribute(a_Points);
//-----------------------------------------------------------------
//Create affect relationship a_Amount(input)->a_Points(output)
status = attributeAffects(a_Amount,a_Points);

return MS::kSuccess;
}
//#################################################################
//----------------------------------COMPUTE----------------------------------------
MStatus node::compute(const MPlug& plug, MDataBlock& data)
{
MStatus status;

if(plug != a_Points)
return MS::kUnknownParameter;
//-----------------------------------------------------------------
//Grab Inputs
MDataHandle h_aAmount = data.inputValue(a_Amount,&status);
int nAmount = h_aAmount.asInt();
//-----------------------------------------------------------------
//Grab Outputs
MDataHandle h_aPoints = data.outputValue(a_Points,&status);
MFnPointArrayData fn_aPoints;
MPointArray p_aPoints;
//--fill point array with data
MObject o_aPoints = fn_aPoints.create(p_aPoints,&status);

h_aPoints.set(o_aPoints);
status = data.setClean ( plug );
}


This is the code for the MPxLocatorNode:


MObject locatorNode::a_Points;
MObject locatorNode::a_PointsOut;

MStatus locatorNode::initialize()
{
MStatus status;

//---------------------------------------------------------------
//Create input attribute to receive point array
MFnTypedAttribute tAttr;

a_Points = tAttr.create("inPoints","ipnt",MFnData::kPointArray,&status);
status = addAttribute(a_Points);
//----------------------------------------------------------------
//Create output attribute - NOT USED REMOVED COMPUTE FUNCTION
MFnTypedAttribute oAttr;
a_PointsOut = tAttr.create("pointsOut","ptsO",MFnData::kPointArray,&status);
status = addAttribute(a_PointsOut);

//----------------------------------------------------------------
//Create affect relationship a_Points(input)->a_PointsOut(output)
status = attributeAffects(a_Points,a_PointsOut);

return MS::kSuccess;
}

//###################################################################
//--------------------------DRAW-------------------------------------
void CrackerGuideNode::draw( M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status )
{
view.beginGL();

MPointArray pts;
getPointData(pts);
//draw point data in array
view.endGL();
}

bool locatorNode::getPointData(MPointArray &pts) const
{
MStatus status;
MObject thisNode = thisMObject();
MPlug plug_aPoints(thisNode,a_Points);
MObject o_aPoints;
plug_aPoints.getValue(o_aPoints);
MFnPointArrayData fn_aPoints(o_aPoints);
fn_aPoints.copyTo(pts);

return true;
}

ganzo
12-23-2010, 11:24 PM
Bump
Updated description of problem.
Please have a look guys....could use the help :)

zoharl
12-24-2010, 08:28 AM
First of debug the release version (just add debug info to it), since there is where you have your problem. For easier tracking (source code compatible to binary - no missing lines) remove the optimization if it still generates the bug.

Secondly try to write for our sake a simpler (and minimal in length) code, and try just to pass a pointer to an integer, and test if passing such a pointer is valid.

Thirdly I'm almost sure that you can't pass a pointer to an MObject (or bad things would happen), but you must pass it by value or reference. Try this exercise with a function in the same plug-in.
Also you need to make sure that the pointer is valid between these two dlls, although there should be no problem, since it's the same process, and thus the same memory address. Still I would verify that with interprocess communication objects such as a shared memory, pipe, mail slot, or a socket.

Fourthly I would look for a more elegant solution. For example I would set an attribute of a type of array of points such as vtx (vertices array) in a mesh, or pass a pointer to my own data structure, simply since you don't have an attribute of type MObject, and passing a pointer to it is irresponsible, although you might be able to make it with defining your own attribute type if it's possible.

ganzo
12-24-2010, 08:48 PM
First of debug the release version (just add debug info to it), since there is where you have your problem. For easier tracking (source code compatible to binary - no missing lines) remove the optimization if it still generates the bug.

Sorry I think I did not explain myself....when I said debug mode...I meant I am actually running the debugger while using the plugin to step through breakpoints. I don't have two separate .mll's By release version I mean I am just using the plugin as is without attaching debugger to it. Sorry about the confusion.

Secondly try to write for our sake a simpler (and minimal in length) code, and try just to pass a pointer to an integer, and test if passing such a pointer is valid.


Sorry about that...I did not realize my code was complicated...I just deleted the status checks to make it shorter.


Thirdly I'm almost sure that you can't pass a pointer to an MObject (or bad things would happen), but you must pass it by value or reference...

I'm not exactly sure what you are talking about can you point out what part of the code you are talking about if you can?...what I'm doing seems pretty trivial. In fact...the code is pretty close to many examples I have seen. Here is what api doc's say about this:

MFnPointArrayData:
"If a user written dependency node either accepts or produces MPointArrays, then this class is used to extract or create the data that comes from or goes to other dependency graph nodes. The MDataHandle::type (http://forums.cgsociety.org/) method will return kPointArray when data of this type is present. To access it, the MDataHandle::data (http://forums.cgsociety.org/) method is used to get an MObject (http://forums.cgsociety.org/) for the data and this should then be used to initialize an instance of MFnPointArrayData (http://forums.cgsociety.org/). "


Fourthly I would look for a more elegant solution. For example I would set an attribute of a type of array of points such as vtx (vertices array) in a mesh, or pass a pointer to my own data structure...
MPointArray is already a data structure meant to handle array of MPoints...I don't know if it is necessary to reinvent the wheel.
from the doc's:

...and the implementation is compatible with the internal Maya implementation so that it can be passed efficiently between plugins and internal maya data structures.

Seems like the adequate solution to me...of course I have been wrong in the past.:blush: Still the fact that it works when I am running the plugin with debugger attached shows that there is some small discrepancy or some exception that is being allowed to pass by the debugger, but crashes maya when I am running the plugin without the debugger attached.

Hope someone can point me in the right direction when passing MPointArrays to a locator node for drawing....I'll still try simple arrays on the side. Thanks!

zoharl
12-25-2010, 01:12 AM
Sorry, I just skimmed your code the first time, and assumed wrong things from your description of things. It seems that you do use an elegant way and define an array attribute as I suggested on my last paragraph. So forget what I said.

I can't see something you do wrong, but something that occurred to me yesterday is still bothering me. I tried to draw a large array of points 30 times quickly. Most of the time maya crashed without any reason. Another code which uses the same draw procedure, but on longer intervals didn't have any problems. In the end I attributed it to the amount of data which might cause memory problems. It might be a long shot, but you described your code working only when you delay it with the debugger. I suggest you try to work first with small models. Then I suggest, just for the sport, to put a sleep command at crucial points, simulating your debugging behavior.

ganzo
12-26-2010, 01:15 AM
You know the timer thing did enter my mind, and I actually tried it with no luck. I have tried passing just a couple of points and nothing helped.

I'm wondering if anyone can post an example of an MPointArray being correctly passed to an MPxLocator node for drawing the points within the draw() function. I'm also wondering if it is better to include a compute function inside the locator node and force the calculation of the compute function to grab the data from the plugs....or if I'm doing it right by just getting direct access to the plug.

Anyone have experience doing such a trivial thing?

ganzo
12-26-2010, 08:07 AM
*sigh*.......I should know better.
Any of you programmers out there always go back to the old "The answer is always the simplest one"?...arggh...hate finding out after exploring all the most complicated solutions first.

Anyways.....problem solved....I think:thumbsup:

zoharl
12-26-2010, 08:18 AM
And the solution is ... ?

ganzo
12-26-2010, 08:06 PM
Ah I'm too ashamed to even mention it! lol
I basically forgot to return the status on my compute functions. Yes yes I know...boy do I look stupid. No wonder I was having trouble spotting a problem on the body of the code, there was none! Anyway, unlike standard functions....the compiler does not force you to return a value when for example using MStatus type functions so it lets it pass. Gotta remember that for the future....the small things that get overlooked.

I still have a question about this....why does maya crash when not returning a status value? Is it really that important for the operation of the whole system? and secondly...why does debugging the plugin make maya not care about the return of a status when it crashes when not debugging?

Just some things to think about....
Anyway....thanks for the help zoharl!

Joviex
12-27-2010, 09:08 PM
I still have a question about this....why does maya crash when not returning a status value? Is it really that important for the operation of the whole system? and secondly...why does debugging the plugin make maya not care about the return of a status when it crashes when not debugging?

The crashing may not be related to a non-returned status.

I see you are doing a bunch of initialization, or rather hoping that a few items get initialized, but are not checking their state and/or returned status.

i.e.


MDataHandle h_aAmount = data.inputValue(a_Amount,&status);
// HOW DO YOU KNOW THIS RETURNED A PROPER HANDLE??

MDataHandle h_aPoints = data.outputValue(a_Points,&status);
// HOW DO YOU KNOW THIS RETURNED A PROPER HANDLE??

MObject o_aPoints = fn_aPoints.create(p_aPoints,&status);
// HOW DO YOU KNOW THIS RETURNED A PROPER OBJECT??



You are making the assumption that it is a return code on the block of code because you are also making the assumption that the initializers are working all the time.

As for the why is Debug mode more robust.... because it is debug mode =) I'd bet you are seeing assertion errors. The debug libraries are very robust and will simply mention it and pass on through (mostly wrapped exceptions).

HTH

ganzo
12-27-2010, 09:42 PM
The crashing may not be related to a non-returned status.

I see you are doing a bunch of initialization, or rather hoping that a few items get initialized, but are not checking their state and/or returned status.


The code you see here has been stripped of all the status checks because of length. My full code is actually plagued with checks although some are the more simple "if(!status)" type checks. I do have more explicit checks to see if for example something is in fact a ::kPointArray. I'll give it another look....thanks!

BTW....not sure if you know this, but while debugging and peeking into values that are returned....data handles / plugs...not sure which one exactly...seem to hold an array of 31 elements regardless of the data being passed..something like a generic container. Is this the actual datablock?...all data inside seems like giberish...but I would really like to know the purpose of this array.

zoharl
12-28-2010, 01:14 AM
First I must confess that I never check for return values. Too lazy for that, and I settle with the magic:

MGlobal::startErrorLogging("c:/prj/plug-ins/OpenMayaErrorLog.txt");

And I check it on demand.


About the compilation error. I give you a conjuncture on the fly. Your compute method suppose to override some other function, but if you change its overloading, it's basically a different function, which doesn't collide with anything. Then maybe the compiler exports two functions: your compute() and the base. Some other thing, if you change the function declaration than the actual implementation, you would have problems later with the memory pointers to the data. Meaning, you can compile whatever you want, and declare/export whatever you want, and nobody checks if they are compatible.

About the mysterious 31, I would have liked to know many machineries in the tools I work with, especially my OS...

CGTalk Moderation
12-28-2010, 01:14 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.