I'm trying to create a plugin which behaves similiar to the Character module. I'll break it down to this:
- The plugin should be an object (using
ObjectData
). - The plugin has settings for the user to modify.
- Depending on the settings the object will generate different objects.
- One of the settings (let's call it
Mode
) should toggle whether the user can see the generated objects as children of the plugin object (to interact with them) in the object manager or not. However the objects will always be visible in the viewport.
So my idea was this:
- In
GetVirtualObjects
I generate the desired objects based on the object settings. All desired objects will always be returned by this method. - To add the objects as children to the plugin object in the document I have to use the main thread. For this I call
ExecuteOnMainThread
from insideGetVirtualObjects
.
As I gathered from this thread with that lovely fella I am indeed allowed to create object hierarchies inside GetVirtualObjects
, but I must not insert these generated objects in the document from inside this method (since it's not running on the main thread). So my idea for the code is this:
BaseObject* MyPlugin::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
{
Bool dirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS::DATA);
if (!dirty)
return op->GetCache(hh);
BaseObject* generatedObjects = generateObjects(op);
// Use a BaseLink to pass the current object to the method on the main thread as suggested in https://plugincafe.maxon.net/topic/13068/calling-executeonmainthread-from-objectdata-getvirtualobjects
BaseContainer* bc = op->GetDataInstance();
BaseLink* link = bc->GetBaseLink(ID_PRV_BASE_LINK);
if (link == nullptr)
{
link = BaseLink::Alloc();
link->SetLink(op);
bc->SetParameter(ID_PRV_BASE_LINK, link);
}
BaseDocument* doc = op->GetDocument();
maxon::ExecuteOnMainThread([this, doc, link, generatedObjects]()
{
addGeneratedObjectsToDocument(doc, link, generatedObjects);
});
return generatedObjects;
}
void MyPlugin::addGeneratedObjectsToDocument(BaseDocument* doc, BaseLink* link, BaseObject* generatedObjects)
{
BaseObject* op = static_cast<BaseObject*>(link->GetLink(doc));
clearChildren(op);
switch(getMode(link))
{
case Mode::ShowObjects:
generatedObjects->InsertUnderLast(op);
break;
default:
// Do nothing.
break;
}
}
So my questions before committing to writing the rest of the code is this:
- Is this the right approach for my goal? Should I call
ExecuteOnMainThread
from withinGetVirtualObjects
or am I on the wrong track? - Is this the intended way to develop a plugin like this? Generators in the traditional sence take an input (which usually is whatever the user places as children of the generator) but in this case (just like with the Character module) the generator children will solely be managed by the object itself.
The code does work, I'd just like to make sure that I'm not messing something up by passing references the wrong way or by abusing the pipeline or anything like that.
Thanks for all you do guys!