hi,
never say never. Sorry for the delay, this is a "unusual" case ^^
I did try several options (observable, notification, message etc)
I finished using the function AddEventNotification witch is private. (so i had to figure out how it was working)
The shader and the viewport is updated but with a small latency.
We can try to improve that solution if you want or you can go with your own.
Below the code for both the ObjectData and the Shader.
The shader need to register to be notified. (this is automatic, nothing to add on the ObjectData's side)
Than you need to check the message in Message
I feel that the important part is to remove the notification and re/add it. (not sure what it can do if you don't do it ^^)
class pc12019_object : public ObjectData
{
INSTANCEOF(pc12019_object, ObjectData);
public:
static NodeData* Alloc() { return NewObjClear(pc12019_object); }
BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) override
{
return BaseObject::Alloc(Ocube);
}
Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) override
{
if (!description->LoadDescription(Obase))
return false;
const DescID* singleid = description->GetSingleDescID();
const DescID cid = DescLevel(OBJ_COLOR, DTYPE_COLOR, 0);
if (!singleid || cid.IsPartOf(*singleid, nullptr))
{
BaseContainer bc = GetCustomDataTypeDefault(DTYPE_COLOR);
bc.SetString(DESC_NAME, "Color"_s);
bc.SetData(DESC_GUIOPEN, true);
description->SetParameter(cid, bc, DescLevel(ID_OBJECTPROPERTIES));
}
flags |= DESCFLAGS_DESC::LOADED;
return SUPER::GetDDescription(node, description, flags);
}
};
class pc12019_shader : public ShaderData
{
INSTANCEOF(pc12019_shader, ShaderData);
public:
static NodeData* Alloc() { return NewObjClear(pc12019_shader); }
Vector Output(BaseShader* sh, ChannelData* cd) override
{
return color;
}
Bool Read(GeListNode* node, HyperFile* hf, Int32 level) override
{
// need to read the color
return true;
}
Bool Write(GeListNode* node, HyperFile* hf) override
{
// need to write the color
return true;
}
Bool CopyTo(NodeData* dest, GeListNode* snode, GeListNode* dnode, COPYFLAGS flags, AliasTrans* trn) override
{
pc12019_shader* destShader = static_cast<pc12019_shader*>(dest);
destShader->color = color;
return true;
}
Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) override
{
if (!description->LoadDescription(Xbase))
return false;
const DescID* singleid = description->GetSingleDescID();
DescID cid = DescLevel(SH_OBJECTLINK, DTYPE_BASELISTLINK, 0);
if (!singleid || cid.IsPartOf(*singleid, nullptr))
{
BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BASELISTLINK);
bc.SetString(DESC_NAME, "Link"_s);
bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_LINKBOX);
BaseContainer ac;
ac.SetInt32(Obase, 1);
bc.SetContainer(DESC_ACCEPT, ac);
description->SetParameter(cid, bc, DescLevel(ID_SHADERPROPERTIES));
}
flags |= DESCFLAGS_DESC::LOADED;
return SUPER::GetDDescription(node, description, flags);
}
INITRENDERRESULT InitRender(BaseShader* sh, const InitRenderStruct& irs) override
{
iferr_scope_handler
{
err.DiagOutput();
return INITRENDERRESULT::UNKNOWNERROR;
};
if (irs.doc == nullptr)
return INITRENDERRESULT::OK;
BaseContainer* bcShader = sh->GetDataInstance();
if (bcShader == nullptr)
return INITRENDERRESULT::UNKNOWNERROR;
BaseObject * linkedObject = bcShader->GetObjectLink(SH_OBJECTLINK, irs.doc);
if (linkedObject == nullptr)
return INITRENDERRESULT::OK;
RemoveNotification(sh, linkedObject);
AddNotification(sh, linkedObject);
GeData data;
linkedObject->GetParameter(OBJ_COLOR, data, DESCFLAGS_GET::NONE);
color = data.GetVector();
return INITRENDERRESULT::OK;
}
Bool Init(GeListNode* node) override
{
BaseMaterial* mat = static_cast<BaseMaterial*>(node);
BaseContainer* bc = mat->GetDataInstance();
bc->SetLink(SH_OBJECTLINK, nullptr);
return true;
}
void Free(GeListNode* node) override
{
GeData data;
BaseObject* op = static_cast<BaseObject*>(node);
if (op == nullptr)
return;
BaseDocument* doc = node->GetDocument();
if (doc == nullptr)
return;
op->GetParameter(SH_OBJECTLINK, data, DESCFLAGS_GET::NONE);
BaseList2D* linkedObject = data.GetLink(doc);
RemoveNotification(node, linkedObject);
}
Bool RemoveNotification(GeListNode* node, BaseList2D* linkedObject)
{
if ((node == nullptr) || (linkedObject == nullptr))
return false;
BaseObject* op = static_cast<BaseObject*>(node);
if (op == nullptr)
return false;
BaseDocument* doc = op->GetDocument();
if (doc == nullptr)
return false;
if (linkedObject->FindEventNotification(doc, op, NOTIFY_EVENT::CACHE))
{
return linkedObject->RemoveEventNotification(doc, op, NOTIFY_EVENT::CACHE);
}
return true;
}
Bool AddNotification(GeListNode* node, BaseList2D* linkedObject)
{
BaseObject* op = static_cast<BaseObject*>(node);
if (op == nullptr)
return false;
BaseDocument* doc = op->GetDocument();
if (doc == nullptr)
return false;
if (!linkedObject->FindEventNotification(doc, op, NOTIFY_EVENT::MESSAGE))
{
return linkedObject->AddEventNotification(op, NOTIFY_EVENT::MESSAGE, NOTIFY_EVENT_FLAG::NONE, nullptr);
}
return true;
}
Bool Message(GeListNode* node, Int32 type, void* data) override
{
if (type == MSG_NOTIFY_EVENT)
{
NotifyEventData *eventData = static_cast<NotifyEventData*>(data);
// as we can add several notification we check if we received the right one
if (eventData->eventid == NOTIFY_EVENT::MESSAGE)
{
NotifyEventMsg* eventMsg = static_cast<NotifyEventMsg*>(eventData->event_data);
// Checks if the message that the object is fowarding us if the right one. (MSG_DESCRIPTION_POSTSETPARAMETER)
if (eventMsg->msg_id == MSG_DESCRIPTION_POSTSETPARAMETER)
{
DescriptionPostSetValue* dpsv = static_cast<DescriptionPostSetValue*>(eventMsg->msg_data);
const Int32 id = dpsv->descid[0][0].id;
// Checks if the parameter that have been change is part of the message.
if (id == OBJ_COLOR)
{
// ask the shader to update itself.
node->SetDirty(DIRTYFLAGS::ALL);
node->Message(MSG_DESCRIPTION_POSTSETPARAMETER); // this will trigger the mat update and the viewport update. (with a small delay)
}
}
}
return true;
}
return SUPER::Message(node, type, data);
}
private:
Vector color = Vector(1);
};
Cheers,
Manuel