Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

redo action duplicates shapes

redo action duplicates shapes

Anonymous
Not applicable
1,083 Views
11 Replies
Message 1 of 12

redo action duplicates shapes

Anonymous
Not applicable

I implemented a MPxCommand and try to add proper undo/redo support to it. Now I have the problem, that the redo function duplicates the actions.

 

Minimal example:

MStatus myCmd::doIt(const MArgList &args) {
    return redoIt()
}
MStatus myCmd::redoIt() {
    dagMod.createNode("mesh");
    dagMod.doIt();
    return MStatus::kSuccess;
}
MStatus myCmd::undoIt() {
    dagMod.undoIt();
    return MStatus::kSuccess;
}
bool MyCmd::isUndoable() const {
return true;
}

with MDagModifier dagMod as private member of the command class.

 

Is there some kind of .clear() function I need to call to make sure I do not add commands twice to dagMod? I thought undoIt will clear the action stack, but after each undo/redo I get one more shape than before.

0 Likes
Accepted solutions (1)
1,084 Views
11 Replies
Replies (11)
Message 2 of 12

Anonymous
Not applicable

When I try

 

if(done) {
    dagMod.doIt();
dgMod.doIt(); } else { done = true; }

It works with dagMod only, leaving my node (not in the minimal example above) behind. When dgMod is added I get the problem again.

0 Likes
Message 3 of 12

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Maya will call redoIt when redo command.

 

Thus, redoIt and doIt should be like this

MStatus myCommand::doIt(const MArgList& list){
	dagModifier.createNode("mesh");
	dagModifier.doIt();
        return MS::kSuccess;
}

MStatus myCommand::redoIt(){
       dagModifier.doIt();
       return MS::kSuccess;
}

 

You don't have to clear it at all, just call doIt again and it will work.

 

Yours,

Li

Message 4 of 12

Anonymous
Not applicable

I tried putting doIt into redoIt, but I had problems constructing the same data. I guess because I have a dagModifier and a dgModifier and call dagMod.doIt in the middle to create an object which can be connected to other nodes.

 

When I tried to run code with dagMod.doIt and dgMod.doIt in my doIt function and just run dagMod.doIt/dgMod.doIt in my redo function I still got DGNodes left.

I am not sure if i need to call undoIt/doIt on both Modifiers one time for each doIt in the right order or if I need to restructure the code to be able to have just one doIt call.

 

I currently implemented undoIt now by deleting the nodes, but I think this may damage the undo history as well.

0 Likes
Message 5 of 12

cheng_xi_li
Autodesk Support
Autodesk Support

Why are you using both MDGModifier and MDagModifier at the same time?

 

MDagModifier inherits MDGModifier it doesn't make sense to me.

 

Yours,

Li

0 Likes
Message 6 of 12

Anonymous
Not applicable

I thought you should always use DGModifier when you're using Dependencynodes which are not in the DAG. Something like the DG allowing circular connections while the DAG does not or similar. So I should just use a DagModifier? I'll try.

0 Likes
Message 7 of 12

cheng_xi_li
Autodesk Support
Autodesk Support

OK. I see your point. It should be separated. Let me try with your method now.

 

Yours,

Li

0 Likes
Message 8 of 12

cheng_xi_li
Autodesk Support
Autodesk Support
MStatus nodeInfo::doIt( const MArgList& args )
{
	dagModifier.createNode("mesh");
	dgModifier.createNode("lambert");
	dagModifier.doIt();
	dgModifier.doIt();
	return MS::kSuccess;
}

MStatus nodeInfo::redoIt()
{
	dagModifier.doIt();
	dgModifier.doIt();
	return MS::kSuccess;
}

MStatus nodeInfo::undoIt()
{
	dgModifier.undoIt();
	dagModifier.undoIt();
	return MS::kSuccess;
}

It is working fine, you'll need to call undoIt for both modifier. It also should be in order to prevent potential issues.

 

Yours,

Li

0 Likes
Message 9 of 12

Anonymous
Not applicable

This does not work for me.

 

my doIt only reads some input which should stay constant during undo/redo, then I call redoIt. I guess this should be fine.

In redoIt I create and rename Nodes and then apply this with the dagMod to connect them with the dgMod later.

 

The relevant pieces are mostly

 

undoIt:

 

        dagMod.undoIt();
        dgMod.undoIt();

doIt

doIt(const MArgList &args) {
	MStatus status;
	status = MGlobal::getActiveSelectionList(selList);
	return redoIt();
}

redoIt 

 

        MObject offsetMeshTransform = dagMod.createNode("transform");
        MObject offsetMesh = dagMod.createNode("mesh", offsetMeshTransform);
        dagMod.renameNode(offsetMeshTransform, "offsetMesh"); 
        dagMod.renameNode(offsetMesh, "offsetMeshShape"); 
        dagMod.doIt();
        MObject extractNode = dgMod.createNode(flatOffsetExtractNode::id);
        dgMod.connect(extractNodeOutOffsetMeshPlug, offsetInMeshPlug);
        while(!it.isDone()) {
                // some code to get the plugs
                dgMod.connect(worldMeshPlug, myInMeshPlug);        
        }
        dgMod.doIt();

 offsetMesh and extractNode need to be removed on undo and created again on redo. Currently they get deleted on undo but redo acts like it would both redo and execute the command again. This means when I undo/redo three times, I got four nodes and four meshes.

Another undo then removes all four, so this seems to work, just the next doIt seems to have the old operations still on the stack.

0 Likes
Message 10 of 12

cheng_xi_li
Autodesk Support
Autodesk Support
Accepted solution

Hi,

 

Are you still having createNode inside of redoIt? It should just have MDG/MDagModifier:doIt. All createNode or connecting code should be inside MPxCommand::doIt.

 

When Maya first executes ab undoable command, it will create a new MPxCommand and call doIt, then put it in the undo queue.

When it undos, Maya will find the latest command call undoIt.

When it redos, Maya will call its redoIt. So if you add all dg/dag action in redo it, you are adding it again when redoing the command. Because Maya will always call redoIt instead doIt. So, the correct way here is putting all dg related code inside doIt and just call MDG/MDagModifier::doIt inside redoIt to reuse previous dg/dag modifiers.

 

If you have already done that and it still doesn't work, could you let me have a look at a working sample code?

 

Yours,

Li

 

0 Likes
Message 11 of 12

Anonymous
Not applicable

Yes, I create them in redoIt. Sounds like that's the problem. I thought the main code should go into redoIt, like a node should do everything in compute.

I think try to isolate the createNode code into doIt and put the computation in redoIt then.

0 Likes
Message 12 of 12

Anonymous
Not applicable

I create the node and mesh in doIt and the rest is computed in redoIt. Seems to work fine now. Thank you.

0 Likes