Generator crashes and guidance
-
I have a relatively complicated generator. It's loads a caching format similar to Alembic and builds and internal hierarchy in GetVirtualObjects. I need a little bit of clarity, and info is strewn in a lot of different places, it's hard to piece together.
My generator doesn't get centered on when Alt left clicking with the mouse and moving and it blinks out of view and certain camera angles, I assume something is wrong maybe with my bounds for that?
My generator crashes C4D when Ctrl copied, and when placing it under something that is being instanced. I assume CopyTo and my lack of an implementation of it might be the culprit?
My generator crashes when renaming, something probably to do with CopyTo again maybe?
Thanks for the insights on this matter.
-
Hi,
without you giving us more information on what your code is doing systematically and practically (code snippets) it is impossible to give you any reasonable advice; will end up in pure speculation.
Your problems do not clearly fall into one category of possible causes for the described behaviours. Especially the viewport related ones are odd, since a generator should be static regarding viewport operations, rely on its cache, unless you have specifically designed it to operate otherwise.
NodeData::CopyTo()
usually has only to be implemented when you have to alter data of your node when it is copied. Which could be the case for you, depending on how you handle your "alembic-like caching format", but should neither be needed for renaming nor copying in "normal" cases.Cheers,
zipit -
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.
-
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 beTrue
(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 modifiesnode
. 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?
-
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 [email protected]
Cheers,
Manuel