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
[URL-REMOVED] 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()
[URL-REMOVED],Write()
[URL-REMOVED] andCopyTo()
[URL-REMOVED], 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
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
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