Solved Unable to insert a key frame for the color attribute of the plugin.

Hello, I'm here for help.

  1. I want to insert some keyframes for a color property of the plug-in, and the sub-level light object will change accordingly.The problem now is that I can't insert a keyframe for this color property (the keyframe icon always appears yellow).
  2. In addition, I have another question: where can I listen for the click event of the key frame icon?

These two problems have been bothering me for two or three days now, either pyhton or C++ code, Any ideas would be much appreciated!

Thanks,
Sean

import c4d
import os

class res(object):
    AAAAAA_COLOR = 1000

res = res()

def load_bitmap(path):
    path = os.path.join(os.path.dirname(__file__), path)
    bmp = c4d.bitmaps.BaseBitmap()
    if bmp.InitWith(path)[0] != c4d.IMAGERESULT_OK:
        bmp = None
    return bmp


class aaaaaaData(c4d.plugins.ObjectData):

    PLUGIN_ID = 123566
    PLUGIN_NAME = 'aaaaaa'
    PLUGIN_INFO = 0
    PLUGIN_DESC = 'Oaaaaaa'
    PLUGIN_ICON = load_bitmap('res/icons/aaaaaa.tiff')
    PLUGIN_DISKLEVEL = 0

    def __init__(self):
        self.value = c4d.Vector(1, 0, 0)

    @classmethod
    def Register(cls):
        return c4d.plugins.RegisterObjectPlugin(
            cls.PLUGIN_ID, cls.PLUGIN_NAME, cls, cls.PLUGIN_DESC, cls.PLUGIN_INFO,
            cls.PLUGIN_ICON, cls.PLUGIN_DISKLEVEL)

    def Init(self, node):
        #self.InitAttr(node, c4d.Vector(1,0,0), [res.AAAAAA_COLOR])
        node[res.AAAAAA_COLOR] = c4d.Vector(1, 0, 0)

        return True

    def CreateKey(self, obj, id, value):
        track = obj.FindCTrack(id)
        if not track:
            track = c4d.CTrack(obj, id)
            obj.InsertTrackSorted(track)
            c4d.EventAdd()

        curve = track.GetCurve()
        key = curve.AddKey(obj.GetDocument().GetTime())
        if not key:
            return False

        if type(value) == int or type(value) == float:
            key["key"].SetValue(curve, value)
        else:
            key["key"].SetGeData(curve, value)

        return True

    def setColor(self, node, data):
        plugin_color = c4d.DescLevel(res.AAAAAA_COLOR, c4d.DTYPE_COLOR, 0)
        plugin_color_r = c4d.DescLevel(c4d.COLOR_R, c4d.DTYPE_REAL, 0)
        plugin_color_g = c4d.DescLevel(c4d.COLOR_G, c4d.DTYPE_REAL, 0)
        plugin_color_b = c4d.DescLevel(c4d.COLOR_B, c4d.DTYPE_REAL, 0)
        self.CreateKey(node, c4d.DescID(plugin_color, plugin_color_r), data.x)
        self.CreateKey(node, c4d.DescID(plugin_color, plugin_color_g), data.y)
        self.CreateKey(node, c4d.DescID(plugin_color, plugin_color_b), data.z)

        light = node.GetDown()
        if light:
            light[c4d.LIGHT_COLOR] = data
            light_color = c4d.DescLevel(c4d.LIGHT_COLOR, c4d.DTYPE_COLOR, 0)
            light_color_r = c4d.DescLevel(c4d.COLOR_R, c4d.DTYPE_REAL, 0)
            light_color_g = c4d.DescLevel(c4d.COLOR_G, c4d.DTYPE_REAL, 0)
            light_color_b = c4d.DescLevel(c4d.COLOR_B, c4d.DTYPE_REAL, 0)
            self.CreateKey(light, c4d.DescID(
                light_color, light_color_r), data.x)
            self.CreateKey(light, c4d.DescID(
                light_color, light_color_g), data.y)
            self.CreateKey(light, c4d.DescID(
                light_color, light_color_b), data.z)

    def SetDParameter(self, node, id, data, flags):
        paramID = id[0].id
        if paramID == res.AAAAAA_COLOR:
            self.setColor(node, data)
            self.value = data
            return True, flags | c4d.DESCFLAGS_SET_PARAM_SET

    def GetDParameter(self, node, id, flags):
        paramID = id[0].id
        if paramID == res.AAAAAA_COLOR:
            data = self.value
            return True, data, flags | c4d.DESCFLAGS_GET_PARAM_GET

        return True


if __name__ == '__main__':
    aaaaaaData.Register()

未命名图片.png

Please, either pyhton or C++ code, Any ideas would be much appreciated!

Hello,

about the keyframe you have to use TranslateDescID we have an example in our github repository

The keyFrame will be create on the target parameter and not yours.

For your second question, I have to double check.

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

Hello,

For Vectors, in c++ you have to use the macro HandleDescGetVector and HandleDescSetVector

They are simple switch to handle individual component (x, y, z)

// Macro that handles GetParameter() calls for Vector. (For an example of usage see @em datatype.cpp SDK example.)
#define HandleDescGetVector(tid, vector, t_data, flags) \
	switch (tid[1].id) \
	{ \
		case 0:			t_data = GeData(vector);   flags |= DESCFLAGS_GET::PARAM_GET; break; \
		case 1000:	t_data = GeData(vector.x); flags |= DESCFLAGS_GET::PARAM_GET; break; \
		case 1001:	t_data = GeData(vector.y); flags |= DESCFLAGS_GET::PARAM_GET; break; \
		case 1002:	t_data = GeData(vector.z); flags |= DESCFLAGS_GET::PARAM_GET; break; \
	} \

