Detecting Parameters & Connecting XPresso Ports



  • On 03/12/2015 at 18:33, xxxxxxxx wrote:

    Hi,

    I'm trying to write a script that duplicates an object and connects all animatable parameters of the new object, with the corresponding parameters of the source object via Xpresso. So far, I've been able to achieve the basics (clone object, create XPresso tag & nodes, link parameters) :

    However, I'm still struggling with the following issues/questions:

    1. How do I get Cinema 4D to show that a parameter has been linked as an input/output via XPresso? Something like this:

    2. How do I determine if a parameter in an object's description is animatable? For example: "Size.x" can be keyed but "Size" cannot be.

    Here is my current code, I'd be very interested in any suggestions you may have:

      
    """Name-US: CV-Make Replicant   
    Description-US: Duplicates the selected object and links all parameters via Xpresso.   
      
    USAGE INSTRUCTIONS   
    ------------------   
      
    1. Select an object.   
    2. Run "Scripts > CV-Make Replicant"   
      
    LICENSE   
    -------   
      
    Copyright (C) 2015 Maxon Computer, Inc.   
    Programming: Donovan Keith <donovanskeith@gmail.com>   
      
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE   
    WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR   
    COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR   
    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   
    """   
      
    #====== IMPORTS ======#   
      
    import c4d   
      
    #====== GLOBALS ======#   
      
    PLUGIN_ID = None   
    PLUGIN_VERSION = "0.01"   
      
    #====== UTILS ======#   
      
    def AddObjectNode(node_master, obj, x=0) :   
        """Adds and returns an object node into Xpresso graph's node_master"""   
           
        obj_node = node_master.CreateNode(parent=node_master.GetRoot(), id=c4d.ID_OPERATOR_OBJECT, x=x, y=50)   
        obj_node[c4d.GV_OBJECT_OBJECT_ID] = obj   
        return obj_node   
      
    #====== MAIN ======#   
      
    def main() :   
        doc.StartUndo()   
           
        #Get the active objects   
        active_objects = doc.GetActiveObjects(flags=c4d.GETACTIVEOBJECTFLAGS_CHILDREN)   
           
        for source in active_objects:   
            #Make and insert a copy of the selected object   
            destination = source.GetClone()   
            destination.SetName(source.GetName() + " Replicant")   
            doc.InsertObject(destination, pred=source)   
            doc.AddUndo(c4d.UNDOTYPE_NEW, destination)   
           
            #Create XPresso Tag   
            xpresso_tag = c4d.modules.graphview.XPressoTag()   
            node_master = xpresso_tag.GetNodeMaster()   
      
            #Add the Tag to the destination object   
            destination.InsertTag(xpresso_tag)   
      
            #Add a Node for the source object   
            source_node = AddObjectNode(node_master, source, x=50)   
            dest_node = AddObjectNode(node_master, destination, x=300)   
      
      
            #Add and link ports for all parameters, except:   
            banned_ids = [   
                c4d.ID_BASELIST_NAME,   
                c4d.ID_LAYER_LINK,   
                c4d.ID_BASEOBJECT_VISIBILITY_EDITOR,   
                c4d.ID_BASEOBJECT_VISIBILITY_RENDER,   
                c4d.ID_BASEOBJECT_USECOLOR,   
                c4d.ID_BASEOBJECT_COLOR,   
                c4d.ID_BASEOBJECT_GENERATOR_FLAG,   
                c4d.ID_BASEOBJECT_XRAY   
            ]   
      
            banned_types = [   
                c4d.CUSTOMGUI_BUTTON,   
                c4d.CUSTOMGUI_STATICTEXT,   
                c4d.CUSTOMGUI_SEPARATOR,   
                c4d.CUSTOMGUI_PROGRESSBAR   
            ]   
      
      
            #Loop through all parameters of the active   
            source_obj_description = source.GetDescription(flags=c4d.DESCFLAGS_DESC_0)   
            for bc, descid, groupid in source_obj_description:   
                id = descid[0].id   
                if id in banned_ids:   
                   continue   
      
                data_type = bc[c4d.DESC_CUSTOMGUI]   
                if (data_type is not None) and (data_type not in banned_types) :   
                   #Add a output port   
                   output_port = source_node.AddPort(c4d.GV_PORT_OUTPUT, descid)   
      
                   #Tell C4D that it should display the Output port???   
                   bc[c4d.DESC_OUTPORT] = True   
      
                   #Add an input port   
                   input_port = dest_node.AddPort(c4d.GV_PORT_INPUT, descid, flag=c4d.GV_PORT_FLAG_IS_VISIBLE)   
      
                   #Link the two   
                   output_port.Connect(input_port)   
      
            source.Message(c4d.MSG_CHANGE)   
            destination.Message(c4d.MSG_CHANGE)   
            doc.AddUndo(c4d.UNDOTYPE_NEW, xpresso_tag)   
           
        c4d.EventAdd()   
        doc.EndUndo()   
      
    if __name__=='__main__':   
        main()   
    


  • On 04/12/2015 at 03:38, xxxxxxxx wrote:

    Hello,

    if you want to find out if a parameter is animateable you can check the DESC_ANIMATE parameter of the description. But you are asking if a parameter has a subdescription. Since the Description is very limited in Python I guess the best solution is to check if the parameter is question is a vector or color and to handle the subparameters manually.

    The BaseContainer returned by GetDescription() is a copy so changing this BaseContainer won't do anything.

    The Xpresso usage of a parameter is only displayed in the Attribute Manager if the connection between the Object Operator and the referenced object is created properly. To do this one would have to use OperatorSetData() which is only available in C++.

    The Object Operator is able to fix this connection. This is done for example when the document is merged with another document. So a "hack" would be to send the MSG_DOCUMENTINFO_TYPE_LOAD message. Something like this:

      
    doc.SendInfo(c4d.MSG_DOCUMENTINFO_TYPE_LOAD, c4d.FORMAT_C4DIMPORT, "", None, False)  
    

    best wishes,
    Sebastian



  • On 04/12/2015 at 11:41, xxxxxxxx wrote:

    Hi Sebastian,

    That hack does the trick! I never would have found that. Thank you. I assume this will be pretty slow on large scenes as it will force a full reload?
    Thanks!

    Donovan


Log in to reply