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



  • 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



  • @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.



  • @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



  • @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