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

    Write object to HyperFile

    SDK Help
    0
    13
    1.1k
    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 23/01/2013 at 11:05, xxxxxxxx wrote:

      Thanks for the input, Ferdinand. This is a good idea of yours. I will do some tests and report. 🙂

      Best,
      Niklas

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

        On 24/01/2013 at 06:43, xxxxxxxx wrote:

        Hello Ferdinand,

        unfortunately, my fears have been confirmed that the GeData only stores a link/reference to the
        BaseList2D object, not the object itself. So using WriteGeData() does not work at all. Thanks anyway!

        I am thinking about trying to replicate Cinema's  saving procedure for the object, if no built-in way
        is available. Am I missing something on the list that needs to be done written/read from the
        HyperFile?

        • Plugin ID
        • Container
        • Invoke NodeData::Write() / Read()

        Something like this maybe?

        /**
         * Retrieve the virtual method table of a NodeData plugin.
         */
        #define RetrieveTable(x, t, m) ((x)->*((t* )C4DOS.Bl->RetrieveTableX((x), 0))->m)
          
        /**
         * Write a BaseList2D plugin to a HyperFile.
         */
        Bool WriteBaseList2D(BaseList2D* node, HyperFile* hf) {
            NodeData* nd = node->GetNodeData();
            if (nd == NULL) return NULL;
          
            BaseContainer* container = node->GetDataInstance();
            if (!hf->WriteLong(node->GetType())) return FALSE;
            if (!hf->WriteContainer(*container)) return FALSE;
            if (!RetrieveTable(nd, NODEPLUGIN, Write)(node, hf)) return FALSE;
          
            return TRUE;
        }
        

        Seems legit, but how can I do the reading? Can I simply allocate a BaseList2D with the 
        plugin ID and call the NodeData's Read() method again?

        Also, I've just seen that C4DAtom has a Read() and Write() method. But I need to allocate an
        instance before I can call it's Read() method, so how am I supposed to Read() a C4DAtom
        when using it's Write() method?

        How can I obtain the disklevel of a plugin? This value is required for C4DAtom::Read() and
        NodeData::Read(), so either method I use, I need to obtain this value from somewhere.

        Thanks,
        Niklas

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

          On 24/01/2013 at 06:56, xxxxxxxx wrote:

          I was able to retrieve the disklevel like this:

          /**
           * Retrieve a value from the NodeDatas' table.
           */
          #define GetNodeAttribute(x, t, m) (((t* )C4DOS.Bl->RetrieveTableX((x), 0))->m)
            
          NodeData* nd = node->GetNodeData();
          LONG level = GetNodeAttribute(nd, NODEPLUGIN, disklevel);
          
          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 24/01/2013 at 07:24, xxxxxxxx wrote:

            hm,

            i cannot say so much really helpful, but nevertheless a few thoughts.

            Originally posted by xxxxxxxx

            Seems legit, but how can I do the reading? Can I simply allocate a 
            BaseList2D with the plugin ID and call the NodeData's Read() method again?

            hm, note sure how far this is related but i have once tried to store a baselist2d(renderdata) 
            outside of the c4d file in this way and i lost all children (the videopost). i could read the children, 
            but i could not write them back. not sure if it was my crappy coding, but i ended up rebuilding my renderdata from scratch.

            Originally posted by xxxxxxxx

            How can I obtain the disklevel of a plugin? This value is required for 
            C4DAtom::Read() and NodeData::Read(), so either method I use, I need to obtain this value
            from somewhere.

            at least for plugins the disklevel is just the revison, so you basically ignore it if you do not
            plan multiple versions with upwards comp - assume its default 0.

            the whole approach seems at least to me like trying to fit square into circle. why don't 
            you use a customdata type to store your custom data, when you are already in cpp.
            a rather cheap way could also be to write you custom data into an invisible variable tag 
            on your mainplugin instance just before your object is freed/stored and when it is alloctaed 
            agian you could read the data back into your baselist2d. all this depends of couse on the 
            nature of your data.

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

              On 24/01/2013 at 07:33, xxxxxxxx wrote:

              Originally posted by xxxxxxxx

              at least for plugins the disklevel is just the revison, so you basically ignore it if you do not
              plan multiple versions with upwards comp - assume its default 0.

              I need the disklevel of the object to write, not the disklevel of my own plugin. If my plugin reads
              in an object with another disklevel and I set it to 0 where it would actually support the new data
              from a higher disklevel, this would be incorrect (or inconvenient) behavior. However, I already
              figured out how to retrieve it, see my previous post. 🙂

              Originally posted by xxxxxxxx

              the whole approach seems at least to me like trying to fit square into circle. why don't 
              you use a customdata type to store your custom data, when you are already in cpp.
              a rather cheap way could also be to write you custom data into an invisible variable tag 
              on your mainplugin instance just before your object is freed/stored and when it is alloctaed 
              agian you could read the data back into your baselist2d. all this depends of couse on the 
              nature of your data.

              I do not just have some data, I have actual BaseObject instances that can be "packed" into my
              plugin. I don't know how I should represent this as a CustomDataType. And there, I would also
              need to write the objects to the HyperFile.

              Anyway, I just figured out how to do it. I'm not very happy with it, however. It would be nice
              to know how to use the C4DAtom::Read() method correctly rather than using my own code,
              because it would guaruntee everything is done correctly. I can imagine that I have forgotten
              something important.

              /\*\*
               \* Retrieve a virtual method from the NodeDatas' table.
               \*/
              #define GetNodeMethod(x, t, m) ((x)->\*((t\*)C4DOS.Bl->RetrieveTableX((x), 0))->m)
              
              /\*\*
               \* Retrieve a value from the NodeDatas' table.
               \*/
              #define GetNodeAttribute(x, t, m) (((t\*)C4DOS.Bl->RetrieveTableX((x), 0))->m)
              
              /\*\*
               \* Write a BaseList2D plugin to a HyperFile.
               \*/
              Bool WriteBaseList2D(BaseList2D\* node, HyperFile\* hf) {
                  NodeData\* nd = node->GetNodeData();
                  if (nd == NULL) return NULL;
              
                  BaseContainer\* container = node->GetDataInstance();
                  if (!hf->WriteLong(node->GetType())) return FALSE;
                  if (!hf->WriteContainer(\*container)) return FALSE;
                  if (!GetNodeMethod(nd, NODEPLUGIN, Write)(node, hf)) return FALSE;
              
                  return TRUE;
              }
              
              /\*\*
               \* Read a BaseList2D plugin from a HyperFile.
               \*/
              Bool ReadBaseList2D(BaseList2D\*& node, HyperFile\* hf) {
                  LONG pluginId;
                  BaseContainer container;
                  if (!hf->ReadLong(&pluginId)) return FALSE;
                  if (!hf->ReadContainer(&container, FALSE)) return FALSE;
              
                  /\* Allocate a new BaseList2D instance. \*/
                  node = BaseList2D::Alloc(pluginId);
                  if (node == NULL) return FALSE;
                  NodeData\* nd = node->GetNodeData();
                  if (nd == NULL) {
                      BaseList2D::Free(node);
                      return FALSE;
                  }
              
                  LONG disklevel = GetNodeAttribute(nd, NODEPLUGIN, disklevel);
                  if (!GetNodeMethod(nd, NODEPLUGIN, Read)(node, hf, disklevel)) return FALSE;
              
                  node->SetData(container);
                  return TRUE;
              }
              

              Best,
              Niklas

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

                On 24/01/2013 at 07:38, xxxxxxxx wrote:

                I just realized that this method does also not include the children of the object. I would
                need to go on recursively for the children of the object to be written. Tags are not included as well.

                How can I use C4DAtom::Read() correctly? An example would be very nice.
                *poking the MAXON support*
                🙂

                Thanks,
                Niklas

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

                  On 24/01/2013 at 09:21, xxxxxxxx wrote:

                  Hi Niklas,

                  Have you considered inserting the BaseObject in the document?

                  C4DAtom's Write()/Read() and WriteObject()/ReadObject() methods are actually rather private and as stated in the docs, not recommended for plugins.
                  The developers recommend to save the objects as C4D documents rather than hyperfiles using a dummy document and SaveDocument()/LoadDocument().

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

                    On 24/01/2013 at 09:31, xxxxxxxx wrote:

                    Hello Yannick,
                    thanks for your answer.

                    I was already considering creating a "fake" document, insert all my private objects and save
                    this document to the HyperFile. I could've sworn there was a fucntion to save a document to
                    a HyperFile, but I can't find it anymore (so I guess, there isn't). Possibly I'm just missing something
                    obvious?

                    Using the SaveDocument()/LoadDocument() functions, I'd need to write my objects to a seperate
                    file. This would be very inconvenient IMO. I'd like them to be written to the HyperFile passed on
                    my ObjectData's Write(). (the same for reading of course)

                    Thank you,
                    -Niklas

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

                      On 24/01/2013 at 10:01, xxxxxxxx wrote:

                      PS: Just tried this, and it doesn't work. Even looks unnatural, because the ID is provided twice,
                      but was worth a try. 😉

                      Bool ReadBaseList2D(BaseList2D*& node, HyperFile* hf) {
                          LONG pluginId;
                          if (!hf->ReadLong(&pluginId)) return FALSE;

                      /* Allocate a new BaseList2D instance. */
                          node = BaseList2D::Alloc(pluginId);
                          if (node == NULL) return FALSE;
                          NodeData* nd = node->GetNodeData();
                          if (nd == NULL) {
                              BaseList2D::Free(node);
                              return FALSE;
                          }

                      LONG disklevel = GetNodeAttribute(nd, NODEPLUGIN, disklevel);
                          if (!node->Read(hf, pluginId, disklevel)) {    // ! returns FALSE
                              GePrint("C4DAtom::Read() failed.");
                              return FALSE;
                          }

                      return TRUE;
                      }

                      I've used C4DAtom::Write() in the write procedure of course.

                      PS: Using ReadObject()/WriteObject() instead doesn't work either. I get a MessageDialog
                      with "Incorrect File Structure" message.

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

                        On 25/01/2013 at 11:10, xxxxxxxx wrote:

                        Hi Niklas,

                        You can call SaveDocument()/LoadDocument() to write/read a document from a memory file.
                        Drawback of this solution is the the byte sequences saved by HyperFile::WriteMemory() will not be platform independent.

                        Here's some code:

                        Bool MyObjectData::Write(GeListNode *node, HyperFile *hf)
                        {
                            Filename file;
                            AutoAlloc<MemoryFileStruct> mfs;
                          
                            // Set the memory file sruct to store the data saved
                            file.SetMemoryWriteMode(mfs);
                            
                            // Save document to the file in memory
                            Bool res = SaveDocument(doc, file, SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, FORMAT_C4DEXPORT);
                            if (res)
                            {
                                void *data = NULL;
                                VLONG size;
                          
                                // Get the memory data that was written to the file in memory
                                mfs->GetData(data, size);
                                
                                // Write the memory data to the object's hyperfile
                                hf->WriteMemory(data, size);
                            }
                          
                        	return TRUE;
                        }
                          
                        Bool MyObjectData::Read(GeListNode *node, HyperFile *hf, LONG level)
                        {
                            void *data = NULL;
                            VLONG size;
                          
                            // Read the file stored in memory
                            Bool res = hf->ReadMemory(&data, &size);
                            if (res)
                            {
                                Filename file;
                          
                                // Set the file to read from the memory buffer
                                file.SetMemoryReadMode(data, size);
                          
                                // Load the document from the memory file
                                doc = LoadDocument(file, SCENEFILTER_OBJECTS, NULL);
                          
                                // Free the data! (See note in the docs at HyperFile::ReadMemory())
                                GeFree(data);
                          
                                // Kill the document!
                                KillDocument(doc);
                            }
                          
                        	return TRUE;
                        }
                        
                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 27/01/2013 at 12:01, xxxxxxxx wrote:

                          Hello Yannick,

                          thank you very much for the example. I did not know we can save a document to memory this

                          way. Using this method works perfectly!

                          Best,
                          Niklas

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