Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    SceneHook & GeDialog initialization [SOLVED]

    SDK Help
    0
    9
    919
    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.
    • H
      Helper
      last edited by

      On 30/04/2016 at 00:55, xxxxxxxx wrote:

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

      ---------
      Hello,

      I stumbled upon a little problem when accessing a scenehook from a Dialog.
      I integrated my Dialog into my Layout and from there I want to access my Scenehook.
      The problem is, that the Scenehook is initialized after the Dialog, so my scenehook pointer is always nullptr when creating a new scene.

      I know, I can add additional checks to my Dialog actions and set the SceneHook if neccessary. But is there another way? Maybe catching a message when the scenehook has been initialized or something?

      Thanks in advance,
      Robert

      edit:
      Never mind, figured it out.
      Thanks to the ActiveObject SDK example, EVMSG_CHANGE is the way to go. 🙂

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 01/05/2016 at 14:29, xxxxxxxx wrote:

        Another thing I noticed though:
        I'm currently inserting BaseList2D(NodeData) elements to my SceneHook. When calling "Reload Python plugins", my elements get removed from the document. Even if they are saved to the doc. (Something similar happens with e.g. Object ID-Multipasses - you can see that in the ActiveObjectDialog; it "loses" track of those passes)
        Is this normal behaviour?
        Can I prevent this somehow? (I suppose that using ObjectData solves this issue).

        Any hints would be appreciated. 🙂

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 02/05/2016 at 02:06, xxxxxxxx wrote:

          Hello,

          how exactly do you store elements in your ScenHook and how do you reference these elements? To properly store NodeData elements with a SceneHook (or any other NodeData based class) you have to do the following:

          The host object (your scene hook) stores a GeListHead. This GeListHead takes ownership of the child elements you add to it. You must inform Cinema about this new tree branch by implementing GetBranchInfo(). Also make sure to handle the list head in Read(), Write() and CopyTo() so that a copy of the scene hook also contains the copies of the child elements.

            
          Int32 GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags)  
          {  
            Int32 count = SUPER::GetBranchInfo(node, info, max, flags);  
            
            if (!_branchHead)  
            return count;  
            
            if (count < max)  
            {  
            info[count].head = _branchHead;  
            info[count].name = &_branchName;  
            info[count].id = 123456;  
            info[count].flags = BRANCHINFOFLAGS_0;  
            
            count++;  
            }  
            
            return count;  
          }  
          

          I would recommend to use your scene hook to access the stored elements and not to store references of the elements themselves.

          Best wishes,
          Sebastian

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 02/05/2016 at 02:26, xxxxxxxx wrote:

            Hey Sebastian,

            thanks for the reply.
            I'm currently doing exactly the same in the example you provided. (Except that you return the parent BranchCount if head does not exist - will add that check and see, if that makes any difference).

            I'm currently using a method in a worker class that's called by my GeDialog to allocate my elements.
            Then I'm requesting the branch info to insert the allocated nodes into the desired ListHead.

            I'll post some code this evening to rule out any mistakes made by myself. 🙂

            edit: Totally forgot about CopyTo(). How will this method have to look like? Would it be sufficient to Store, Read and Copy just the ListHead?

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 02/05/2016 at 12:09, xxxxxxxx wrote:

              Okay, here's my (shortened) code so far:

              SceneHook:

                
              class MySceneHook : public SceneHookData   
              {   
              public:   
                   static NodeData* Alloc(void);   
                   virtual Bool Init(GeListNode* node) override;   
                   virtual Bool Read(GeListNode* node, HyperFile* hf, Int32 level) override;   
                   virtual Bool Write(GeListNode* node, HyperFile* hf) override;   
                   virtual Int32 GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags) override;   
              private:   
                   AutoAlloc<GeListHead> _nodelist;   
                   String _name = "Test Branch";   
              };   
                
              NodeData* MySceneHook::Alloc(void)   
              {   
                   return NewObjClear(MyceneHook);   
              }   
                
              Bool MySceneHook::Init(GeListNode* node)   
              {   
                   if (!_nodelist || !node)   
                        return false;   
                
                   _nodelist->SetParent(node);   
                   return true;   
              }   
                
              Bool MySceneHook::Read(GeListNode* node, HyperFile* hf, Int32 level)   
              {   
                   return _nodelist->ReadObject(hf, true);   
              }   
                
              Bool MySceneHook::Write(GeListNode* node, HyperFile* hf)   
              {   
                   return _nodelist->WriteObject(hf);   
              }   
                
              Int32 MySceneHook::GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags)   
              {   
                   if (!node)   
                        return 0;   
                
                   info[0].head = _nodelist;   
                   info[0].name = &_name;   
                   info[0].id = MY_SCENEHOOK_PID;   
                   info[0].flags = BRANCHINFOFLAGS_0;   
                
                   return 1;   
              }   
                
              Bool RegisterMySceneHook(void)   
              {   
                   return RegisterSceneHookPlugin(MY_SCENEHOOK_PID, MY_SCENEHOOK_PNAME, PLUGINFLAG_SCENEHOOK_SUPPORT_DOCUMENT_DESCRIPTION, MySceneHook::Alloc, EXECUTIONFLAGS_0, NULL);   
              }   
              

              Worker:

                
              class MyWorker   
              {   
              // ...   
              public:   
                   void Init();   
                   void AddNode();   
              private:   
                   GeListHead* GetNodeRoot();   
                   BaseSceneHook* _sceneHook = nullptr;   
              };   
                
              void MyWorker::AddNode()   
              {   
                   if (!_sceneHook)   
                        return;   
                   BaseList2D* node = BaseList2D::Alloc(MY_NODE_PID);   
                
                   GeListHead* head = GetNodeRoot();   
                   BaseList2D* node = static_cast<BaseList2D*>(head->GetDown());   
                
                   if(!node)   
                        return;   
                
                   node->InsertUnderLast(head);   
                   // node->SetParameter(...);   
                   EventAdd();   
              }   
              

              GeDialog:

                
              class MyDialog : public GeDialog   
              {   
              public:   
                   //...   
              private:   
                      //...   
                   MyWorker worker;   
              };   
                
              Bool MyDialog::Command(Int32 id, const BaseContainer& msg)   
              {   
                   switch (id)   
                   {   
                   case MY_ID:   
                        worker.AddNode();   
                        break;   
                   }   
                   return true;   
              }   
              

              By guessing around, I think to following happens:
              When calling "Reload python plugins" for example, The Document gets re-initialized. This means, that also the scenehook gets destroyed and re-allocated. So does the _nodelist - so it's empty, which is quite logical.
              But after that, "ReadObject()" is not called again, so the nodelist stays empty - which is also makes sense.

              But how am I able to "hold" these elements after re-allocating the Scenehook then?

              I have the feeling, it depends on the CopyTo() method being implemented? At least the docs suggest to do so.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 03/05/2016 at 01:29, xxxxxxxx wrote:

                Hello,

                as a rule of thumb one should always implement all three functions of Read(), Write() and CopyTo() if one of these functions is implemented. CopyTo() is especially important since it is relevant for undo handling.

                Best wishes,
                Sebastian

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 03/05/2016 at 10:44, xxxxxxxx wrote:

                  Originally posted by xxxxxxxx

                  Hello,as a rule of thumb one should always implement all three functions of Read(), Write() and CopyTo() if one of these functions is implemented. CopyTo() is especially important since it is relevant for undo handling.Best wishes,Sebastian

                  Thanks again Sebastian!

                  This was the right hint.

                  After implementing CopyTo() correctly, everything works as expected.
                  One question about though: What exactly happens when "Reload Py plugins" is called?

                  Here is the code that fixes the problem:

                    
                  Bool MySceneHook::CopyTo(NodeData* dest, GeListNode* snode, GeListNode* dnode, COPYFLAGS flags, AliasTrans* trn)   
                  {   
                       MySceneHook* desthook = static_cast<MySceneHook*>(dest);   
                       _nodelist->CopyTo(desthook->_nodelist, COPYFLAGS_0, trn);   
                       return true;   
                  }   
                  
                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 04/05/2016 at 00:37, xxxxxxxx wrote:

                    Hello,

                    for technical reasons the current BaseDocument will be reloaded when the Python plugins are reloaded.

                    Best wishes,
                    Sebastian

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 04/05/2016 at 01:26, xxxxxxxx wrote:

                      I see, thanks again. This thread can be marked as solved then. 🙂

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