Interesting behaviour with loaded object..[SOLVED]



  • On 02/10/2014 at 15:49, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R14 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Inside my plugin i`m using LoadDocument to load a c4d file into a temp doc, then grabbing an object out of the loaded doc, then cloning the object with GetClone, then freeing up the temp doc with Free, and then passing the new cloned object back to my main function and adding it into the ActiveDocument..

    The code looks like this:

    BaseObject* LoadMyObject(const String *objName)
    {
    	tempdoc = LoadDocument(GeGetPluginPath()+Filename("MyObjects.c4d"),SCENEFILTER_OBJECTS, NULL);
    	BaseObject *obj = tempdoc->SearchObject(*objName);
    	C4DAtom *newObj = obj->GetClone(COPYFLAGS_0,NULL);
    	//KillDocument(tempdoc);
    	BaseDocument::Free(tempdoc);
    	if (newObj == NULL) {
    		return NULL;
    	} else {
    		return (BaseObject* )newObj;
    	}
    }
    

    The interesting thing is that when i run my plugin, and the object loads and is displayed - if i then open the MyObjects.c4d scene and alter the source object in that and then save, the changes are automatically updated in the loaded object that my plugin is displaying..

    I kind of thought that as the object had been loaded then Cloned, then added to the current active document that it would have broken any ties with the original object.  I guess the fact that the line

    C4DAtom *newObj = obj->GetClone(COPYFLAGS_0,NULL);
    

    is returning a pointer means that it is still referencing the original..

    So two questions:

    1. So what is the point of GetClone if it`s just a pointer and not actually a clone?
    2. What would be the way to actually clone an object so that it is independent?

    Any ideas appreciated.



  • On 02/10/2014 at 16:13, xxxxxxxx wrote:

    I'm not sure as documentation is empty here, may be the COPYFLAGS_0 means shallow copy "just pointer" , and another flag means deep copy "whole memory copy"



  • On 02/10/2014 at 16:23, xxxxxxxx wrote:

    Usually a "temp doc" is created in memory. And then it get's tossed away.
    It never physically exists. So there's no danger of the temp doc doing what's happening to you.

    AutoAlloc<BaseDocument> tmpDoc;
    

    When a document is saved to the HD. It's no longer a "temporary document".
    That act of saving it to the HD turns it  into a "permanent document".

    -ScottA



  • On 02/10/2014 at 16:41, xxxxxxxx wrote:

    Im not saving the doc Scott im loading it in to grab objects from it..



  • On 02/10/2014 at 16:58, xxxxxxxx wrote:

    Sorry i think i see the confusion - what i meant was when i run c4d and use my plugin, if i then open the MyObjects.c4d file and say scale my object and hit Save, the changes are reflected immediately in my scene with the plugin running ( which references the MyObjects.c4d file ), if that makes sense..

    So my point is, even though I've cloned the object inside my plugin via GetClone, its still referencing the original object..



  • On 02/10/2014 at 17:57, xxxxxxxx wrote:

    Yeah. It's a confusing name to use.
    I would personally call it the "source doc" instead of "temp doc".

    I've never needed to do a distinct copy like that. Because I always use a traditional temp doc and then delete it right away. Which breaks any connections between them.
    But I do know that of you want to copy a rigged character. You have to use AliasTrans to get another copy of it.

        PolygonObject *obj = (PolygonObject* ) doc->GetActiveObject();  
      if(!(obj && (obj->GetType() == Opolygon))) return FALSE;  
      
      AutoAlloc<AliasTrans> aliastrans;  
      if(!aliastrans || !aliastrans->Init(doc)) return FALSE;  
      
      C4DAtom *copy = obj->GetClone(COPYFLAGS_0, aliastrans);  
      if(!copy) return FALSE;  
      
      aliastrans->Translate(TRUE);  
      
      BaseObject *cloneObj = (BaseObject* )copy;  
      doc->InsertObject(cloneObj, NULL, NULL);
    

    I don't know if that will work for you or not.
    I don't know  that much about how and when to use AliasTrans. It might only be for keeping any linkfield data in tact. And not have anything to do with creating a new distinct copy of the object

    -ScottA



  • On 02/10/2014 at 19:04, xxxxxxxx wrote:

    AliasTrans breaks the connections to the old 'object' and makes new ones for the new 'object'.  It really is a must when doing certain copies with references (links) involved.  When the old ones continue to exist, you can get away without it.  When the old ones are going away and new ones are created, you need to have C4D update those references to maintain rational connections or they won't work any longer.



  • On 03/10/2014 at 04:07, xxxxxxxx wrote:

    Hmmmm.  Thanks for the ideas folks.  I still can`t get my cloned object to be independant from the source doc.

    Have tried a few different combinations, including Initialising the AliasTrans with both the Active Doc and the source Doc.  Also, the documentation says that AliasTrans is for updating baselinks, i`m not using baselinks at all but i though maybe there might be one internally which references the original object in the source doc..  *shrugs*

    I also thought that if the cloned object is still referencing the original object from the source doc, that the line BaseDocument::Free(sourcedoc) would probably throw an error or cause the object to not appear, but it doesnt the object still shows.  Also tried the line thats commented out below ( KillDocument(sourcedoc); ) which makes no difference to that either.

    So a bit stuck at the moment.  Have updated the code with AliasTrans and changed the doc name to sourcedoc just for you Scott :)

    BaseObject* LoadMyObject(const String *objName)
    {
    	BaseDocument *doc = GetActiveDocument();
      
    	BaseDocument *sourcedoc = LoadDocument(GeGetPluginPath()+Filename("MyObjects.c4d"),SCENEFILTER_OBJECTS, NULL);
    	BaseObject *obj = sourcedoc->SearchObject(*objName);
      
    	AutoAlloc<AliasTrans> aliastrans;
    	if(!aliastrans || !aliastrans->Init(doc)) return NULL;
    	//if(!aliastrans || !aliastrans->Init(sourcedoc)) return NULL;  // Tried this also
      
    	C4DAtom *newObj = obj->GetClone(COPYFLAGS_0,aliastrans);
    	
    	aliastrans->Translate(TRUE);
    	
    	//KillDocument(sourcedoc);
    	BaseDocument::Free(sourcedoc);
      
    	if (newObj == NULL) {
    		return NULL;
    	} else {
    		return (BaseObject* )newObj;
    	}
    }
    

    Maybe i have to actually insert the object into the ActiveDoc before it`ll break ties?  *shruggety shrug*



  • On 03/10/2014 at 07:41, xxxxxxxx wrote:

    If AliasTrans doesn't work. There's no need to keep it in there just for me. 🙂
    I was basically just taking a guess.

    I would try the other flags like Mohamed suggested.
    And if that doesn't work. Then I guess I would try to free the individual object pointers rather than the source document. And see if that works.

    -ScottA



  • On 03/10/2014 at 14:03, xxxxxxxx wrote:

    Scott it was the doc name i changed to sourcedoc just for you :)

    The other flags don`t look relevant at all but i could test them out..

    Freeing the individual object pointers i guess is an idea..

    Any word from the Maxon guys on this ie how to duplicate an object completely?



  • On 06/10/2014 at 02:52, xxxxxxxx wrote:

    Hi guys,
    just wanted to let you know, that you are not forgotten and I'll dig into this.
    But as you might know, I'm still in a learning process, so I need to ask for a bit your patience.



  • On 06/10/2014 at 07:02, xxxxxxxx wrote:

    Thanks that`d be appreciated..

    I can live with it at the moment but would like to know at some point if this is the expected behaviour and/or the right way of going about the cloning i described..



  • On 06/10/2014 at 08:29, xxxxxxxx wrote:

    Hi,

    your code looks just fine (even the first). There is no AliasTrans necessary. GetClone will always give you a clone independant from the flags used.

    There should be no dependancies after this call and you definetly take over the ownership. It's hard to say if this is a follow-up error. What kind of plugin are you executing your code in?



  • On 06/10/2014 at 14:40, xxxxxxxx wrote:

    Hi Katachi,

    Its an Object Generator plugin.  A simplified version of how it flows at the moment is - The GVO function calls Function A.  Function A does some stuff, and calls Function B ( which is my doc/object loader function above ) which returns the loaded BaseObject to Function A, which then returns it to the GVO.  And thats about it.

    Plugin is registered with the OBJECT_GENERATOR and OBJECT_INPUT flags ( although i could prob have just used generator ).



  • On 07/10/2014 at 00:00, xxxxxxxx wrote:

    I think, I solved your problem.
    Is it possible, that you are calling LoadMyObject() on every call of GVO? At least that's how a I was able to reproduce the described behaviour. Basically I suppose you are reloading the scene and importing the object from the MyObjects.c4d scene on every requested update. That's why you get the updated object only AFTER you save MyObjects.c4d. The connection is not in memory, but on your harddisc.

    Just in case, I understood something wrong, here's what I did to test on my side:
    I took the RoundedTube.cpp from cinema4dsdk examples, replaced the code in GVO with a call to your LoadMyObject() function. I created a new scene MyObjects.c4d containing a default cube and a default sphere and closed it. Then I called the changed RoundedTube plugin (I didn't care for elaborate code, so the sphere only showed up after a forced viewport update). Then I loaded the MyObjects.c4d and changed the sphere size. Up to now, the "rounded tube scene" is still fine. The moment I saved the MyObjects.c4d and returned to the rounded tube scene, I got the updated sphere. The reason I explained above.



  • On 07/10/2014 at 01:03, xxxxxxxx wrote:

    I haven't tested it but guess it's enough Andreas did. In one of your above scenes you wrote you are inserting it into the currently active scene. Please be aware that in general it is forbidden to modify the current scene in any way out of a GetVirtualObjects call!



  • On 07/10/2014 at 02:28, xxxxxxxx wrote:

    Andreas that is absolutely correct you solved it.  Damnit why didnt i see that!  Im calling it from GVO and it is reloading each time.. *slow gratuitous facepalm*  Thanks for taking the time!

    Katachi Im still getting used to what is and isnt good practice so thanks for the heads-up.  What i`ll do here is i think load the object elsewhere ( possibly from Init ), and then clone and return it via my GVO routines..

    Thanks for the help folks!



  • On 07/10/2014 at 02:43, xxxxxxxx wrote:

    You are welcome. I'm glad I could help (my first solved issue as an MAXON employee, yeah! 🙂), everybody's making errors and often it's hard to see the wood in between all those trees.

    A small advice, although you might already know:
    The console (to be opened from the scripts menu) is a very good friend. In conjunction with GePrint() (or its friends from the debug front) this can work miracles to get an overview, who is called how often and in what order. GVO for example is called quite often. You do good to double check your code in there and invest some time to optimize it.
    And even more mighty, the good old debugger. Even though you don't have the source for C4D, you can very well use the debugger to step through your plugin. On Windows ind VisualStudio (Express is fine) simply put CINEMA 4D's exe in your project settings under Debug->Debug Command. Beginning with R15 it's a good idea to add -g_alloc=debug as command argument, for versions before R15 simply put an empty text file called c4d_debug.txt next to your cinema.exe, in order to get even more information.


Log in to reply