/// Macro that handles SetParameter() calls for Vector. (For an example of usage see @em datatype.cpp SDK example.)
#define HandleDescSetVector(v, tid, vector, t_data, flags) \
	switch (tid[1].id) \
	{ \
		case 0:			v = t_data.GetVector(); flags |= DESCFLAGS_SET::PARAM_SET; break; \
		case 1000:	v = Vector(t_data.GetFloat(), vector.y, vector.z); flags |= DESCFLAGS_SET::PARAM_SET; break; \
		case 1001:	v = Vector(vector.x, t_data.GetFloat(), vector.z); flags |= DESCFLAGS_SET::PARAM_SET; break; \
		case 1002:	v = Vector(vector.x, vector.y, t_data.GetFloat()); flags |= DESCFLAGS_SET::PARAM_SET; break; \
	} \

It doesn't exist in python you have to come with your own solution, something like this :
Note that i've added an extra case where the id depth is only one level. Seems that in python it doesn't sent a two level DescID with the second level ID set to 0.

 def HandleDescGetVector(self, tid, value, flags):
        data = None
        result = False
        if tid.GetDepth() != 2:
            data = value
            flags |=  c4d.DESCFLAGS_GET_PARAM_GET
            result = True
            return result, data, flags
        
        if tid[1].id == 0:
            data = value
            flags |=  c4d.DESCFLAGS_GET_PARAM_GET
            result = True
        elif tid[1].id == 1000:
            data = value.x
            flags |=  c4d.DESCFLAGS_GET_PARAM_GET
            result = True
        elif tid[1].id == 1001:
            data = value.y
            flags |=  c4d.DESCFLAGS_GET_PARAM_GET
            result = True
        elif tid[1].id == 1002:
            data = value.z
            flags |=  c4d.DESCFLAGS_GET_PARAM_GET
            result = True
        return result, data, flags

  
    def SetDParameter(self, node, id, data, flags):
        paramID = id[0].id
        if paramID == res.AAAAAA_COLOR:
            if id.GetDepth() == 1:
                self.value = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
            elif id[1].id == 1000:
                self.value.x = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
          
            elif id[1].id == 1001:
                self.value.y = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
            
            elif id[1].id == 1002:
                self.value.z = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
            
            return True, flags

        elif paramID == res.myReal:
            self.myReal = data
        elif paramID == res.myVector:
            
            if id.GetDepth() == 1:
                self.myVector = data
                flags |= c4d.DESCFLAGS_SET_PARAM_SET
                
            elif id[1].id == 1000:
                self.myVector.x = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
                
            elif id[1].id == 1001:
                self.myVector.y = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET
                
            elif id[1].id == 1002:
                self.myVector.z = data
                flags |=  c4d.DESCFLAGS_SET_PARAM_SET

            return True, flags

        return True

    def GetDParameter(self, node, id, flags):
        paramID = id[0].id
        

        if id[0].id == res.AAAAAA_COLOR:
            return  self.HandleDescGetVector(id, self.value, flags)
        elif paramID == res.myReal:
            return True, self.myReal, flags | c4d.DESCFLAGS_GET_PARAM_GET
        elif paramID == res.myVector:
            return  self.HandleDescGetVector(id, self.myVector, flags)
            

        return True

About detecting the click on the icon, there's no solution for that.
just to be sure, you are talking about the circle in front of the parameter, not the "record active object" command ? (shortcut f9)

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes Hello, thank you for providing the method, I have already done it. The problem now is that the color properties of the plug-in do route to the color properties of the sub-lights, and the lights have keyframe markers on the timeline, but nothing on the plug-in's timeline.

    def TranslateDescID(self, node, id):

        paramID = id[0].id

        if paramID == res.AAAAAA_COLOR:
            light = node.GetDown()
            if light:
                desc = light.GetDescription(c4d.DESCFLAGS_DESC_0)
                if not desc:
                    return False

                descid = c4d.DescID(c4d.DescLevel(c4d.LIGHT_COLOR))
                completeid = desc.CheckDescID(descid, None)

                return (True, completeid, light)

        return False

微信图片_20191205225400.png 微信图片_20191205225410.png

hello,

this is also the case when you have for example a cube with a phong tag.
If you select the cube, the phong tag tab is visible in the attribute manager and you can add keyframe but they only appear on the time line if you select the phong tag itself.

Those keyframe appear if the selected object have tracks and keyframe witch is not the case of your NodeData. The track is created on the light itself.

You have to create the keyframe on both but that will double the keyframes for nothing.

Cheers,
Manuel.

MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes Hello, your statement is consistent with my imagination, but when you click the little circle in front of the color attribute of the plug-in, how about creating keyframes for both?Can you provide simple code?Ingredient gratitude!

Cheers,
Sean

You can simply pick the code you write to create the key for both parameters. That part was right.
The only issue you had was the way you have to get and set parameters for vector for x, y and z.

But in that case, (two tracks) you will have to make decisions, what happen if i create a keyframe in the light myself ? Will it be erased by your NodeData ?

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes
Hello, thank you very much for your inspiration. You've been very helpful.

There is no need to overwrite TranslateDescID(), only two macros HandleDescGetVector and HandleDescSetVector can realize my idea. Thanks again!

Cheers,
Sean