Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
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"; }
*/
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); }
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.
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.)