Possible to save BaseArray with document?



  • On 09/11/2013 at 01:08, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      
    Language(s) :

    ---------
    I have several BaseArrays "floating around" in memory. And some Null objects who are created at runtime and inserted into the document. When I save, close and reopen the C4D project file, the Null objects are there, as I left them. The BaseArrays are gone, as expected. Is there a way for the doument to also save a BaseArray? In My case, the BaseArray contains classes, who hold certain values like Real, Integers or Vectors.

    I know how to serialize objects like this (making a long string out of the object ans store it in a file), so this question is not about that. The question is to what extent it would be possible to tell the BaseDocument in a [magical] way to also store the BaseArray, warts and all. And when opening the project file again - poof - like magic, the BaseArray is there again, like magic I woulkd like to say..



  • On 09/11/2013 at 04:47, xxxxxxxx wrote:

    That is an interesting question.  Looking at the documentation for BaseArray, there is no Read()/Write() implementation.  That might be because you determine the type being stored within it (??) and BaseArray has not been designed to handle permanent storage facilities directly (i.e.: files).  What you might need to do is go through the members stored in the BaseArray and save/load them to/from file from your plugin's Write()/Read() methods and then, on Read(), store them into your BaseArray (using Append() or whatever).

    The 'magical' way is by using Read()/Write() to retain and reconstruct elements not stored in the plugin's BaseContainer (Descriptions).

    Note: If you are storing class instances in the BaseArray, it may be wise to implement your own Read()/Write() methods for the class, passing the HyperFile* from your plugin, so that the saving of the class's member variables is encapsulated.

    For instance:

    class MyClass  
    {  
      Real  fReal;  
      Vector  vVector;  
      Bool Write(HyperFile* hf)  
      {  
        if (!hf->WriteReal(fReal)) return FALSE;  
        if (!hf->WriteVector(vVector)) return FALSE;  
        return TRUE;  
      }  
      Bool Read(HyperFile* hf)  
      {  
        if (!hf->ReadReal(&fReal)) return FALSE;  
        if (!hf->ReadVector(&vVector)) return FALSE;  
        return TRUE;  
      }  
    };
    


  • On 09/11/2013 at 05:34, xxxxxxxx wrote:

    Yes I see there are several (many) predefined ways to write common classes to the hyperfile, even Matrices. I understand a complex class cannot be written just like that, so I accept this.  In any case, these Write / Read methods come in very handy and saves time and code.
    When reading the docs earlier today, I saw it mentioned somewhere that "plugin developers should not use Read / Write methods" or something like this, but I cannot find the chapter where it was mentioned.



  • On 09/11/2013 at 07:01, xxxxxxxx wrote:

    Howdy,

    Originally posted by xxxxxxxx

    ...When reading the docs earlier today, I saw it mentioned somewhere that "plugin developers should not use Read / Write methods" or something like this, but I cannot find the chapter where it was mentioned...

    this?:

    Note:  It is recommended to store as much as possible in the [BaseContainer](file:///Users/danlibisch/Documentation/C4D%20Manuals/R10%20SDK/pages/c4d_basecontainer/class_BaseContainer44.html) as CINEMA 4D will handle the reading of those values automatically. Only use member variables when necessary.

    Important:  If you implement at least one of [Read()](file:///Users/danlibisch/Documentation/C4D%20Manuals/R10%20SDK/pages/c4d_nodedata/class_NodeData872.html#read4), [Write()](file:///Users/danlibisch/Documentation/C4D%20Manuals/R10%20SDK/pages/c4d_nodedata/class_NodeData872.html#write5) and [CopyTo()](file:///Users/danlibisch/Documentation/C4D%20Manuals/R10%20SDK/pages/c4d_nodedata/class_NodeData872.html#copyto7), you must usually implement all three. Otherwise data might be lost.

    In my opinion, you should handle it the way Robert described. It wouldn't surprise me a bit if we could access the internal source code to "ReadVector()" it might have 3 "ReadReal()" calls within that function. 😉

    Adios,
    Cactus Dan



  • On 10/11/2013 at 04:12, xxxxxxxx wrote:

    Hi ingvarai,

    check this out:

    >
    > /* Copyright (c) 2013 Niklas Rosenstein
    > *
    > * Permission is hereby granted, free of charge, to any person obtaining a copy
    > * of this software and associated documentation files (the "Software"), to deal
    > * in the Software without restriction, including without limitation the rights
    > * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    > * copies of the Software, and to permit persons to whom the Software is
    > * furnished to do so, subject to the following conditions:
    > *
    > * The above copyright notice and this permission notice shall be included in
    > * all copies or substantial portions of the Software.
    > *
    > * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    > * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    > * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    > * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    > * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    > * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    > * THE SOFTWARE. */
    >
    > #include <c4d.h>
    >
    >
    > /* This class describes the interface for the writer and reader class that
    >
    >
    > is given as a template parameter to the ReadArray() and WriteArray()
    >
    >
    > functions. */
    > class HyperFileRW {
    >
    > public:
    >
    > Bool Read(HyperFile* hf, Real* dest, LONG disklevel) {
    > return hf->ReadReal(dest);
    > }
    >
    > Bool Read(HyperFile* hf, LONG* dest, LONG disklevel) {
    > return hf->ReadLong(dest);
    > }
    >
    > Bool Read(HyperFile* hf, Vector* dest, LONG disklevel) {
    > return hf->ReadVector(dest);
    > }
    >
    > Bool Read(HyperFile* hf, Matrix* dest, LONG disklevel) {
    > return hf->ReadMatrix(dest);
    > }
    >
    > /* More possible overloaded methods ... */
    >
    > Bool Write(HyperFile* hf, const Real value) {
    > return hf->WriteReal(value);
    > }
    >
    > Bool Write(HyperFile* hf, const LONG value) {
    > return hf->WriteLong(value);
    > }
    >
    > Bool Write(HyperFile* hf, const Vector& value) {
    > return hf->WriteVector(value);
    > }
    >
    > Bool Write(HyperFile* hf, const Matrix& value) {
    > return hf->WriteMatrix(value);
    > }
    >
    > /* More possible overloaded methods ... */
    >
    > };
    >
    > /* Write an array to a HyperFile. */
    > template <typename ArrayClass, typename WriterClass>
    > Bool WriteArray(HyperFile* hf, ArrayClass& array, WriterClass writer) {
    > /* Write the size of the array. */
    > LONG count = array.GetCount();
    > if (!hf->WriteLong(count)) return FALSE;
    >
    > /* And now each and every element. */
    > ArrayClass::ConstIterator it = array.Begin();
    > for (; it != array.End(); it++) {
    > if (!writer.Write(hf, *it)) return FALSE;
    > }
    >
    > return TRUE;
    > }
    >
    > /* Read an array from a HyperFile. */
    > template <typename Datatype, typename ArrayClass, typename ReaderClass>
    > Bool ReadArray(HyperFile* hf, ArrayClass& array, ReaderClass reader, LONG disklevel) {
    > /* Read the size of the array. */
    > LONG size;
    > if (!hf->ReadLong(&size)) return FALSE;
    >
    > /* Resize the array and fill in the values. */
    > array.Resize(size);
    > ArrayClass::Iterator it = array.Begin();
    > Datatype value;
    > for (; it != array.End(); it++) {
    > if (!reader.Read(hf, &value, disklevel)) return FALSE;
    > *it = value;
    > }
    >
    > return TRUE;
    > }
    >
    >
    > Bool PluginStart() {
    > GePrint("-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-");
    > GePrint("PluginStart(), running write/read tests...");
    >
    > /* In-memory file. */
    > AutoAlloc<MemoryFileStruct> mfs;
    > if (!mfs) {
    > GePrint("Could not allocate MemoryFileStruct.");
    > return FALSE;
    > }
    >
    > /* Write Test */
    > /* ---------- */
    >
    > /* Allocate the HyperFile. */
    > AutoAlloc<HyperFile> hf;
    > if (!hf) {
    > GePrint("Could not allocate HyperFile.");
    > return FALSE;
    > }
    >
    > /* Open a new HyperFile with the in-memory file. */
    > Filename mem;
    > mem.SetMemoryWriteMode(mfs);
    > if (!hf->Open(0, mem, FILEOPEN_WRITE, FILEDIALOG_NONE)) {
    > GePrint("Could not open HyperFile in WRITE mode.");
    > return FALSE;
    > }
    >
    > /* Create an array of vectors. */
    > c4d_misc::BaseArray<Vector> source_array;
    > source_array.Resize(100);
    > for (LONG i=0; i < 100; i++) source_array = Vector(SNoise(i), SNoise(i * i), SNoise(1 * 3 + 2)); /* And write the array to the file. */
    > if (!WriteArray(hf, source_array, HyperFileRW())) {
    > GePrint("Failed to write array.");
    > return FALSE;
    > }
    >
    > /* Close the HyperFile and report about our success. */
    > hf->Close();
    > GePrint("Array successfully written!");
    >
    > /* Read Test */
    > /* --------- */
    >
    > /* Retrieve a pointer to the data of the MemoryFileStruct. */
    > void* data = NULL;
    > VLONG data_size = -1;
    > mfs->GetData(data, data_size, FALSE);
    > if (!data) {
    > GePrint("Could not obtain data-pointer from MemoryFileStruct.");
    > return FALSE;
    > }
    >
    > /* And open the HyperFile in READ mode. */
    > hf.Free();
    > hf.Assign(HyperFile::Alloc());
    > if (!hf) {
    > GePrint("Could not allocated HyperFile.");
    > return FALSE;
    > }
    > mem.SetMemoryReadMode(data, data_size);
    > if (!hf->Open(0, mem, FILEOPEN_READ, FILEDIALOG_NONE)) {
    > GePrint("Could not open HyperFile in READ mode.");
    > return FALSE;
    > }
    >
    > /* Read the array. */
    > c4d_misc::BaseArray<Vector> read_array;
    > Bool result = ReadArray<Vector, c4d_misc::BaseArray<Vector>, HyperFileRW>(
    > hf, read_array, HyperFileRW(), 0);
    > if (!result) {
    > GePrint("Could not read array.");
    > return FALSE;
    > }
    >
    > GePrint("Array successfully read from HyperFile, checking results..");
    >
    > /* Do they have the same size? */
    > if (source_array.GetCount() != read_array.GetCount()) {
    > GePrint("> Sizes do not equal.");
    > return FALSE;
    > }
    >
    > /* Are the values equal? */
    > c4d_misc::BaseArray<Vector>::Iterator it1 = source_array.Begin();
    > c4d_misc::BaseArray<Vector>::Iterator it2 = read_array.Begin();
    > LONG index = 0;
    > for (; it1 != source_array.End() && it2 != read_array.End(); it1++, it2++, index++) {
    > if (*it1 != *it2) {
    > GePrint("> Elements at index " + LongToString(index) + " do not equal.");
    > return FALSE;
    > }
    > }
    >
    > GePrint("A pure success!");
    > return TRUE;
    > }
    >
    > Bool PluginMessage(LONG type, void* pData) {
    > switch (type) {
    > case C4DPL_INIT_SYS:
    > return resource.Init();
    > };
    > return TRUE;
    > }
    >
    > void PluginEnd() {
    > }

    You can easily use this to write any data you like.
    Best,
    -Niklas
    __



  • On 10/11/2013 at 11:20, xxxxxxxx wrote:

    Niklas - a million thanks for this, absolutely fantastic!
    I will definitely use this one, sehr nett von Dir!

    -Ingvar


Log in to reply