Open Search
    Graph View Data Format (XPresso) Manual

    Currently there are two ways to store data of variable type. The first one is GeData, the class that is used in most of the SDK for example in BaseContainer. The second one is the void* data that is used in Graph View. This document describes how the Graph View data type system works.

    Note: Types registered with CustomDataTypeClass are automatically included in the Graph View type system as well.

    Value vs. Data

    The actual format of the data stored in the void* pointer is determined by its value, described by a GvValueID. This is all you need to know to be able to perform calculations with the data or convert it to other types.

    Similar kinds of data can share a common value. The combination of a symbol/name and a value is called a data, described by a GvDataID. For example both the normal and the color data types could be implemented as a vector value.

    The different data types are grouped in value groups. However, currently there is only one group, so you can ignore this feature most of the time.

    Note
    FindCustomDataTypePlugin() will always return a valid plugin when fed a GvValueID. You cannot convert a GvValueID to a GvDataID directly, though you can do CallCustomDataType(pl, GetDataID).

    Raw Format

    For the common built-in types (Int32, Float, Vector, Matrix, BaseTime and String) the void* pointer simply points to the data type in question. For custom data types it instead points to the GvHelper structure. Please observe that generally these pointers are to an array that you should index with the current CPU ID.

    Note
    Normally you should not need to manipulate these raw values.

    Dynamic Data

    GvDynamicData is a convenience structure that stores both the void* data pointer and a GvDataInfo structure with the handlers. There are several ways to get a dynamic data structure:

    • If you have a GvDataID you can first use GvWorld::GetDataTypeInfo() to get the information for the data type. Then you can use GvAllocDynamicData() to allocate your data.
    • If you only have a GvValueID you can use FindCustomDataTypePlugin() and CallCustomDataType(pl, GetDataID) to get the GvDataID.
    • You can also allocate the data pointer manually with GV_VALUE_HANDLER::Alloc().

    Many of these functions are implemented in clear code in c4d_graphview.h and c4d_graphview.cpp, so you can see how they work.

    Examples

    Getting a GeData from a calculated port:

    GeData GvGetPortGeData(GvNode* node, GvPort* port, GvRun* run, Bool* success)
    {
    if (success)
    *success = false;
    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;
    GeData result;
    if (port->GetData(data.data, data.info->value_handler->value_id, run))
    {
    CUSTOMDATATYPEPLUGIN* pl = FindCustomDataTypePlugin(data.info->data_handler->data_id);
    if (pl && CallCustomDataType(pl, ConvertGvToGeData)(data.data, 0, result))
    {
    if (success)
    *success = true;
    }
    }
    return result;
    }
    GvDataInfo * GetDataTypeInfo(GvDataID id)
    Definition: c4d_graphview.h:2388
    PyObject PyObject * result
    Definition: abstract.h:43
    Bool GvAllocDynamicData(GvNode *bn, GvDynamicData &data, GvCalc *c, Int32 id)
    Definition: c4d_graphview.h:2707
    GvWorld * GvGetWorld()
    void GvFreeDynamicData(GvDynamicData &data)
    Definition: c4d_graphview.h:2718
    CUSTOMDATATYPEPLUGIN * FindCustomDataTypePlugin(Int32 type)
    maxon::Bool Bool
    Definition: ge_sys_math.h:46
    _Py_clock_info_t * info
    Definition: pytime.h:197
    Definition: node.h:10

    Setting the port data from a GeData:

    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==nullptr)
    return false;
    GvDynamicData data;
    CUSTOMDATATYPEPLUGIN* pl = FindCustomDataTypePlugin(data.info->data_handler->data_id);
    if (pl==nullptr)
    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;
    }

    Getting a Thinking Particles particle ID from a port:

    Int32 GvGetParticleID(GvNode* node, GvPort* port, GvRun* run)
    {
    if (!port || !node || !run) return NOTOK;
    GeData p = GvGetPortGeData(node, port, run);
    if (p.GetType() != ID_TP_DATA_TYPE_PARTICLE) return NOTOK;
    struct GvParticleHelper : public CustomDataType
    {
    Int32* pid;
    }* helper = static_cast<GvParticleHelper*>(p.GetCustomDataType(ID_TP_DATA_TYPE_PARTICLE));
    if (!helper || !helper->pid) return NOTOK;
    return *(helper->pid);
    }
    Setting a Thinking Particles particle ID in a port:
    Bool GvSetParticleID(Int32 pid, GvNode* node, GvPort* port, GvRun* run)
    {
    if (!port || !node || !run) return NOTOK;
    struct GvParticleHelper : public CustomDataType
    {
    Int32* pid;
    } helper;
    helper.pid = &pid;
    GeData p(ID_TP_DATA_TYPE_PARTICLE, helper);
    return GvSetPortGeData(p, node, port, run);
    }
    #define ID_TP_DATA_TYPE_PARTICLE
    Particle data type ID.
    Definition: c4d_particles.h:30
    unsigned char * p
    Definition: floatobject.h:87
    #define NOTOK
    Definition: ge_sys_math.h:258
    maxon::Int32 Int32
    Definition: ge_sys_math.h:51