Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Generator crashes and guidance

    Cinema 4D SDK
    c++
    5
    13
    1.8k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ferdinandF
      ferdinand
      last edited by ferdinand

      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

      MAXON SDK Specialist
      developers.maxon.net

      1 Reply Last reply Reply Quote 0
      • E
        eldiren
        last edited by

        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.

        1 Reply Last reply Reply Quote 0
        • ferdinandF
          ferdinand
          last edited by ferdinand

          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

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 1
          • E
            eldiren
            last edited by

            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?

            kbarK 1 Reply Last reply Reply Quote 0
            • kbarK
              kbar @eldiren
              last edited by kbar

              @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

              https://www.gamelogicdesign.com
              https://www.plugins4d.com

              1 Reply Last reply Reply Quote 0
              • r_giganteR
                r_gigante
                last edited by

                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

                1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand
                  last edited by

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

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • kbarK
                    kbar
                    last edited by

                    @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.

                    https://www.gamelogicdesign.com
                    https://www.plugins4d.com

                    r_giganteR 1 Reply Last reply Reply Quote 0
                    • E
                      eldiren
                      last edited by

                      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.

                      1 Reply Last reply Reply Quote 0
                      • r_giganteR
                        r_gigante @kbar
                        last edited by

                        @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

                        1 Reply Last reply Reply Quote 0
                        • E
                          eldiren
                          last edited by

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

                          1 Reply Last reply Reply Quote 0
                          • ManuelM
                            Manuel
                            last edited by

                            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

                            MAXON SDK Specialist

                            MAXON Registered Developer

                            1 Reply Last reply Reply Quote 1
                            • First post
                              Last post