my expresso-node example, and questions



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

    On 16/12/2002 at 03:43, xxxxxxxx wrote:

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

    ---------
    I made an Expresso node based on Mikael Sterner's example in "Topic: Nodes that Iterate",
    and some of his other examples.

    (my node is not suppose to iterate).
    It works, but I have no idea if I did it right...
    Also, it has one problem: When nothing is connected to the inport,
    i want to get the value directly from the inport, but the ...->Calculate(bn,r,c) returns NULL!

    So, how do I get the import values without having to connect them to something?

    BTW: Life would be easier if all of Maxon's own nodes where available in source.

    Thanks!
    kris

    Complete source code follows: (with some more questions).
    ////////////////////////////////////////////////////
    ////////////////////////////////////////////////////
    #include "c4d.h"
    #include "c4d_operatordata.h"

    #include "Kaaref1.h"

    // forward declarations for functions from Mikael Sterner's post in "Topic: from port->SetData".
    // I use these because port->GetData and ->SetData cause Cinema to crash.
    GeData GvGetPortGeData(GvNode* node, GvPort* port, GvRun* run);
    Bool GvSetPortGeData(const GeData& ge_data, GvNode* node, GvPort* port, GvRun* run);

    const GvOperatorID KAAGETTAG1_ID = 10983430; // just random
    static LONG input_ids[] = { 0 };

    class KaaGvRef1 : public GvOperatorData
    {
    private:
         GvCalcTable* table; // not used... What is it for?
    public:
         LONG mode;
         LONG steps;

    KaaGvRef1(void) : table(NULL) {}
         
         Bool Init(GeListNode *node)
         {          
              // Use iCreateOperator instead!
              return TRUE;
         }
              
         virtual Bool iCreateOperator(GvNode *bn)
         {
              BaseContainer* data = bn->GetOpContainerInstance();
              if (!data) return FALSE;
              data->SetLong(STEPS, 3);
              //return SUPER::iCreateOperator(bn); // SUPER undefined...
              return GvOperatorData::iCreateOperator(bn);
         }

    Bool InitCalculation(GvNode *bn, GvCalc *c, GvRun *r)
         {
              BaseContainer *data = bn->GetOpContainerInstance();
              steps = data->GetLong(STEPS);
              mode = data->GetLong(MODE_ID);
              return TRUE;          
         }

    void FreeCalculation(GvNode *bn, GvCalc *c)
         {
         }

    Bool Calculate(GvNode *bn, GvPort *port, GvRun *r, GvCalc *c)
         {
              if (!port) return TRUE;
              
              // Calculate inport
              GvPort* inport = bn->GetInPortFirstMainID(INPORT_LINK);
              if (!inport) return FALSE; // never happens?
              inport = inport->Calculate(bn, r, c); // link
              if (!inport) return FALSE; // hapens when the inport is not connected
              // this is where I want to get data from the node itself!

    // Get the data from the inport
              BaseList2D * mylist2D = NULL; // can't use AutoAlloc
              
              GeData linkdata = GvGetPortGeData(bn, inport, r);
              BaseLink* test = linkdata.GetBaseLink();
              if (test && test->GetLink(bn->GetNodeMaster()->GetDocument()))
              {
                   mylist2D = test->GetLink(bn->GetNodeMaster()->GetDocument());
                   GePrint(mylist2D->GetName());
              }
              else {
                   GePrint("no link");
              }

    // do I have to get the inport data for each outport i wish to calculate?
              // or is it a bette way?

    switch(port->GetMainID()) // maby not needet for one outport?
              {
                   // is this the right way, when you have many outports? What is most efficient?
                   case OUTPORT_LINK:
                   {
                        BaseObject * b = (BaseObject* )mylist2D;                    
         
                        for (LONG i = 0; i<steps; i++){
                             switch(mode){
                                  case GETDOWN:
                                       b = b->GetDown(); break;
                                  case GETUP:
                                       b = b->GetUp(); break;
                                  case GETPRED:
                                       b = b->GetPred(); break;
                                  case GETNEXT:
                                       b = b->GetNext(); break;
                             }     
                             if (!b) break;
                        }
                        AutoAlloc<BaseLink> bl;
                        bl->SetLink(b);
                        GvSetPortGeData(GeData(bl), bn, port, r); // returns bool
                        break;
                   }
              }

    return TRUE;
         }

    static NodeData* Alloc(void) { return gNew KaaGvRef1; }
    };

    Bool RegisterKaaref1()
    {
         return GvRegisterOperatorPlugin(
              KAAGETTAG1_ID, "Kaaref1", 0,
              KaaGvRef1::Alloc, "Kaaref1", 0,
              ID_GV_OPCLASS_TYPE_GENERAL, ID_GV_OPGROUP_TYPE_GENERAL, 0, NULL);
    }

    /*

    // Kaaref1.res
    CONTAINER Kaaref1
    {
         NAME Kaaref1;
         INCLUDE GVbase;
         GROUP ID_GVPROPERTIES
         {
              LONG MODE_ID
              {
                   CYCLE
                   {
                        GETDOWN;
                        GETUP;
                        GETPRED;
                        GETNEXT;
                   }
              }
              LONG STEPS { MIN 0; }
         }
         GROUP ID_GVPORTS
         {
              LINK INPORT_LINK {INPORT; STATICPORT; CREATEPORT;}
              LINK OUTPORT_LINK {OUTPORT; STATICPORT; CREATEPORT;}
         }
    }

    // Kaaref1.h
    #ifndef _Kaaref1_H_
    #define _Kaaref1_H_
    enum
    {
         MODE_ID               = 1000,
              GETDOWN          = 0,
              GETUP,
              GETPRED,
              GETNEXT,

    STEPS = 2000,
         INPORT_LINK = 3000,
         OUTPORT_LINK = 4000
    };
    #endif

    // Kaaref1.str
    STRINGTABLE Kaaref1
    {
         Kaaref1 "Kaaref1";
         MODE_ID               "Mode";
              GETDOWN          "GetDown()";
              GETUP          "GetUp()";
              GETPRED          "GetPrev()";
              GETNEXT          "GetNext()";
         STEPS "Steps";
         INPORT_LINK "in";
         OUTPORT_LINK "out";
    }

    */



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

    On 17/12/2002 at 02:19, xxxxxxxx wrote:

    Well, first of all the Xpresso API isn't officially supported at the moment. But that being said here's a better example using some convenience functions I learned along the way:

        
        
        #include "c4d.h"  
        #include "c4d_operatordata.h"
        
        
        
        
        #include "Kaaref1.h"
        
        
        
        
        // Updated versions:
        
        
        
        
        GeData GvGetPortGeData(GvNode* node, GvPort* port, GvRun* run)  
        {   
          if (!node || !port) return GeData();
        
        
        
        
          GvPortDescription pd;  
          if (!node->GetPortDescription(port->GetIO(), port->GetMainID(), &pd)) return GeData();  
            
          GvDataInfo* info = GvGetWorld()->GetDataTypeInfo(pd.data_id);  
          if (!info) return GeData();  
            
          GvDynamicData data;  
          GvAllocDynamicData(node, data, info);  
            
          if (!port->GetData(data.data, data.info->value_handler->value_id, run)) return GeData();  
            
          CUSTOMDATATYPEPLUGIN* pl =   
            FindCustomDataTypePlugin(data.info->data_handler->data_id);   
          if (!pl) return GeData();  
            
          GeData ge_data;   
          if (!CallCustomDataType(pl, ConvertGvToGeData)(data.data, 0, ge_data)) return GeData();  
            
          return ge_data;  
        }
        
        
        
        
        Bool GvSetPortGeData(const GeData& ge_data, GvNode* node, GvPort* port, GvRun* run)  
        {   
          if (!node || !port || !run) return FALSE;  
            
          GvPortDescription pd;  
          if (!node->GetPortDescription(port->GetIO(), port->GetMainID(), &pd)) return FALSE;
        
        
        
        
          GvDataInfo* info = GvGetWorld()->GetDataTypeInfo(pd.data_id);  
          if (!info) return FALSE;  
            
          GvDynamicData data;  
          GvAllocDynamicData(node, data, info);  
            
          CUSTOMDATATYPEPLUGIN* pl =   
            FindCustomDataTypePlugin(data.info->data_handler->data_id);   
          if (!pl) return FALSE;  
            
          if (!CallCustomDataType(pl, ConvertGeDataToGv)(ge_data, data.data, 0)) return FALSE;  
            
          if (!port->SetData(data.data, data.info->value_handler->value_id, run)) return FALSE;  
            
          return TRUE;  
        }
        
        
        
        
        const GvOperatorID KAAGETTAG1_ID = 1010893; // From PluginCafe!
        
        
        
        
        static LONG input_ids[] = { INPORT_LINK, 0 }; // Use this for the input ports!  
        enum { INPORT_LINK_INDEX };
        
        
        
        
        class KaaGvRef1 : public GvOperatorData  
        {  
        // Defines super  
        INSTANCEOF(KaaGvRef1, GvOperatorData)  
        public:
        
        
        
        
            
          virtual Bool iCreateOperator(GvNode *bn)  
          {  
            BaseContainer* data = bn->GetOpContainerInstance();   
            if (!data) return FALSE;
        
        
        
        
            data->SetLong(STEPS, 3);
        
        
        
        
            return SUPER::iCreateOperator(bn);  
          }  
            
            
            
          Bool InitCalculation(GvNode *bn, GvCalc *c, GvRun *r)  
          {  
            return GvBuildInValuesTable(bn, ports, c, r, input_ids);      
          }  
            
            
          void FreeCalculation(GvNode *bn, GvCalc *c)  
          {  
            GvFreeValuesTable(bn, ports);  
          }  
            
          Bool Calculate(GvNode *bn, GvPort *port, GvRun *run, GvCalc *calc)  
          {  
            if (!port) return FALSE;  
              
            BaseContainer *data = bn->GetOpContainerInstance();  
            if (!data) return FALSE;
        
        
        
        
            LONG steps = data->GetLong(STEPS);  
            LONG mode = data->GetLong(MODE_ID);
        
        
        
        
            GvValue* vinport = ports.in_values[INPORT_LINK_INDEX];  
            if (!vinport) return FALSE; // Doesn't matter that it never happens; always check pointers!
        
        
        
        
            if (!vinport->Calculate(bn, GV_PORT_INPUT, run, calc, 0)) return FALSE;  
              
            GvPort* inport = vinport->GetPort();  
            GeData inportdata = GvGetPortGeData(bn, inport, run);
        
        
        
        
            BaseDocument* doc = bn->GetNodeMaster()->GetDocument();  
            if (!doc) return FALSE;
        
        
        
        
            BaseLink* link = inportdata.GetBaseLink();  
            if (!link) return FALSE;
        
        
        
        
            BaseList2D* list = link->GetLink(doc);  
            if (!list) return FALSE;  
              
            switch(port->GetMainID())   
            {  
            case OUTPORT_LINK:  
              {  
                BaseObject* obj = static_cast<BaseObject*>(list);  
                for (LONG i = 0; list && i < steps; ++i)  
                {  
                  switch(mode)  
                  {  
                  case GETDOWN: obj = obj->GetDown(); break;  
                  case GETUP: obj = obj->GetUp(); break;  
                  case GETPRED: obj = obj->GetPred(); break;  
                  case GETNEXT: obj = obj->GetNext(); break;  
                  }       
                } 
        
        
        
        
                AutoAlloc<BaseLink> bl;  
                if (!bl) return FALSE;  
                bl->SetLink(obj);
        
        
        
        
                return GvSetPortGeData(GeData(bl), bn, port, run);  
              }  
            }  
              
            return FALSE;  
          }  
              
          static NodeData* Alloc(void) { return gNew KaaGvRef1; }
        
        
        
        
        private:  
          GvValuesInfo ports;  
        };
        
        
        
        
        const LONG ID_GV_OPGROUP_MY = 1010850;  
        const LONG ID_GV_OPCLASS_MY = 1010851;
        
        
        
        
        static const String* GetMyGroupName()  
        {  
          static String mygroup("My Group");  
          return &mygroup;  
        }
        
        
        
        
        static BaseBitmap* GetMyGroupIcon()  
        {  
          // Never used  
          static AutoAlloc<BaseBitmap> icon;  
          if (!icon) return NULL;  
          if (icon->GetBw() == 0)  
          {  
            icon->Init(24, 24);  
            icon->Clear(200, 0, 0);  
          }  
          return icon;  
        }
        
        
        
        
        static const String* GetMyClassName()  
        {  
          static String mygroup("My Class");  
          return &mygroup;  
        }
        
        
        
        
        static BaseBitmap* GetMyClassIcon()  
        {  
          // Never used  
          static AutoAlloc<BaseBitmap> icon;  
          if (!icon) return NULL;  
          if (icon->GetBw() == 0)  
          {  
            icon->Init(24, 24);  
            icon->Clear(0, 0, 200);  
          }  
          return icon;  
        }
        
        
        
        
         
        
        
        
        
        Bool RegisterKaaref1()  
        {  
          static AutoAlloc<BaseBitmap> icon;  
          if (!icon) return NULL;  
          if (icon->GetBw() == 0)  
          {  
            icon->Init(24, 24);  
            icon->Clear(100,200, 0);  
          }
        
        
        
        
          static GV_OPCLASS_HANDLER myclass;  
          myclass.class_id = ID_GV_OPCLASS_MY;  
          myclass.GetName = GetMyClassName;  
          myclass.GetIcon = GetMyClassIcon;
        
        
        
        
          if (!GvRegisterOpClassType(&myclass, sizeof(myclass))) return FALSE;
        
        
        
        
          static GV_OPGROUP_HANDLER mygroup;  
          mygroup.group_id = ID_GV_OPGROUP_MY;  
          mygroup.GetName = GetMyGroupName;  
          mygroup.GetIcon = GetMyGroupIcon;
        
        
        
        
          if (!GvRegisterOpGroupType(&mygroup, sizeof(mygroup))) return FALSE;;
        
        
        
        
          return GvRegisterOperatorPlugin(  
            KAAGETTAG1_ID, "Kaaref1", 0,   
            KaaGvRef1::Alloc, "Kaaref1", 0,   
            ID_GV_OPCLASS_MY, ID_GV_OPGROUP_MY, ID_GV_IGNORE_OWNER, icon);  
        }
    


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

    On 17/12/2002 at 05:00, xxxxxxxx wrote:

    I compiled it, and it works!
    Had to change "list" in "for (LONG i = 0; list && i < steps; ++i)" to "obj"

    Nice to have a custom class and group (GvRegisterOpClassType, GvRegisterOpGroupType)
    Did you just give them random IDs?

    Thank you.



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

    On 17/12/2002 at 11:49, xxxxxxxx wrote:

    Quote: Originally posted by kris on 17  December 2002
    >
    > * * *
    >
    >
    > Nice to have a custom class and group (GvRegisterOpClassType, GvRegisterOpGroupType)
    > Did you just give them random IDs?
    No, they must be unique IDs from plugincafe. (Every time you see a seemingly random number it's a good bet that it's a unique ID.)


Log in to reply