Saving and Loading an AtomArray?
-
On 31/01/2013 at 04:07, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R10-R14
Platform: Windows ; Mac OSX ;
Language(s) : C++ ;---------
In my latest plugin, the user can drag-and-drop a set of Point Selection or Polygon Selection tags as a way to denote the groups on a polygon object. These are stored in a persistent AtomArray and displayed by name in a SimpleListView in a GeDialog associated with a Tag plugin. When the document is saved, I would like the my plugin tag to retain a reference to these selection tags (with Write/Read). I could go the naive route and simply write the names but it would be better if I could write BaseLinks or something like that. Since Hyperfile has no WriteLink() or similar, what alternative is there? Could I set up a BaseContainer and fill it with the links using SetLink() and then use the links on read to reestablish the elements in the AtomArray.A bit convoluted but your ideas are much appreciated!
Thanks,
-
On 31/01/2013 at 04:45, xxxxxxxx wrote:
Hi Robert,
Have you considered converting the references to BaseLinks when writing, then reading
BaseLinks from the HyperFile again and converting them back into the AtomArray?Some pseudo code for the reading mechanism (because I don't have the SDK with me) :
Bool MyTagData::Read(GeListNode\* node, HyperFile\* hf) { if (!TagData::Read(node, hf)) return FALSE; LONG count; if (!hf->ReadLong(&count)) return FALSE; if (count < 0) return FALSE; if (this->array) this->array->Flush(); else this->array = AtomArray::Alloc(); BaseDocument\* doc = node->GetDocument(); BaseLink\* link = BaseLink::Alloc(); for (LONG i=0; i < count; i++) { if (!link->Read(hf)) { BaseLink::Free(link); return FALSE; } C4DAtomGoal\* goal = link->GetLink(doc); this->array->Append(goal); } BaseLink::Free(link); return TRUE; }
I'm pretty sure this code won't compile, but I hope it can demonstrate what my approach was.
Best,
Nik -
On 31/01/2013 at 05:45, xxxxxxxx wrote:
That's why I was asking.
I could allocate an array of BaseLinks with atomarray->GetCount() elements and SetLink() each. Will have to see how robust this is.
Thanks!
-
On 31/01/2013 at 05:47, xxxxxxxx wrote:
Hi Robert,
You can indirectly save BaseLinks in a HyperFile with HyperFile::WriteGeData().
-
On 31/01/2013 at 10:07, xxxxxxxx wrote:
So far, no go. I am not getting the BaseLinks read back in. Here is the code:
// NodeData.Read - Read data from HyperFile //*---------------------------------------------------------------------------* Bool SymMorphyTag::Read(GeListNode* node, HyperFile* hf, LONG level) //*---------------------------------------------------------------------------* { if (!node) return FALSE; if (!hf) return FALSE; BaseContainer* bc = ((BaseTag* )node)->GetDataInstance(); if (!bc) return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), "SymMorphyTag.Read.bc"); if (bodypartArray) { LONG vcnt = bc->GetLong(TSYMMORPHY_BODYPARTCOUNT); if (vcnt) { BaseDocument* doc = hf->GetDocument(); if (!doc) return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), "SymMorphyTag.Read.doc"); BaseLink* bpBL = BaseLink::Alloc(); if (!bpBL) { bc->SetLong(TSYMMORPHY_BODYPARTCOUNT, 0L); return MessageSystem::Throw(GeLoadString(KDZERR_MEMORY), "SymMorphyTag.Read.bpBL"); } BaseList2D* bl2d = NULL; for (LONG i = 0L; i != vcnt; ++i) { if (!bpBL->Read(hf)) { BaseLink::Free(bpBL); return MessageSystem::Throw(GeLoadString(KDZERR_FILE), "SymMorphyTag.Read.bpBL"); } bl2d = bpBL->GetLink(doc); if (bl2d) { // NOT GETTING ANY GEPRINTS!!!! GePrint(bl2d->GetName()); if (!bodypartArray->Append(bpBL->GetLink(doc))) { BaseLink::Free(bpBL); return MessageSystem::Throw(GeLoadString(KDZERR_FILE), "SymMorphyTag.Read.bodypartArray.Append"); } } } BaseLink::Free(bpBL); } else MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), "SymMorphyTag.Read.bodypartArray.Count"); } return TRUE; } // NodeData.Write - Write data to HyperFile //*---------------------------------------------------------------------------* Bool SymMorphyTag::Write(GeListNode* node, HyperFile* hf) //*---------------------------------------------------------------------------* { if (!node) return FALSE; if (!hf) return FALSE; BaseContainer* bc = ((BaseTag* )node)->GetDataInstance(); if (!bc) return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), "SymMorphyTag.Write.bc"); if (bodypartArray) { LONG vcnt = bodypartArray->GetCount(); if (vcnt) { BaseLink* bpBL = BaseLink::Alloc(); if (!bpBL) return MessageSystem::Throw(GeLoadString(KDZERR_MEMORY), "SymMorphyTag.Write.bpBL"); for (LONG i = 0L; i != vcnt; ++i) { bpBL->SetLink((C4DAtomGoal* )bodypartArray->GetIndex(i)); if (!bpBL->Write(hf)) { BaseLink::Free(bpBL); return MessageSystem::Throw(GeLoadString(KDZERR_FILE), "SymMorphyTag.Write.bpBL"); } } BaseLink::Free(bpBL); bc->SetLong(TSYMMORPHY_BODYPARTCOUNT, vcnt); } } return TRUE; }
-
On 31/01/2013 at 11:12, xxxxxxxx wrote:
Hello Robert,
I think at the point the object is read, the tags have not been read yet, although the links would
be valid. You can read them, but you have to evaluate them at a later time, for example at the
first message sent to your object after reading was done./** * Copyright (C) 2013, Niklas Rosenstein * You are allowed to use and/or modify this code for private or * commercial use. **/ #include <c4d.h> #include <ge_dynamicarray.h> class TestObject : public ObjectData { public: LONG count; BaseLink** array; static NodeData* Alloc() { return gNew TestObject; } TestObject() : ObjectData(), array(NULL) { } ~TestObject() { if (array) { for (LONG i=0; i < count; i++) { BaseLink::Free(array[i]); } GeFree(array); array = NULL; } } // Overrides: ObjectData Bool Message(GeListNode* node, LONG type, void* pData) { if (!ObjectData::Message(node, type, pData)) return FALSE; if (array) { BaseDocument* doc = node->GetDocument(); GeDebugOut("%d BaseLinks were read in!", count, type); for (LONG i=0; i < count; i++) { BaseLink* link = array[i]; BaseTag* tag = (BaseTag* ) link->GetLink(doc); BaseLink::Free(link); if (tag) { // Requires a DEBUG build! GeDebugOut(" - " + tag->GetName()); } else { GeDebugOut(" - <NULL>"); } } GeFree(array); array = NULL; } return TRUE; } Bool Read(GeListNode* node, HyperFile* hf, LONG level) { if (!ObjectData::Read(node, hf, level)) return FALSE; if (!hf->ReadLong(&count)) return FALSE; if (array) { GeFree(array); } array = (BaseLink** ) GeAlloc(sizeof(BaseLink** ) * count); if (!array) return FALSE; for (LONG i=0; i < count; i++) { BaseLink* link = BaseLink::Alloc(); if (!link) return FALSE; if (!link->Read(hf)) { BaseLink::Free(link); return FALSE; } array[i] = link; } return TRUE; } Bool Write(GeListNode* node, HyperFile* hf) { if (!ObjectData::Write(node, hf)) return FALSE; AutoAlloc<AtomArray> tags; AutoAlloc<BaseLink> link; if (!tags || !link) return FALSE; // Fill the *tags* array with all tags on the host object. BaseTag* tag = ((BaseObject* )node)->GetFirstTag(); while (tag) { tags->Append(tag); tag = tag->GetNext(); } // Write the number of tags to the file. LONG count = tags->GetCount(); if (!hf->WriteLong(count)) return FALSE; // Write the tag-links to the file. for (LONG i=0; i < count; i++) { tag = (BaseTag* ) tags->GetIndex(i); link->SetLink(tag); link->Write(hf); } return TRUE; } }; Bool PluginStart() { return RegisterObjectPlugin( 1000001, "BaseLink Writer", 0, TestObject::Alloc, "", NULL, 0); } Bool PluginMessage(LONG type, void* pData) { return TRUE; } void PluginEnd() { }
Best,
Niklas
-
On 31/01/2013 at 22:00, xxxxxxxx wrote:
That the tags have not been read into the document yet has come to mind as the possible issue. So, looks like I will need to store the links and then fill in the atomarray with the receipt of MSG_MULTI_DOCUMENTIMPORTED in Message(). Wish me luck!
Update: That did the trick!