[Closed] SDK – PolyObject modify verts not undoable
Hello,
I have written a function in the Max SDK that takes a delta offset and applies it to all verts in the given editable poly.
It works as expected, however the action is not undoable, which is confusing as if I use a function that manipulates a TriMesh rather than a MNMesh it is undoable.
I cannot use the TriMesh function as it causes any custom attributes on my editable poly object to be lost as it is converting the object to an Editable Mesh.
I am not sure what I could be missing, other than TriMesh has undo functionality included and MNMesh does not.
Here is the function that modifies the MNMesh:
PolyObject* GetPolyObjectFromNode(INode* inNode, TimeValue inTime, bool& deleteIt)
{
Object* object = inNode->GetObjectRef();
if (object->CanConvertToType(Class_ID(POLYOBJ_CLASS_ID, 0)))
{
PolyObject* polyObject = (PolyObject*)object->ConvertToType(inTime, Class_ID(POLYOBJ_CLASS_ID, 0));
// Note that the polyObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
if (object != polyObject) deleteIt = true;
return polyObject;
}
else
{
return NULL;
}
}
static bool applyOffsetToVertices(INode* inNode, Point3 inOffset)
{
static bool success = false;
bool deleteIt = false;
bool polyDeleteIt = false;
Interface* coreInterface = GetCOREInterface();
PolyObject* polyObject = GetPolyObjectFromNode(inNode, coreInterface->GetTime(), deleteIt);
if (polyObject)
{
MNMesh& mesh = polyObject->GetMesh();
for (int vertIndex = 0; vertIndex < mesh.VNum(); vertIndex++)
{
MNVert* vert = mesh.V(vertIndex);
vert->p += inOffset;
}
inNode->SetObjectRef(polyObject);
polyObject->FreeCaches();
polyObject->NotifyDependents(FOREVER, OBJ_CHANNELS, REFMSG_CHANGE);
coreInterface->RedrawViews(coreInterface->GetTime());
success = true;
}
return success;
}
and here is the function that modifies the TriMesh:
TriObject* GetTriObjectFromNode(INode* inNode, TimeValue inTime, bool& deleteIt)
{
deleteIt = false;
Object* obj = inNode->EvalWorldState(inTime).obj;
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
{
TriObject* triObject = (TriObject*)obj->ConvertToType(inTime, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
if (obj != triObject) deleteIt = true;
return triObject;
}
else
{
return NULL;
}
}
static bool applyOffsetToVertices(INode* inNode, Point3 inOffset)
{
static bool success = false;
bool deleteIt = false;
TriObject* triObject = GetTriObjectFromNode(inNode, GetCOREInterface()->GetTime(), deleteIt);
if (triObject)
{
Mesh& mesh = triObject->GetMesh();
for (int vertIndex = 0; vertIndex < mesh.getNumVerts(); vertIndex++)
{
Point3 position = mesh.getVert(vertIndex);
mesh.setVert(vertIndex, position + inOffset);
}
mesh.InvalidateGeomCache();
mesh.InvalidateTopologyCache();
inNode->SetObjectRef(triObject);
triObject->NotifyDependents(FOREVER, OBJ_CHANNELS, REFMSG_CHANGE);
Interface* coreInterface = GetCOREInterface();
coreInterface->RedrawViews(coreInterface->GetTime());
success = true;
}
return success;
}
You’ll have to add your modification to the undo stack manually if it doesn’t do it internally. Look at the docs for “theHold”.
This is what I thought, I just wanted to make sure before I implemented undo logic myself.
Hey Denis,
Thanks for the reply.
I have found a bit of type to try your suggestion but I cannot quite figure out how the EPoly interface works.
It causes a memory error when I try to apply the offset using ApplyDelta.
Here is the code I have ( put together from digging around in the SDK for examples ):
static bool applyOffsetToVerticesEPoly(INode* inNode, Point3 inOffset)
{
static bool success = false;
bool deleteIt = false;
bool polyDeleteIt = false;
Interface* coreInterface = GetCOREInterface();
PolyObject* polyObject = GetPolyObjectFromNode(inNode, coreInterface->GetTime(), deleteIt);
if (polyObject)
{
EPoly* ePolyInterface = NULL;
ePolyInterface = (EPoly*)inNode->GetInterface(EPOLY_INTERFACE);
MNMesh& mesh = polyObject->GetMesh();
Tab<Point3> deltaTab;
deltaTab.SetCount(mesh.VNum());
for (int index = 0; index < mesh.VNum(); index++)
{
deltaTab[index] = inOffset;
}
ePolyInterface->ApplyDelta(deltaTab, ePolyInterface, coreInterface->GetTime());
success = true;
}
return success;
}
Is there something I am missing?
Ignore me, I found the correct way straight after replying to you!
static bool applyOffsetToVerticesEPoly(INode* inNode, Point3 inOffset)
{
static bool success = false;
bool deleteIt = false;
bool polyDeleteIt = false;
Interface* coreInterface = GetCOREInterface();
PolyObject* polyObject = GetPolyObjectFromNode(inNode, coreInterface->GetTime(), deleteIt);
if (polyObject)
{
ObjectState objectState = inNode->EvalWorldState(coreInterface->GetTime(), true);
Object* nodeObjectBase = objectState.obj->FindBaseObject();
EPoly *ePolyInterface = (EPoly *)(nodeObjectBase->GetInterface(EPOLY_INTERFACE));
MNMesh& mesh = polyObject->GetMesh();
Tab<Point3> deltaTab;
deltaTab.SetCount(mesh.VNum());
for (int index = 0; index < mesh.VNum(); index++)
{
deltaTab[index] = inOffset;
}
ePolyInterface->ApplyDelta(deltaTab, ePolyInterface, coreInterface->GetTime());
success = true;
}
return success;
}
Thanks very much for the suggestion, it works a treat!