Variable size BaseArray in Hyperfile [SOLVED]



  • On 05/12/2016 at 07:49, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   14+ 
    Platform:   Windows  ; Mac  ;  
    Language(s) :     C++  ;

    ---------
    Hello,

    I would like to cache a BaseArray of vectors at every frame in the scene file, similar to particle system caching. I thought about using a Hyperfile for that, where I store all the positions of the particles in a HF and retrieve them at will.
    If I use a fixed size BaseArray, I am able to cache the array. If on the other hand I change the size of the array and save the scene, upon scene open, I get an Incorrect File Structure error and the scene would not load.
    Here is the code I am using to test the caching:

      
    class myObject : public ObjectData
    {
    	...
      
    public:
    	maxon::BaseArray<Vector>myVectors; // define myVectors as a class member BaseArray
    	...
    }
      
    // Init
    Bool myObject::Init(GeListNode *node)
    {
    	...
    	myVectors.Resize(10);  
    	LONG aa = myVectors.GetCount();
      
    	for (LONG i=0; i<aa; i++) myVectors[i] = Vector(i);
    }
      
    // Read and Write the Hyperfile
    Bool myObject::Read(GeListNode *node, HyperFile *hf, LONG level)
    {
    	if (level>=0)
    	{
    		for (LONG i=0; i<myVectors.GetCount(); i++)   // I think the problem resides here...
    		{
    			hf->ReadLVector(&myVectors[i]);
    		}
    	}
    	return TRUE;
    }
      
    Bool myObject::Write(GeListNode *node, HyperFile *hf)
    {
    	for (LONG i=0; i<myVectors.GetCount(); i++) // and here...
    	{
    		hf->WriteLVector(myVectors[i]);
    	}
      
    	return TRUE;
    }
      
    // Message buttons to read into the console and write into the BaseArray
    Bool myObject::Message(GeListNode *node, LONG type, void *data)
    {
    	...
    	if (dc->id[0].id == HF_READ)
    	{			
    		print(myVectors); // print the vector array into the console
    	}
      
    	if (dc->id[0].id == HF_WRITE)
    	{				
    		myVectors.Resize(5);  			// here I am changing the size of the array
    		for (LONG i=0; i<5; i++) myVectors[i] = Vector(i);
    	}
    }
      
      
    
    

    Is the proper way of caching a BaseArray into the scene file?
    How can I solve the variable size error that I am getting?

    Thanks!



  • On 05/12/2016 at 09:28, xxxxxxxx wrote:

    Upon saving the file your Write() function only stores 5 vector values. But in your Read() function (when c4d loads the stored file) you want to read in 10 vector values. So when it tries to read the 6th vector value (which is not available in the hyperfile as you only have stored 5 values previously) ReadLVector() will return false. C4D notices this and stops the reading of the file as obviously something is wrong. Then the dialog message as you describe it will appear.

    You can fix this easily by first writing the amount of vector values you are writing in Write(). And then in Read() use it to dynamically resize your container before writing.

    Something like:

      
    Bool myObject::Write(..)  
    {  
       if(!hf->WriteInt32(myVectors.GetCount())) return false; //Write the array size  
       //... rest as before  
    }  
      
    Bool myObject::Read(...)  
    {  
       Int32 stored_cnt = 0; if(!hf->ReadInt32(&stored_cnt)) return false;  
       myVectors.resize(stored_cnt); //Now resize to the actual stored amount of vector values  
      
       for(Int32 i = 0; i < stored_cnt; ++i) //only iterate up to stored count. Or rather use array iterators  
       //...rest as before  
    }  
    
    


  • On 05/12/2016 at 10:27, xxxxxxxx wrote:

    Thank you Samir, it works.

    Since I never used Hyperfiles before, can you please clarify how hf->WriteInt32(myVectors.GetCount()) and  hf->ReadInt32(&stored_cnt) are referring to the same thing? I am finding it confusing since we did not specify a class member variable for that. What if I had 2 Int32 values that I needed to write? Sorry if this seems like a stupid question.



  • On 05/12/2016 at 11:24, xxxxxxxx wrote:

    The Write() function of your object is called whenever the c4d scene file is saved by the user.
    And Read() is called whenever the scene file is loaded into c4d.

    Hyperfiles use FIFO (first in first out) style storage. This means, the first value (no matter the type) you write to the hyperfile in your Write() function, is also the first value you need to read in your Read() function.

    So you must read your data in the same order that you have written them into the hyperfile.

    And hf->WriteInt32(myVectors.GetCount()) is the first data value we write into the hyperfile.
    So hf->ReadInt32(&stored_cnt) is the first data value we need to read from the hyperfile.

    That way we know the basearray element count when the file was saved and we can resize it accordingly.

    And I am not sure I understand. We did not specify a class member variable for what?



  • On 05/12/2016 at 11:26, xxxxxxxx wrote:

    If you wanted to write 2 Int values, just follow the FIFO style.

    Write()  
    {  
      hf->WriteInt32(an_integer_value);  
      hf->WriteInt32(another_integer_value);  
      hf->WriteFloat32(a_float_value);  
    }  
      
    Read()  
    {  
      Int32 a,b,c;  
      hf->ReadInt32(&a);  
      hf->ReadInt32(&b);  
      hf->ReadInt32(&c); //<-- Will fail! It expects us to read in a Float32 value (see Write() above)  
    }
    


  • On 05/12/2016 at 11:53, xxxxxxxx wrote:

    Makes perfect sense now. Thanks again!


Log in to reply