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!
krisComplete 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.)