Generator crashes and guidance



  • I have a FILENAME in my res file for the generator that I reference similar to so:

    Bool dirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS::DATA);
    	
    	// if the frame changed since last time the object should be dirty
    	if (_frame != doc->GetTime().GetFrame(doc->GetFps()))
    		dirty = true;
    
    	// if user changed fps since the last time the object should be dirty, and we should recalculate our frame ranges
    	if (_frame != doc->GetTime().GetFrame(doc->GetFps())) {
    		dirty = true;
    		_loader.SetFrameTimes(doc->GetFps());
    	}
    
    	_frame = doc->GetTime().GetFrame(doc->GetFps());
    
    	if (!dirty)
    		return op->GetCache(hh);
    	else {
    		// always pass c4d back a null, otherwise the system will keep polling this function and get real annoying
    		lumiCache = BaseObject::Alloc(Onull);
    		lumiCache->SetName(op->GetName());
    
                   maxon::String file = bc->GetFilename(CACHEFILE).GetString();
                   
                   if (file.IsPopulated()) {
    			_loader.GetCacheManager()->Load(file, doc);
    
                            BaseObject* node = _loader.GetRoot()
                            while (node) {
                                node->InsertUnder(lumiCache);
                            }
    
    	lumiCache->Message(MSG_UPDATE);
    	return lumiCache;
    

    The objects it inserts could be cameras, lights, meshes, splines, etc.



  • @eldiren

    You should not store the pointers to the BaseObjects in a std::vector. Instead use BaseLinks. Store them in a BaseArray, you may have to put them i a struct and add the struct to the BaseArray.

    The reason for using a BaseLink is because C4D can delete the BaseObjects and change them. The BaseLinks are correctly updated to point to the new object pointers.

    So your std::vector is most likely pointing to random memory which is causing your random crashes.

    This is because C4D is owning the objects if you are just passing them back in the GetVirtualObjects method.

    If you want to own them and keep a pointer to them yourself then there is a flag for generators that you can pass in when you register the generator object. In this case storing the pointer like you are doing is fine as long as you make sure you handle all read, write and copyto methods to correctly duplicate all internal objects that the generator, ie you, own.

    I am on my phone at the moment so can’t give an example, I am sure someone else will post something up if you need it. Including the flag. Otherwise I will find it tomorrow for you and post it up.

    Kent



  • Hi,

    well, what the type referenced with the _loader attribute does would be also important. However, if I am not overlooking something the following part is an infinite loop:

    BaseObject* node = _loader.GetRoot()
    while (node) {
        node->InsertUnder(lumiCache);
    }
    

    node will always be True (if _loader did not return the null pointer in the first place) and therefore probably be responsible for some of the crashes; you are missing a break condition, something that modifies node. The current code is also trying to insert the same node multiple times (which is not allowed in a c4d graph). You are probably trying to traverse a node graph and missing some kind of next node logic?

    Cheers
    zipit



  • I'm sorry, I kept the code sample brief and changed some stuff to protect my code.

    while (node) {
    				// add obj to virtual hierarchy
    				if (!node->GetUp() // the parent is root
    					node>InsertUnder(lumiCache);
    
    				obj = _loader.GetNextObject();
    			}
    

    This is closer to what the actual function looks like, the loader gets the next object form the caching format and does some processing to make it a BaseObject. Since I'm creating a number of BaseObject, I'm wondering about ownership, does C4D own these once their inserted and passed back via GetVirtualObjects(), or am I still responsible for them, because right now I'm just throwing them in there and not maintaining them. Behind the scenes my loader holds these cache objects in a std::vector for later run when it get dirty. Maybe something with that state is also causing issues?



  • @eldiren

    You should not store the pointers to the BaseObjects in a std::vector. Instead use BaseLinks. Store them in a BaseArray, you may have to put them i a struct and add the struct to the BaseArray.

    The reason for using a BaseLink is because C4D can delete the BaseObjects and change them. The BaseLinks are correctly updated to point to the new object pointers.

    So your std::vector is most likely pointing to random memory which is causing your random crashes.

    This is because C4D is owning the objects if you are just passing them back in the GetVirtualObjects method.

    If you want to own them and keep a pointer to them yourself then there is a flag for generators that you can pass in when you register the generator object. In this case storing the pointer like you are doing is fine as long as you make sure you handle all read, write and copyto methods to correctly duplicate all internal objects that the generator, ie you, own.

    I am on my phone at the moment so can’t give an example, I am sure someone else will post something up if you need it. Including the flag. Otherwise I will find it tomorrow for you and post it up.

    Kent



  • Hi @eldiren , thanks for reaching out us.

    With regard to the random crashes I second the comment from @kbar about storing BaseObject pointers in a std::vector. We'll never cease to stress enough about the relevance of BaseLink when reference to C4DAtom instances needs to be handled. A BaseLink Manual can be found in our C++ API documentation together wtih some notes to the BaselinkArray - a specialized BaseArray - designed to store multiple BaseLinks in a convenient way.

    Last but not least please have a look at the C4DAtom::CopyTo section in the C4DAtom Manual where the scope of both C4DAtom::CopyTo() and C4DAtom::Clone()` are discussed.

    @kbar : can you comment more on the flag for generators that you can pass in when you register the generator object to directly make use of BaseObject pointers?

    Cheers, R



  • I might be wrong, but I think he was referring to the flag OBJECT_DONTFREECACHE.



  • @zipit said in Generator crashes and guidance:

    OBJECT_DONTFREECACHE

    Yes that is the flag. If you enable that flag then you own the objects. And you pass the pointer as the result of the GetVirtualObjects call. But you MUST ensure correct deletion of the objects when the generator is deleted. And you must handle all read/write/copyto calls correctly for your generator.



  • I've refactored my generator so it generates the BaseObjects more direct rather than through some proxy nodes, since I'm just thorw the BaseObject out there and not storing them in a intermediary, specifically a std::vector the renaming, random crashes, and Meakeditable crashes have gone away.

    I still have an issue with rotation via mouse and clipping. Since my generator does create OPolygon, OCamera, Olights, Osplines, etc. according to the docs I need to implement GetDimension(). I've recently done that in my Poly and spline generation code like so:

    	for (int i = 0; i < pnts.size(); i++) {
    		CacheVec pos = pnts[i];
    		Vector pnt(pos[0], pos[1], -pos[2]);
    		pntsPtr[i] = pnt;
    		_cacheBounds.AddPoint((Vector32)pnt);
    	}
    

    _cacheBounds being a private variable of the type SMinMax. In GetDimension I use it like so:

    	*mp = (Vector)_loader.GetCacheBounds().GetMp(); // Bounding box center
    	*rad = (Vector)_loader.GetCacheBounds().GetRad(); //box size
    

    The generator is still producing a situation where when I Alt+left click the camera moves about the pivot of scene rather than around the object I picked, and things clip randomly. When I make my generator editable I also still can't orbit about the objects. I wonder if I not setting up the PolygonObjects/SplineObjects properly.



  • @kbar said in Generator crashes and guidance:

    @zipit said in Generator crashes and guidance:

    OBJECT_DONTFREECACHE

    Yes that is the flag. If you enable that flag then you own the objects. And you pass the pointer as the result of the GetVirtualObjects call. But you MUST ensure correct deletion of the objects when the generator is deleted. And you must handle all read/write/copyto calls correctly for your generator.

    Thanks Kent for providing additional notes, but I think I need to clarify a bit about its real scope. The OBJECT_DONTFREECACHE allows generators to maintain their caches on their own which means that Cinema will not handle the cache deletion upon its generator object has been deleted. This flag is highly dangerous and should be used only in combination with a correct memory management design that secures against memory leaks.
    That said, this has no relation on the option to safely refer a BaseObject in the scene by directly storing or accessing its pointer. Again, safely accessing a reference to a BaseObject must be done via BaseLink.

    Cheers, R



  • About my most recent question related to SMinMax? I think it got lost in the discussion.



  • Hello,

    please open a new thread for that question, we will probably need your code. You can send it to us using our email sdk_support@maxon.net

    Cheers,
    Manuel


Log in to reply