On 05/12/2013 at 17:58, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R15
Platform: Windows ;
Language(s) : C++ ;
---------
Hi,
I have a problem with an object generator plugin and the cache handling (the "dirty" stuff).
The plugin should be able to use child objects but without a child it should use a default object.
Now the problem is, with the internal default object everything works as expected but adding an object as a child or removing it from the generator object (in the object manager inside C4D!) won't be recognized as a change and doesn't set "dirty" to TRUE (and I checked all available DIRTYFLAGS even those who have nothing to do with it at all).
First there have to be another change that the child object replaces the default object.
Like to alter an attribute of the generator object or deactivating/activating it.
And it's the same the other way around when the child object will be removed or deleted.
Without these lines, the child object changes are recognized immediately of course:
Bool dirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS_DATA);
if (!dirty) return op->GetCache(hh);
But at the cost of a lot of unnecessary rebuilts of the generator of course too.
Or do I somehow have to utilize that DependenceList stuff to make it work?
(I thought and hope that wouldn't be necessary as long as there are just base objects for my default object involved and I didn't create one from scratch.)
Here is a very basic stripped down plugin example to test and demonstrate the behaviour I'm talking about:
//////////////////////////////////////////////////////////////
// CINEMA 4D ObjectGeneratorTest //
//////////////////////////////////////////////////////////////
// objectgeneratortest.cpp //
//////////////////////////////////////////////////////////////
#include "c4d.h"
/////////////////////////////////////////////////////////
// Class functions
/////////////////////////////////////////////////////////
class ObjectGeneratorTest : public ObjectData
{
public:
//ObjectData (Generator)
virtual BaseObject* GetVirtualObjects(BaseObject *op, HierarchyHelp *hh);
static NodeData *Alloc(void) { return gNew ObjectGeneratorTest; }
};
// main routine: build virtual testobject
BaseObject *ObjectGeneratorTest::GetVirtualObjects(BaseObject *op, HierarchyHelp *hh)
{
CallCommand(13957); // Clear Console
GePrint("Cache: " + RealToString(op->CheckCache(hh))); // console output for debugging!
GePrint("DIRTYFLAGS_0: " + RealToString(op->IsDirty(DIRTYFLAGS_0))); // console output for debugging!
GePrint("DIRTYFLAGS_MATRIX: " + RealToString(op->IsDirty(DIRTYFLAGS_MATRIX))); // console output for debugging!
GePrint("DIRTYFLAGS_DATA: " + RealToString(op->IsDirty(DIRTYFLAGS_DATA))); // console output for debugging!
GePrint("DIRTYFLAGS_SELECT: " + RealToString(op->IsDirty(DIRTYFLAGS_SELECT))); // console output for debugging!
GePrint("DIRTYFLAGS_CACHE: " + RealToString(op->IsDirty(DIRTYFLAGS_CACHE))); // console output for debugging!
GePrint("DIRTYFLAGS_CHILDREN: " + RealToString(op->IsDirty(DIRTYFLAGS_CHILDREN))); // console output for debugging!
GePrint("DIRTYFLAGS_DESCRIPTION: " + RealToString(op->IsDirty(DIRTYFLAGS_DESCRIPTION))); // console output for debugging!
GePrint("DIRTYFLAGS_SELECTION_OBJECTS: " + RealToString(op->IsDirty(DIRTYFLAGS_SELECTION_OBJECTS))); // console output for debugging!
GePrint("DIRTYFLAGS_SELECTION_TAGS: " + RealToString(op->IsDirty(DIRTYFLAGS_SELECTION_TAGS))); // console output for debugging!
GePrint("DIRTYFLAGS_SELECTION_MATERIALS: " + RealToString(op->IsDirty(DIRTYFLAGS_SELECTION_MATERIALS))); // console output for debugging!
// check if something has been changed
Bool dirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS_DATA); // if !dirty object is already cached and doesn't need to be rebuilt
GePrint("dirty: " + RealToString(dirty)); // console output for debugging!
if (!dirty) return op->GetCache(hh); // if nothing has changed return cache
// create a null object
BaseObject *parent = BaseObject::Alloc(Onull);
if (!parent) return NULL;
BaseObject *testobject;
if (!op->GetDown())
{
// create a figure as testobject
testobject = BaseObject::Alloc(Ofigure);
}
else
{
// clone child object(s) as testobject
// testobject = (BaseObject* ) op->GetDown()->GetClone(COPYFLAGS_0, NULL); // use the first child object only
testobject = op->GetAndCheckHierarchyClone(hh, op->GetDown(), HIERARCHYCLONEFLAGS_ASIS, &dirty, NULL, TRUE); // use all child objects
}
if (testobject)
{
testobject->InsertUnderLast(parent);
}
return parent;
}
/////////////////////////////////////////////////////////
// Register function
/////////////////////////////////////////////////////////
// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_OBJECTGENERATORTEST 1000001 // Plugin IDs 1000001-1000010 are reserved for development only!
Bool RegisterObjectGeneratorTest(void)
{
return RegisterObjectPlugin(ID_OBJECTGENERATORTEST, "Object Generator Test", OBJECT_GENERATOR|OBJECT_INPUT, ObjectGeneratorTest::Alloc, "", NULL, 0);
}
Edit:
By the way, MSG_DRAGANDDROP is only triggered when something is dropped on the plugin object, not away from it!
Just in case someone would come to the idea to use that in any way.
Kind regards,
Tom