DescribeIO Manual
A custom data type or an implementation of an interface will contain some internal data. A static custom
DescribeIO()
function describes how this data is written to or from a file.
A
DescribeIO()
function handles the given
maxon::DataSerializeInterface
argument. This object should not be handled directly; only with these macros:
Describe()
calls are made.
Certain elements may only be handled if a certain condition is fulfilled:
DescribeEndIf()
.
This snippet shows a simple custom data type:
// This example shows a simple custom data type.// DescribeIO() describes how the data type is stored in a file static maxon::Result<void> DescribeIO ( const maxon::DataSerializeInterface & stream);
This is the straightforward implementation of
DescribeIO()
.
// each member variable is stored in the file Describe ( "_a" , _a, maxon::Int , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; Describe ( "_b" , _b, maxon::Int , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; Describe ( "_c" , _c, maxon::Int , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; return maxon::OK ; }
DescribeIO()
is invoked when an instance of the data type is written to or read from a file:
// define data SimpleTriplet triplet; triplet._a = 100; triplet._b = 200; triplet._c = 300;
// file URL const maxon::Url url = (targetFolder + "triplet.txt" _s) iferr_return ; const maxon::Id fileID { "net.maxonexample.simpletriplet" };
// save to file maxon::WriteDocument (url, maxon::OPENSTREAMFLAGS::NONE , fileID, triplet, maxon::IOFORMAT::JSON ) iferr_return ;
// read from file SimpleTriplet loadedTriplet; maxon::ReadDocument (url, fileID, loadedTriplet) iferr_return ;
// display loaded data DiagnosticOutput ( "Loaded Triplet: @, @, @" , loadedTriplet._a, loadedTriplet._b, loadedTriplet._c);
The write-process will result in a file like this:
{ "identification" : "net.example.simpletriplet" , "content" : { "_a" : 100, "_b" : 200, "_c" : 300 } }A helper class is used to define code that is executed when Cinema 4D handles the data. The helper class is used with these macros:
WriteAction()
and
ReadAction()
.
// helper class class TripletHelperClass { public : // WriteAction() is called when data is written to a file, as defined with PrepareHelper() maxon::Result<void> WriteAction( maxon::DataSerializeInterface * ds, const HelperTriplet& triplet, maxon::UInt elementHash) { // construct on initialization if (elementHash == maxon::INITIALIZEHASH ) { // all the data should be stored as a single string // the triplet values are merged into this single string _combined = maxon::String::IntToString(triplet._a); _combined += "::" _s; _combined += maxon::String::IntToString(triplet._b); _combined += "::" _s; _combined += maxon::String::IntToString(triplet._c); } return maxon::OK ; }
// ReadAction() is called when data is read from a file, as defined with PrepareHelper() maxon::Result<void> ReadAction( maxon::DataSerializeInterface * ds, HelperTriplet& triplet, maxon::UInt elementHash) { iferr_scope ;
// deconstruct on finalization if (elementHash == maxon::FINALIZEHASH ) { // all data is stored in a single string
// split string maxon::BaseArray<maxon::String> parts; _combined.Split( "::" _s, true , parts) iferr_return ;
// check element count const maxon::Int count = parts. GetCount (); DebugAssert (count == 3);
// store values in the original data type triplet._a = parts[0].ToInt() iferr_return ; triplet._b = parts[1].ToInt() iferr_return ; triplet._c = parts[2].ToInt() iferr_return ; } return maxon::OK ; } maxon::String _combined; // string containing all data }; maxon::Result<void> HelperTriplet::DescribeIO ( const maxon::DataSerializeInterface & stream) { iferr_scope ; PrepareDescribe (stream, HelperTriplet); // prepare helper class // the helper functions should be invoked on initialization / finalization PrepareHelper (TripletHelperClass, maxon::PREPAREHELPERFLAGS::INITIALIZE_WRITE | maxon::PREPAREHELPERFLAGS::FINALIZE_READ ); // the helper's "_combined" member will be stored in the file DescribeHelper ( "data" , _combined, maxon::String , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; return maxon::OK ; }
This will result in a file like this:
{ "identification" : "net.example.helpertriplet" , "content" : { "data" : "100::200::300" } }This more complex example uses DescribeHelperIf() :
// This example shows a helper class and how it is used in an implementation of DescribeIO(). // The helper class analyses the values stored in the given object. If all triplet values are the same, // only one number is stored in a file. If the values are not the same, all values are stored.// helper class class CompactTripletHelperClass { // hashes for relevant helper members // used to identify values handled in WriteAction() / ReadAction() CONSTHASH (_compact); // hash for _compact CONSTHASH (_compactValue); // hash for _compactValue CONSTHASH (_z); // hash for _z public : // WriteAction() is called as defined with DescribeHelperIf() maxon::Result<void> WriteAction( maxon::DataSerializeInterface * ds, const CompactTriplet& triplet, maxon::UInt elementHash) { // writing the " _compact" value if (elementHash == _compactHash) { // if all three values are the same, store only one value in "compact" mode const maxon::Bool aEqualsB = triplet._a == triplet._b; const maxon::Bool bEqualsC = triplet._b == triplet._c; if (aEqualsB && bEqualsC) { _compact = true ; _compactValue = triplet._a; } else { // store each individual value _compact = false ; _x = triplet._a; _y = triplet._b; _z = triplet._c; } } return maxon::OK ; }
// ReadAction() is called as defined with DescribeHelper() maxon::Result<void> ReadAction( maxon::DataSerializeInterface * ds, CompactTriplet& triplet, maxon::UInt elementHash) { switch (elementHash) { // load compact value; DESCRIBEFLAGS::ACTION_AFTER_READ was set case (_compactValueHash): { triplet._a = _compactValue; triplet._b = _compactValue; triplet._c = _compactValue; break ; } // last individual value has been loaded; DESCRIBEFLAGS::ACTION_AFTER_READ was set case (_zHash): { // load all values after the third value has been read triplet._a = _x; triplet._b = _y; triplet._c = _z; break ; } default : { break ; } } return maxon::OK ; }
// helper class member data // the member name must be the same as the name used with DescribeHelper() maxon::Bool _compact; // compact mode maxon::Int _compactValue; // compact value maxon::Int _x; // x value maxon::Int _y; // y value maxon::Int _z; // z value }; maxon::Result<void> CompactTriplet::DescribeIO ( const maxon::DataSerializeInterface & stream) { iferr_scope ; PrepareDescribe (stream, CompactTriplet); // prepare helper PrepareHelper (CompactTripletHelperClass, maxon::PREPAREHELPERFLAGS::NONE );
// check if compact mode or not when writing to file DescribeHelperIf ( "_compact" , _compact, maxon::Bool , maxon::DESCRIBEFLAGS::ACTION_BEFORE_WRITE , true , true ) iferr_return ; { // store compact value; handle values after reading DescribeHelper ( "_compactValue" , _compactValue, maxon::Int , maxon::DESCRIBEFLAGS::ACTION_AFTER_READ ) iferr_return ; } DescribeElse () iferr_return ; { // simply write/read all values into the helper class DescribeHelper ( "_x" , _x, maxon::Int , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; DescribeHelper ( "_y" , _y, maxon::Int , maxon::DESCRIBEFLAGS::NONE ) iferr_return ; // after all values have been loaded, copy to data type DescribeHelper ( "_z" , _z, maxon::Int , maxon::DESCRIBEFLAGS::ACTION_AFTER_READ ) iferr_return ; } DescribeEndIf () iferr_return ; return maxon :: OK ; }
A "compact" file using the same value for each channel will look like this:
{ "identification" : "net.example.compacttriplet" , "content" : { "_compact" : true , "_compactValue" : 100 } }A non-compact file will look like this:
{ "identification" : "net.example.compacttriplet" , "content" : { "_compact" : false , "_x" : 10, "_y" : 100, "_z" : 1000 } }