[Closed] Instance Cloning when the Object is referencing the INode
which option do you go for
-
- object references new node (original node loses functionality)
-
- object references original node (new node has no functionality)
-
- object references all nodes (possible nonsensical functionality and other issues and probably not possible)
-
- disable instance and reference cloning (can’t seem to find an easy way to do this)
-
- other ?
looking into original post i see that the scenario is built-in. so, it’s how is it in max. Do you want to have a ‘special’ clone scenario? maybe it will be easier just add your own ‘clone’ method?
I went for other in the end, creating a NOTIFY_NODE_CLONED Notification handler, not ideal, but a makes any reference or instances clone into a copy clone. Though it doesn’t get “caught” with inst = instance node or ref = reference node in mxs but it does work with maxops.cloneNodes.
I’m sorry I can’t get into this issue deep… very busy right now. But the problem is very interesting, and I have met it before in my tasks. So, as soon as I have time, I will play with it.
heres the handler so far…
static void cloned_notify_proc(void* param, NotifyInfo* info)
{
INode* cloned_node = static_cast<INode*>(info->callParam);
Object* cloned_node_obj = cloned_node->GetObjectRef();
if(cloned_node_obj)
{
cloned_node_obj = cloned_node_obj->FindBaseObject(); // skip over any modifers (not that any work on this)
if(cloned_node_obj->SuperClassID() == GEN_DERIVOB_CLASS_ID) // is it a reference ?
{
IDerivedObject* dobj = static_cast<IDerivedObject*>(cloned_node_obj);
cloned_node_obj = dobj->GetObjRef(); // it is so get what it's derived from
}
if(cloned_node_obj->ClassID() != XFORM_MONITOR_CLASS_ID) return; // this clone is not our's to interfere with so bum out
}
// get the object the the new node is references
XFormMonitor* cloned_xfm_obj = static_cast<XFormMonitor*>(cloned_node_obj);
if(!cloned_xfm_obj || cloned_xfm_obj->GetThisNode() == cloned_node) return; // already a copy clone op
// get the object we are cloning from
XFormMonitor* src_xfm_obj = static_cast<XFormMonitor*>(param);
if(!src_xfm_obj || src_xfm_obj->GetThisNode() == cloned_node) return; // catch whether the src node and new node the same ?
// so we now have 2 different nodes and one xfm object so make the cloned_node a nice "unique" xfm object of it's own
// it's "this node" (cloned_node) will be caught and assigned to the object when the node references it in SetObjectRef.
XFormMonitor* unique_xfm_obj = static_cast<XFormMonitor*>(src_xfm_obj->Clone());
if(unique_xfm_obj)
cloned_node->SetObjectRef(unique_xfm_obj);
if(src_xfm_obj != cloned_xfm_obj)
cloned_xfm_obj->DeleteThis(); // delete the derived object the reference was referencing
}
a couple of notes…
GetThisNode() if a function that returns the node from a INodeTransformMonitor reference that our object maintains.
It’s weird/unusal notify event because it’s not as general as most so every node that is cloned will fire off this event but with our this pointer attached (regardless of class) and if we have 20 of our nodes in the scene that’s 20 different events ready to be fired off when cloning something completely unrelated which is pretty bonkers. It’s was quite amusing and a tad bizarre turning boxes into helpers when instance or reference cloning
perhaps the more “global” NOTIFY_POST_NODES_CLONED would be a better bet than trying to handle at an individual level though it would still need to be registered with the class and not in each constructor. hmmmm.
turns out the NOTIFY_POST_NODES_CLONED was a much better solution, put the registration in LibInitialize
__declspec(dllexport) int LibInitialize()
{
RegisterNotification(notify_post_nodes_cloned_proc, NULL, NOTIFY_POST_NODES_CLONED);
return TRUE;
}
with the function now looking like this…
struct npnc_callparam
{
INodeTab* origNodes;
INodeTab* clonedNodes;
CloneType cloneType;
};
void notify_post_nodes_cloned_proc(void *param, NotifyInfo* info)
{
npnc_callparam* params = static_cast<npnc_callparam*>(info->callParam);
if(params->cloneType == NODE_COPY) return;
INodeTab& origNodes = *params->origNodes;
INodeTab& clonedNodes = *params->clonedNodes;
assert(origNodes.Count() == clonedNodes.Count());
for(int i = 0; i < origNodes.Count(); ++i)
{
INode* orig_node = origNodes[i];
Object* orig_obj = orig_node->GetObjectRef();
orig_obj = orig_obj->FindBaseObject();
if(orig_obj && orig_obj->ClassID() == XFORM_MONITOR_CLASS_ID)
{
INode* cloned_node = clonedNodes[i];
Object* cloned_obj = cloned_node->GetObjectRef();
XFormMonitor* unique_xfm_obj = static_cast<XFormMonitor*>(orig_obj->Clone());
cloned_node->SetObjectRef(unique_xfm_obj);
if(params->cloneType == NODE_REFERENCE && cloned_obj && cloned_obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
cloned_obj->DeleteThis();
}
}
}
}
much neater solution all round
what is ‘instance’ and ‘reference’? (correct me if I’m wrong):
- two nodes are instances if their RefObjects are the same
- two nodes are references if their reference targets are the same
- two nodes are references but not instances if their reference targets are the same but their refobjects are different (other way they are instances)
- two objects are instances or references if their reference targets are the same
what any other relation can be possible?
there is another case – World Space Modifier Object. But let’s forget about this case for now…
isn’t a reference just a node referencing an IDerivedObject where it’s ObjRef points to the original object
so you have two nodes:
- NODE_A – node with modifiers
- NODE_B – some node
and you want to replace Derived Object of NODE_A with ObjRef of NODE_B. Right?
delete objects
b0 = box()
b1 = reference b0 pos:[40,0,0]
addmodifier b1 (edit_poly())
b2 = instance b1 pos:[80,0,0]
make a changes in the setup the way you want