Creating Custom Callback?

On 15/04/2018 at 15:45, xxxxxxxx wrote:

For all my experience in Cinema 4D as an artist I am much more familiar with scripting in Nuke and Maya where custom callbacks are relatively straightforward to create.

Is it possible to create custom callbacks to trigger on specific events?

I'm specifically interested in modifying Redshift material presets to use the proper colors whether the current document is using an sRGB or Linear input profile.  So far I know that I can use


to query the current input profile. And I can use


to convert from Linear to sRGB or vice versa, but how can I attach my custom function to execute when the Redshift material preset dropdown


is modified?

On 16/04/2018 at 03:59, xxxxxxxx wrote:

Good morning Darby and thanks for writing us.

With regard to your request on implementing a custom callback triggered on certain events, I invite you to implement a MessageData plugin and implement a CoreMessage method in order to catch the event of your interest.
I also invite you to give a look at the Core Message Manual which can provide some further explanation about the mechanism behind the message dispatching and handling in Cinema 4D.

Best, Riccardo

On 16/04/2018 at 23:50, xxxxxxxx wrote:

Thank you Riccardo for writing back.

I've looked into writing a MessageData plugin but I'm running into some issues.

I think I'm able to detect when an attribute is modified, but it seems a bit off as I can't find the right c4d.EVMSG or c4d.MSG constant to use.  Instead I found that the message id 1026901 is sent when most attributes are modified.

As far as I can tell the base container that comes along with the message may contain up to two additional parameters (c4d.BFM_CORE_PAR1 and c4d.BFM_CORE_PAR2) but these are PyCObjects and I don't know how to use them.

I can't think of any way to find out which attribute on which material is sending me these messages. Any additional help would be much appreciated!

On 17/04/2018 at 05:24, xxxxxxxx wrote:

Hi darby, thanks for following up.

Actually after you catch a value change event it's pretty straightforward to see if linear workflow or color space has changed with something like

class SDKSupport_14183(plugins.MessageData) :
last_cp = 0
last_lw = 1
mat_last_cp = 0
def CoreMessage(self, id, bc) :
# attempt to retrieve the active document
doc = c4d.documents.GetActiveDocument()
if doc is None:
return True
mat = doc.GetActiveMaterial()
if mat is None:
return True
if id == c4d.EVMSG_CHANGE:
matBC = mat.GetDataInstance()
if matTxt.GetType() == c4d.Xbitmap:
matTxtBC = matTxt.GetDataInstance()
if mat_cp != self.mat_last_cp:
print "Color profile setting changed [",mat_cp, "] in ", mat.GetName()
#update the stored value
self.mat_last_cp = mat_cp
# attempt to retrieve doc settings instance
docSettings = doc.GetSettingsInstance(c4d.DOCUMENTSETTINGS_DOCUMENT)
if docSettings is None:
return True
# retrieve the color profile and linear workflow values
cp = docSettings[c4d.DOCUMENT_COLORPROFILE]
# check against the last stored value
if cp != self.last_cp:
print "Color profile setting changed [", cp, "]"
#update the stored value
self.last_cp = cp
# check against the last stored value
if lw != self.last_lw:
print "Linear workflow setting changed [", lw, "]"
#update the stored value
self.last_lw = lw 
return True

Hope it helps.

On 18/04/2018 at 22:06, xxxxxxxx wrote:

Thanks again Riccardo!

This has helped me quite a bit but I'm still running into some issues.

I have a MessageData plugin responding to EVMSG_CHANGE, and I've used the script editor to prototype the action I need to occur on the Redshift material:

import c4d
from c4d import documents, utils
def main() :
    doc = documents.GetActiveDocument() 
    mat = doc.GetActiveMaterial()
    if mat:
        node = mat[c4d.REDSHIFT_GRAPH_NODES]
        while node:
            if node[c4d.GV_REDSHIFT_SHADER_META_CLASSNAME] == 'Material':
                mat_bc = node.GetOperatorContainer()
                desc = node.GetDescription(c4d.DESCFLAGS_DESC_0)
                for bc, paramid, groupid in desc:
                    if paramid[0].dtype == c4d.DTYPE_COLOR and paramid[0].creator == 0:
                        color = mat_bc[paramid[0].id]
                        mat_bc[paramid[0].id] = utils.TransformColor(color, c4d.COLORSPACETRANSFORMATION_LINEAR_TO_SRGB)
            node = node.GetNext()
if __name__=='__main__':

However, I can't figure out an elegant way to make sure that I only perform the above action to the proper Redshift material graph when a new material preset is selected for that material. Initially the problem was that whenever the EVMSG_CHANGE message was being received it would update the colors on the active material, which obviously happens way too frequently. I changed my MessageData plugin to keep track of the previous material preset but that goes out of sync if you switch from material to material.

It seems that I need a way to determine whether the EVMSG_CHANGE was triggered by a specific attribute being modified.  Is that possible?  I have to admit that I'm still struggling to understand the details of Descriptions, DescIDs and DescLevels but I'm glad to finally be tackling this stuff :)

On 19/04/2018 at 03:00, xxxxxxxx wrote:


just to drop a short note: you find information on many topics in the C++ SDK documentation. For example:

best wishes,

On 28/04/2018 at 16:05, xxxxxxxx wrote:

Thanks for the help.

I can't find a way around this one.

Unless it's possible to find out what sort of message is being sent by the Redshift plugin's Material Preset dropdown menu so that I can act on it as well I think I'm out of luck.  Oh well, on to the next one.

On 02/05/2018 at 02:44, xxxxxxxx wrote:

Good morning, thanks for following up.

With regard to your last point, being something out of our purview, I suggest to get in touch with Redshift development and ask them to implement something useful to your purposes.

Best, Riccardo