Programmatically doing Set Driven Keys



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 29/03/2006 at 20:56, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   9.102 
    Platform:   Windows  ; Mac  ;  Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    I'd like to set up XPresso driver and driven parameters from within my C++ plugin programmatically, exactly as "Set Driven (Relative)" does interactively. Not only does it need to set these, but also configure the Relative mapping values (Set Driven (Relative)).

    How can this be accomplished?

    Thanks!



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 30/03/2006 at 04:47, xxxxxxxx wrote:

    Okay, here is my pathetic attempt so far. Note that AddPortIsOK() always returns false. Talk about 'being the mushroom'. I am blindly attempting blind attempts at blind code. Hmmm, could you pretty please provide several (dozen) examples in the next SDK release, please...

    // IPPDial.ResolveMasterDials  
    // - Convert Channel MasterDialEntries into Active MasterDials (XPresso tags)  
    //*---------------------------------------------------------------------------*  
    Bool IPPDial::ResolveMasterDials(BaseDocument* doc, AtomArray* atomArray, BaseObject* ippBase, BaseTag* tag, BOOL doUndo)  
    //*---------------------------------------------------------------------------*  
    {  
         XPressoTag*          xtag;  
         GvNodeMaster*     nodeMaster;  
         GvNode*               root;  
         // Driver  
         GvNode*               snode;  
         GvPort*               sport;  
         // RangeMapper  
         GvNode*               rnode;  
         GvPort*               riport;  
         GvPort*               roport;  
         // Driven  
         GvNode*               dnode;  
         GvPort*               dport;  
         BaseObject*          driver;  
         BaseTag*          dial;  
         BaseContainer*     bc =          tag->GetDataInstance();  
         BaseContainer*     nbc;  
         LONG               sindex;  
         LONG               dindex =     bc->GetLong(IPPDIAL_INDEX);  
         ULONG               flags;  
         LONG               x = 8, y = 8;  
         String               nodeName =     ippBase->GetDataInstance()->GetString(IPP_INTERNALNAME)+"."+bc->GetString(IPPDIAL_DIALNAME);  
         for (MasterDialEntry* md = firstMaster; md != lastMaster; md++)  
         {  
              // Find Driver slider  
              driver =          md->bodypart.GetObject(atomArray);  
              if (!(driver && driver->IsInstanceOf(ID_IPPBASE)))     continue;  
              // - Get Dial and index  
              for (dial = driver->GetFirstTag(); dial; dial = dial->GetNext())  
              {  
                   if (!(dial->IsInstanceOf(ID_IPPDIALTAG) || dial->IsInstanceOf(ID_IPPMORPHTAG)))     continue;  
                   bc =     dial->GetDataInstance();  
                   if (bc->GetString(IPPDIAL_DIALNAME) == md->dialName) break;  
              }  
              if (!dial)     continue;  
              sindex =               bc->GetLong(IPPDIAL_INDEX);  
      
              // Create an XPresso tag on the dial tag's ippBase  
              xtag =                    static_cast<XPressoTag*>(ippBase->GetTag(Texpresso));  
              if (!(xtag && (xtag->GetName() == "IPP Slaved")))  
              {  
                   xtag =               XPressoTag::Alloc();  
                   if (!xtag)          return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.xtag");  
                   ippBase->InsertTag(xtag);  
                   xtag->SetName("IPP Slaved");  
              }  
              // Create, Link, and Configure nodes  
              nodeMaster =          xtag->GetNodeMaster();  
              if (!nodeMaster)     return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.nodeMaster");  
              root =                    nodeMaster->GetRoot();  
              if (!root)               return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.root");  
              snode =                    nodeMaster->CreateNode(root, ID_OPERATOR_OBJECT, NULL, x, y);  
              if (!snode)               return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.snode");  
              rnode =                    nodeMaster->CreateNode(root, ID_OPERATOR_RANGEMAPPER, NULL, x+144, y);  
              if (!rnode)               return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.rnode");  
              dnode =                    nodeMaster->CreateNode(root, ID_OPERATOR_OBJECT, NULL, x+288, y);  
              if (!dnode)               return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.dnode");  
              nbc =                    snode->GetOpContainerInstance();  
              nbc->SetLink(GV_OBJECT_OBJECT_ID,     driver);  
              nbc->SetLong(GV_OBJECT_PATH_TYPE,     GV_OBJECT_PATH_TYPE_ABSOLUTE);  
              nbc =                    dnode->GetOpContainerInstance();  
              nbc->SetLink(GV_OBJECT_OBJECT_ID,     ippBase);  
              nbc->SetLong(GV_OBJECT_PATH_TYPE,     GV_OBJECT_PATH_TYPE_RELATIVE);  
              // - Add Ports  
              if (snode->AddPortIsOK(GV_PORT_OUTPUT, sindex))          sport =          snode->AddPort(GV_PORT_OUTPUT, sindex);  
              else                    return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.sport");  
              if (dnode->AddPortIsOK(GV_PORT_INPUT, dindex))          dport =          dnode->AddPort(GV_PORT_INPUT, dindex);  
              else                    return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.dport");  
              roport =               rnode->GetOutPort(0);  
              if (!roport)          return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.roport");  
              riport =               rnode->GetInPort(0);  
              if (!riport)          return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.riport");  
              /*  
              // - Connect Driver to RangeMapper  
              if (!nodeMaster->IsConnectionValid(snode, sport, rnode, riport, snode, sport, rnode, riport))     { GePrint("InvalidConnection 1"); return FALSE; }  
              if (!snode->AddConnection(snode, sport, rnode, riport))     return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.AddConnection");  
              // - Connect RangeMapper to Driven  
              if (!nodeMaster->IsConnectionValid(rnode, roport, dnode, dport, rnode, roport, dnode, dport))     { GePrint("InvalidConnection 2"); return FALSE; }  
              if (!rnode->AddConnection(rnode, roport, dnode, dport))     return ErrorException::Throw(GeLoadString(ERROR_MEMORY_TEXT), "IPPDial.ResolveMasterDials.AddConnection");  
              */  
      
              // Mark Driver as having Slaves  
              flags =               (ULONG)bc->GetLong(IPPDIAL_TYPESUBFLAGS);  
              bc->SetLong(IPPDIAL_TYPESUBFLAGS, (LONG)(flags & DIAL_FLAGS_SLAVES));  
              y += 80;  
         }  
         EventAdd();  
         GeFree(firstMaster);  
         firstMaster = NULL;  
         return TRUE;  
    }
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 31/03/2006 at 02:26, xxxxxxxx wrote:

    Anything?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 31/03/2006 at 05:21, xxxxxxxx wrote:

    I can confirm that the naive attempt of node->AddPort(GV_PORT_OUTPUT, GV_OUTPUT_FIRST_ID); doesn't work for me either. I'm investigating if there's a proper way to do it.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 31/03/2006 at 12:01, xxxxxxxx wrote:

    I've already confirmed it, Mikael, and have found the solution (so that you can stop investigating this aspect anyway). Here it is:

    // PortList for finding available ports on node  
    AutoAlloc<GvPortList>     portList;  
    if (!portList)               return ErrorException::Throw("error");  
    GvPortListEntry*          portLE;  
    GvPortDescription          portDesc;  
    GvNode*                         snode; // filled using GvNodeMaster::CreateNode()  
    GvPort*                         sport;  
    // - Add Ports  
    // -- Source (Master) Node  
    portList->FlushAll();  
    snode->GetPortList(GV_PORT_OUTPUT, *portList);  
    LONG portCount =               portList->GetCount();  
    for (LONG i = 0; i < portCount; i++)  
    {  
         portLE =     portList->GetIndex(i);  
         snode->GetPortDescription(GV_PORT_OUTPUT, portLE->id, &portDesc;);  
         // I'm using the port name to find the port to be added  
         if (portDesc.name == md->dialName) break;  
    }  
    // -- No matching port  
    if (i == portCount)     return ErrorException::Throw("Master Node Port not found!");  
    if (!snode->AddPortIsOK(GV_PORT_OUTPUT, portLE->id))          return ErrorException::Throw("error");  
    sport =                    snode->AddPort(GV_PORT_OUTPUT, portLE->id);  
    if (!sport)               return ErrorException::Throw("error");  
    

    Adding the ports and connecting/configuring them, though, are two differnt things. Have had no luck connecting the ports and it seems that they (or the nodes) are not configured correctly. No idea on how to go about doing that.

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 31/03/2006 at 12:33, xxxxxxxx wrote:

    Almost forgot that I wanted to mention that after some experimenting with the XPresso nodes manually, the desired interaction isn't exactly like 'Set Driven Keys', but instead would be better modeled using something like this:

    Master(out) ---> (in0)|Math::Multiply(out) -> (in)Slave
    Constant(out) -> (in1)|

    The Constant node specifies a proportional multiplier of the Master's value that is used to set the Slave.

    So, one more node to contend with.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 31/03/2006 at 14:29, xxxxxxxx wrote:

    As a continuation of the issues with GraphView here, I'm not having any luck getting a GvRun from the GvNodeMaster. This is sort of catch-22 isn't it? It cannot be instantiated and there is no method (to be found in the docs) to force it or that says that this needs to be done to instantiate it (and yet everything seems to require it). But GvNodeMaster::GetRun() always returns NULL. So, how can one use GvSetPortGeData() (as shown in the docs and repeatedly here) if one does not know how to get the GvRun 'instantiated' in the GvNodeMaster?

    I'm finding it odd that it appears easier to create your own custom XPresso nodes than it is to just use the built-in ones. There is no intention for my code to control these blasted things once (if ever) they get setup properly. Once added, Cinema 4D should be doing the calculations and so on - as if the user added them manually.

    The reason that GvSetPortGeData() seems to be needed is that the Constant Node's data, for instance, is GvDynamic. So, this means that it needs to do all of that magical stuff in that method to set the Real value (since no other approach seems to work).

    One singular example of adding a couple of nodes, connecting one outport to one inport, and configuring it to work would probably cause thousands of SDK developers to actually use GraphView... ;)



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 02/04/2006 at 08:44, xxxxxxxx wrote:

    Here's a piece of code that seems to work:

        
        
        #include "c4d_graphview.h"  
        #include "c4d_operatorplugin.h"  
        #include "......\resource\modules\gv\expressiontag\res\description\gvobject.h"  
        #define GvCall(op,fnc) (((GvOperatorData* )op)->*((OPERATORPLUGIN* )C4DOS.Bl->RetrieveTableX((NodeData* )op,1))->fnc)
        
        
        
        
        Bool MenuTest::Execute(BaseDocument *doc)  
        {   
          BaseObject* cube = doc->GetFirstObject();  
          BaseObject* sphere = cube->GetNext();  
            
          DescID cubeid = DescID(DescLevel(ID_BASEOBJECT_POSITION), DescLevel(VECTOR_X));  
          DescID sphereid = DescID(DescLevel(ID_BASEOBJECT_POSITION), DescLevel(VECTOR_Y));  
            
          XPressoTag* x = static_cast<XPressoTag*>(sphere->GetTag(Texpresso, 0));  
          if (!x) x = static_cast<XPressoTag*>(sphere->MakeTag(Texpresso, NULL));  
            
          GvNodeMaster* m = x->GetNodeMaster();  
            
          GvNode* n1 = m->CreateNode(m->GetRoot(), ID_OPERATOR_OBJECT, NULL, 8, 8);  
          n1->OperatorSetData(GV_ATOM, cube, GV_OP_DROP_IN_BODY);  
          GvOperatorData* op1 = n1->GetOperatorData();    
          LONG s1 = GvCall(op1, GetMainID)(n1, GV_PORT_OUTPUT, cubeid);  
          GvPort* p1 = n1->AddPort(GV_PORT_OUTPUT, s1, GV_PORT_FLAG_IS_VISIBLE, TRUE);  
            
          GvNode* n2 = m->CreateNode(m->GetRoot(), ID_OPERATOR_OBJECT, NULL, 208, 8);  
          n2->OperatorSetData(GV_ATOM, sphere, GV_OP_DROP_IN_BODY);  
          GvOperatorData* op2 = n2->GetOperatorData();    
          LONG s2 = GvCall(op2, GetMainID)(n2, GV_PORT_INPUT, sphereid);  
          GvPort* p2 = n2->AddPort(GV_PORT_INPUT, s2, GV_PORT_FLAG_IS_VISIBLE, TRUE);  
            
          if (p1 && p2)  
          {  
            GvNode* n1u = NULL;  
            GvNode* n2u = NULL;  
            GvPort* p1u = NULL;  
            GvPort* p2u = NULL;  
            if (m->IsConnectionValid(n1, p1, n2, p2, n1u, p1u, n2u, p2u))  
            {  
              n2->AddConnection(n1u, p1u, n2u, p2u);  
            }  
          }  
            
          EventAdd();  
            
          return TRUE;  
        }
    

    Som points:

    • The Object node is initialized by simulating a drag-and-drop action.
    • The ports can then be added by asking the Object node directly about which ID to use.
    • The AddConnection() only works in one way, i.e. you need to call it for the destination node otherwise it silently fails.

    I hope this helps!



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 02/04/2006 at 19:33, xxxxxxxx wrote:

    Hi Mikael,

    Ah, would have never thought about drag-and-drop. I had tried to find ways to simulate that basic idea though with no success. And that information about AddConnection() is invaluable!

    Nearly everything worked! :) The last difficulty now seems to be with setting the Constant Node's value. I tried this:

    constNode->OperatorSetData(GV_REAL, &(md->deltaAddDelta), GV_OP_SET);

    but there was no change. Now, the docs state that for GV_OP_SET: (The constant node uses this.). Okay. But since GV_CONST_VALUE is a GvDynamic type, I'm still not certain about how to set it even with OperatorSetData(). Maybe it wants a GvDynamic in the void* argument?

    Again, there is no GvRun returning from GvNodeMaster so use of GvSetPortGeData() seems to be out (for now).

    Thank you very much for taking the time to research this and provide working code!



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/04/2006 at 19:07, xxxxxxxx wrote:

    Still no luck setting constNode's GV_CONST_VALUE. I've tried everything! And I mean everything:

    opbc- >SetData()
    opbc->SetReal() - good for crashing C4D
    constNode->SetParameter() - also can be coaxed into crashing C4D
    constNode->OperatorSetData()
    assorted GvSetPortData()-like setups

    I've printed the OperatorBaseContainer (which does point to the DA_REAL value, but will not set). I've printed the entire GvDynamicData struct (include GvDataInfo). Nothing of use there. ConvertGeDataToGv() never succeeds when attempting to use that, unless I use the ConstNode OutPort - but the data cannot be set without GvRun. And I cannot get a GvRun. Even tried InitCalculate/Calculate/FreeCalculate on the nodeMaster to see if it came into existence - nope.

    The fact that some setting attempts literally crash C4D says that there is some deep, hidden stuff to which I am not being privy. The last thing that may be attempted is to go through the Descriptions and see if I can get some sort of DescID set that may work (or continue crashing C4D). ;)

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/04/2006 at 17:16, xxxxxxxx wrote:

    To continue, it seems that it may not happen until some other area is set or initialized or something. Using OperatorIsSetDataAllowed() on the Constant Node returns FALSE. So no GvRun for setting the GvPort (not that this is the solution) and no way to set the GvOperatorData even if the code is correct.

    This is getting very frustrating - I donot like this DYNAMIC stuff at all, not without much more information than is given. Three days of pounding this Dynamic GV_CONST_VALUE description with 1000 lb bombs, mortar fire, strafing, and nuclear warheads - nothin'...it won't budge. ;0)



  • On 02/06/2015 at 05:34, xxxxxxxx wrote:

    Hi,

    I recently had the same problem, but I had it fixed.

    First of all, you have to include the gvconst.h file (you have to do this for every type of node you want to use, apparentally.
    So:

    #include "gvconst.h"

    Then, inside your method:

      
    GvNode* constantNode = myNodeMaster->CreateNode(myNodeMaster->GetRoot(), ID_OPERATOR_CONST);  
    if (!constantNode) return false;  
    constantNode->SetParameter(GV_DYNAMIC_DATATYPE, ID_GV_DATA_TYPE_REAL, DESCFLAGS_SET_0);  
    constantNode->SetParameter(GV_CONST_VALUE, Int32(-1), DESCFLAGS_SET_0);  
    GvPort* constantOutPort = constantNode->GetOutPort(0);  
    

    This worked for me.
    I hope my answer isn't too late.
    Greetings,

    Casimir Smets


Log in to reply