Open Search
    BaseContainer Manual

    About

    A BaseContainer is a collection of individual values. Each value has its own ID and type. A BaseContainer can also carry any number of child containers. 90% of Cinema 4D's internal values are stored in containers and all messages are working with containers, so this class is an essential part of the SDK. Containers can store any GeData type, including custom data types. It is recommended to use the available containers to store values in custom NodeData based plugins.

    Warning
    Keep in mind that there is no guarantee for a value to be in the container. Use default values whenever possible when accessing container's ID data.
    Use the typed access methods (for example BaseContainer::GetBool()) whenever possible, instead of the low-level BaseContainer::GetData(). See Access.
    Once a container value has been set using one type one must neither try to access it using another type, nor overwrite it with a value of another type. Using the wrong access will not crash, but it is illegal.
    Note
    To browse through all elements of a BaseContainer use the class BrowseContainer.

    Access

    Every BaseList2D based object of the Cinema 4D API has a BaseContainer that stores its data. This BaseContainer can be accessed with:

    • BaseList2D::GetData(): Returns a copy of the object's BaseContainer.
    • BaseList2D::SetData(): Sets the object's BaseContainer.
    • BaseList2D::GetDataInstance(): Returns a pointer to the object's BaseContainer.
    • BaseList2D::GetDataInstanceRef(): Returns a reference to the object's BaseContainer.

    See BaseList2D Manual.

    Note
    Object parameters should be edited with C4DAtom::GetParameter() / C4DAtom::SetParameter(). Not all parameters of an object may be stored in the BaseContainer.
    // This example accesses the BaseContainer storing the render settings.
    // The BaseContainer is needed as an argument of RenderDocument().
    RenderData* const rdata = doc->GetActiveRenderData();
    if (rdata == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    const BaseContainer renderSettings = rdata->GetDataInstanceRef();
    AutoAlloc<BaseBitmap> bitmap;
    if (bitmap == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // prepare target bitmap
    const Int32 width = renderSettings.GetInt32(RDATA_XRES, 1280);
    const Int32 height = renderSettings.GetInt32(RDATA_YRES, 720);
    const IMAGERESULT imageRes = bitmap->Init(width, height);
    if (imageRes != IMAGERESULT::OK)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // render the image
    const RENDERRESULT res = RenderDocument(doc, renderSettings, nullptr, nullptr, bitmap, flags, nullptr);
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // show the result in the Picture Viewer
    ShowBitmap(bitmap);
    PyCompilerFlags * flags
    Definition: ast.h:14
    Py_UCS4 * res
    Definition: unicodeobject.h:1113
    OK
    User has selected a font.
    Definition: customgui_fontchooser.h:0
    @ RDATA_XRES
    Definition: drendersettings.h:152
    @ RDATA_YRES
    Definition: drendersettings.h:153
    NODOCUMENTCLONE
    Set to avoid an automatic clone of the scene sent to RenderDocument().
    Definition: ge_prepass.h:2
    IMAGERESULT
    Definition: ge_prepass.h:3954
    RENDERFLAGS
    Definition: ge_prepass.h:4725
    RENDERRESULT
    Definition: ge_prepass.h:427
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:69
    Bool ShowBitmap(const Filename &fn)
    maxon::Int32 Int32
    Definition: ge_sys_math.h:51
    RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
    unsigned long Py_ssize_t width
    Definition: pycore_traceback.h:88
    const char * doc
    Definition: pyerrors.h:226

    BaseContainer elements are also often used as an argument in a function call.

    Copy

    The complete content of a BaseContainer object can be copied to another object:

    • BaseContainer::CopyTo(): The content is copied into the given BaseContainer.
    • BaseContainer::GetClone(): Returns a copy of the container including all values.
    • BaseContainer::operator=: Copies the BaseContainer.

    It is also possible to copy a BaseContainer using the copy constructor.

    // This example creates a BaseContainer copies in different ways:
    BaseContainer original;
    original.SetString(100, "foo"_s);
    original.SetString(200, "bar"_s);
    // CopyTo()
    BaseContainer target;
    target.SetString(300, "foobar"_s);
    if (!original.CopyTo(&target, COPYFLAGS::NONE, nullptr))
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    ApplicationOutput(target.GetString(100));
    ApplicationOutput(target.GetString(200));
    ApplicationOutput(target.GetString(300)); // This value is now deleted.
    // GetClone()
    BaseContainer* clone = original.GetClone(COPYFLAGS::NONE, nullptr);
    if (clone == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    ApplicationOutput(clone->GetString(100));
    ApplicationOutput(clone->GetString(200));
    DeleteObj(clone);
    // Copy Constructor
    BaseContainer copy(original);
    ApplicationOutput(copy.GetString(100));
    ApplicationOutput(copy.GetString(200));
    // Assignment
    BaseContainer assignment = original;
    ApplicationOutput(assignment.GetString(100));
    ApplicationOutput(assignment.GetString(200));
    NONE
    Definition: asset_browser.h:1
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204
    #define DeleteObj(obj)
    Definition: newobj.h:159
    Note
    To merge containers see BaseContainer::MergeContainer() in chapter Functionality.

    Data

    ID

    A BaseContainer can have an ID. This ID can be used to identify the container.

    • BaseContainer::GetId(): Returns the ID of the container.
    • BaseContainer::SetId(): Sets the ID of the container.
    // This example shows how GetId() is used to identify the message sent to GeDialog::Message().
    Int32 Message(const BaseContainer& msg, BaseContainer& result)
    {
    switch (msg.GetId())
    {
    {
    // interaction start; if the value is changed create an undo
    _interactStart = true;
    break;
    }
    {
    // interaction end, if an undo was created, end it
    if (_undoStarted)
    {
    BaseDocument* const doc = GetActiveDocument();
    doc->EndUndo();
    _undoStarted = false;
    }
    _interactStart = false;
    break;
    }
    }
    return SUPER::Message(msg, result);
    }
    PyObject PyObject * result
    Definition: abstract.h:43
    @ BFM_INTERACTSTART
    Definition: gui.h:926
    @ BFM_INTERACTEND
    Sent when user interaction ends.
    Definition: gui.h:945
    BaseDocument * GetActiveDocument()
    const char const char * msg
    Definition: object.h:438

    Access

    A BaseContainer stores its data using GeData objects. It is possible to access these GeData objects or the stored values directly using typed access functions. It is recommended to prefer the typed access functions.

    A copy of a GeData element can be obtained with:

    • BaseContainer::GetParameter(): Gets the GeData for the given DescID.
    • BaseContainer::SetParameter(): Sets the GeData for the given DescID.
    Note
    The DescLevel::id property is used as the actual ID.
    // This example stores some data in
    // the BaseContainer using SetParameter().
    BaseContainer bc;
    bc.SetParameter(ConstDescID(DescLevel(100)), GeData { "foobar" });
    GeData data;
    bc.GetParameter(ConstDescID(DescLevel(100)), data);
    ApplicationOutput(data.GetString());
    #define ConstDescID(...)
    Definition: lib_description.h:596

    The GeData elements are also accessible via:

    • BaseContainer::GetData(): Returns the GeData element for the given ID.
    • BaseContainer::SetData(): Sets the GeData element for the given ID.
    // This example stores some data in the
    // BaseContainer using a GeData object.
    BaseContainer bc;
    bc.SetData(100, GeData { "foobar" });
    GeData data = bc.GetData(100);
    ApplicationOutput(data.GetString());

    For fast access read-only pointers to the GeData elements are accessible:

    • BaseContainer::GetDataPointer(): Returns a read-only pointer to the GeData element for the given ID.
    • BaseContainer::GetDataPointers(): Sets an array of read-only GeData pointers for the given array of IDs.
    // This example accesses the data stored
    // in the BaseContainer using data pointers.
    BaseContainer bc;
    bc.SetData(100, GeData { "foo" });
    bc.SetData(200, GeData { "bar" });
    const Int count = 2;
    const GeData* data[count];
    Int32 ids[] = { 100, 200 };
    bc.GetDataPointers(ids, count, data);
    if (data[0])
    ApplicationOutput(data[0]->GetString());
    if (data[1])
    ApplicationOutput(data[1]->GetString());
    Py_ssize_t count
    Definition: abstract.h:640
    maxon::Int Int
    Definition: ge_sys_math.h:55

    A GeData element is also accessible via its index in the BaseContainer:

    • BaseContainer::GetIndexData(): Returns a pointer to the GeData element for the given index.
    // This example accesses the data stored in the
    // BaseContainer using the element index.
    BaseContainer bc;
    bc.SetData(100, GeData { "foo" });
    bc.SetData(200, GeData { "bar" });
    const GeData* const first = bc.GetIndexData(0);
    if (first != nullptr)
    ApplicationOutput(first->GetString());
    const GeData* const second = bc.GetIndexData(1);
    if (second != nullptr)
    ApplicationOutput(second->GetString());

    New GeData elements can be added to the BaseContainer:

    • BaseContainer::InsData(): Inserts a GeData element into the BaseContainer with the given ID.
    • BaseContainer::InsDataAfter(): Inserts a GeData element into the BaseContainer with the given ID after another element.
    // This example inserts some data into the
    // BaseContainer after the first element.
    BaseContainer bc;
    bc.SetData(100, "foo");
    bc.SetData(200, "foobar");
    const GeData* const data = bc.GetIndexData(0);
    bc.InsDataAfter(150, String("bar"), data);

    To access the values of primitive data types, these access functions are available:

    • BaseContainer::GetBool(): Returns the ::Bool value stored at the given ID.
    • BaseContainer::SetBool(): Sets the ::Bool value stored at the given ID.
    • BaseContainer::GetInt32(): Returns the ::Int32 value stored at the given ID.
    • BaseContainer::SetInt32(): Sets the ::Int32 value stored at the given ID.
    • BaseContainer::GetUInt32(): Returns the ::UInt32 value stored at the given ID.
    • BaseContainer::SetUInt32(): Sets the ::UInt32 value stored at the given ID.
    • BaseContainer::GetInt64(): Returns the ::Int64 value stored at the given ID.
    • BaseContainer::SetInt64(): Sets the ::Int64 value stored at the given ID.
    • BaseContainer::GetUInt64(): Returns the ::UInt64 value stored at the given ID.
    • BaseContainer::SetUInt64(): Sets the ::UInt64 value stored at the given ID.
    • BaseContainer::GetFloat(): Returns the ::Float value stored at the given ID.
    • BaseContainer::SetFloat(): Sets the ::Float value stored at the given ID.

    See also Primitive Data Types Manual (Cinema API).

    A BaseContainer can store a void pointer.

    • BaseContainer::GetVoid(): Returns the void pointer stored at the given ID.
    • BaseContainer::SetVoid(): Sets the void pointer stored at the given ID.
    Note
    This should not be used to store a reference to a C4DAtom based element; instead a BaseLink should be used.
    // This example stores a void pointer
    // in the BaseContainer object.
    BaseContainer bc;
    bc.SetVoid(100, &object);
    // ...
    SomeObject* const obj = static_cast<SomeObject*>(bc.GetVoid(100));
    PyObject * obj
    Definition: complexobject.h:60

    A BaseContainer can store raw memory:

    • BaseContainer::GetMemoryAndRelease(): Returns a pointer to the stored memory at the given ID and hands over the ownership.
    • BaseContainer::GetMemory(): Returns a pointer to the stored memory at the given ID.
    • BaseContainer::SetMemory(): Stores the raw memory at the given ID.
    // This example stores a BaseArray as raw memory. (in that case an array of Vectors)
    // Calculates the size of the memory
    maxon::Int size = myArray.GetCount() * SIZEOF(maxon::Vector);
    if (size == 0)
    {
    bc.SetMemory(uniqueID, nullptr, 0);
    }
    else
    {
    // Retrieves the memory pointer using Disconnect. (so the memory will not be freed twice)
    void* pArray = myArray.Disconnect().Begin().GetPtr();
    if (pArray == nullptr)
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    // Sets the memory in the BaseContainer
    bc.SetMemory(uniqueID, pArray, size);
    }
    Py_ssize_t size
    Definition: bytesobject.h:86
    Int64 Int
    signed 32/64 bit int, size depends on the platform
    Definition: apibase.h:187
    #define SIZEOF(...)
    Calculates the size of a datatype or element.
    Definition: apibasemath.h:214
    // This Example reads a BaseArray stored as raw memory.
    // Creates an array
    // Creates a block to retrieves the memory from the block.
    // Retrieves the memory, use GetMemoryAndRelease to release the pointer or the memory will be freed twice)
    void* memFromContainer = bc.GetMemoryAndRelease((Int32)uniqueID, size);
    if (memFromContainer != nullptr && size > 0)
    {
    // Calculates the number of elements for vectors
    maxon::Vector* myMem = static_cast<maxon::Vector*>(memFromContainer);
    if (myMem == nullptr)
    return maxon::NullptrError(MAXON_SOURCE_LOCATION);
    // Fills the block with the memory.
    myblock.Set(myMem, size);
    // Connects the array with the block.
    myOtherArray.Connect(myblock, size);
    }
    // Prints the value of the array.
    for (auto& value : myOtherArray)
    ApplicationOutput("Value is @", value);
    PyObject * value
    Definition: abstract.h:715
    Definition: basearray.h:414
    MAXON_ATTRIBUTE_FORCE_INLINE void Connect(const Block< T > &block, Int capacity=0)
    Sets the array's memory buffer to the given block. The current content of this array is freed before.
    Definition: basearray.h:1581
    Definition: block.h:426
    void Set(T *ptr, Int size, Int stride=(STRIDED &&GENERIC) ? -1 :SIZEOF(StrideType))
    Definition: block.h:553

    A BaseContainer offers also access functions for mathematical data types:

    • BaseContainer::GetVector(): Returns the ::Vector stored at the given ID.
    • BaseContainer::SetVector(): Sets the ::Vector stored at the given ID.
    • BaseContainer::GetMatrix(): Returns the ::Matrix stored at the given ID.
    • BaseContainer::SetMatrix(): Sets the ::Matrix stored at the given ID.

    See also Vector Manual (Cinema API) and Matrix Manual (Cinema API).

    A BaseContainer offers further access functions for typical Cinema 4D data types:

    • BaseContainer::GetString(): Returns the String stored at the given ID.
    • BaseContainer::SetString(): Sets the String stored at the given Id.
    • BaseContainer::GetFilename(): Returns the Filename stored at the given ID.
    • BaseContainer::SetFilename(): Sets the Filename stored at the given ID.

    See also String Manual (Cinema API) and Filename Manual.

    • BaseContainer::GetUuid(): Returns the C4DUuid stored at the given ID.
    • BaseContainer::SetUuid(): Sets the C4DUuid stored at the given ID.
    • BaseContainer::GetTime(): Returns the BaseTime stored at the given ID.
    • BaseContainer::SetTime(): Sets the BaseTime stored at the given ID.

    See also BaseTime Manual.

    A BaseContainer also offers special functions to store and handle BaseLink objects:

    • BaseContainer::GetLink(): Returns the BaseList2D referenced in the BaseLink stored at the given ID.
    • BaseContainer::GetObjectLink(): Returns the BaseObject referenced in the BaseLink stored at the given ID.
    • BaseContainer::GetMaterialLink(): Returns the BaseMaterial referenced in the BaseLink stored at the given ID.
    • BaseContainer::GetBaseLink(): Returns the BaseLink stored at the given ID.
    • BaseContainer::SetLink(): Stores a BaseLink object referencing to the given C4DAtomGoal at the given ID.

    See also BaseLink Manual.

    // store the current selection in the BaseContainer
    BaseContainer bc;
    bc.SetLink(100, doc->GetActiveMaterial());
    bc.SetLink(200, doc->GetActiveObject());
    bc.SetLink(300, doc->GetActiveTag());
    // ...
    // get the material
    BaseMaterial* const mat = bc.GetMaterialLink(100, doc);
    if (mat)
    ApplicationOutput(mat->GetName());
    // get the object
    BaseObject* const obj = bc.GetObjectLink(200, doc);
    if (obj)
    ApplicationOutput(obj->GetName());
    // get tag
    BaseList2D* const link = bc.GetLink(300, doc);
    if (link)
    ApplicationOutput(link->GetName());

    A BaseContainer object can also store further sub-containers:

    • BaseContainer::GetContainer(): Returns the BaseContainer stored at the given ID.
    • BaseContainer::GetContainerInstance(): Returns a pointer to the BaseContainer stored at the given ID.
    • BaseContainer::SetContainer(): Sets the BaseContainer stored at the given ID.
    // This example stores a sub-container
    // in the BaseContainer object.
    BaseContainer subcontainer;
    subcontainer.SetString(100, "foobar"_s);
    BaseContainer bc;
    bc.SetContainer(100, subcontainer);
    // ...
    BaseContainer sub = bc.GetContainer(100);
    ApplicationOutput(sub.GetString(100));

    A BaseContainer can also store custom data types. To set the value of the custom data type a GeData object is needed.

    • BaseContainer::GetCustomDataType(): Returns the custom data type stored at the given ID.
    // This example gets the current time and saves is as DateTimeData in the BaseContainer.
    // Then the DateTimeData is received from that BaseContainer.
    DateTime time;
    AutoAlloc<DateTimeData> date;
    if (date == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    date->SetDateTime(time);
    GeData data;
    data.SetCustomDataType<DateTimeData>(*date);
    BaseContainer bc;
    bc.SetData(100, data);
    // ...
    const DateTimeData* const dateTimeData = bc.GetCustomDataType<DateTimeData>(100);
    if (dateTimeData)
    {
    const DateTime dt = dateTimeData->GetDateTime();
    String result;
    result += String::IntToString(dt.year) + ":";
    result += String::IntToString(dt.month) + ":";
    result += String::IntToString(dt.day) + " - ";
    result += String::IntToString(dt.hour) + ":";
    result += String::IntToString(dt.minute) + ":";
    result += String::IntToString(dt.second);
    // print output
    }
    void GetDateTimeNow(DateTime &t)

    These functions can be used to limit the values of a ::Vector or ::Float value inside a BaseContaier:

    • CutVector(): Limits the values of the components of the vector with the given ID in the given BaseContainer.
    • CutReal(): Limits the float value with the given ID in the given BaseContainer.
    Note
    These functions simply apply ClampValue(), see also Mathematical Functions Manual (Cinema API).

    Index

    The elements stored within a BaseContainer are accessible through their index and their ID:

    • BaseContainer::FindIndex(): Returns the index of the given GeData element.
    • BaseContainer::GetIndexId(): Returns the ID of the element at the given index.

    See also BaseContainer::GetIndexData() above. To loop through values see also BrowseContainer.

    // This example loops through the values of the BaseContainer.
    Int32 i = 0;
    while (true)
    {
    const Int32 id = bc.GetIndexId(i++);
    if (id == NOTOK)
    break;
    else
    ApplicationOutput(bc.GetData(id).GetString());
    }
    Py_ssize_t i
    Definition: abstract.h:645
    #define NOTOK
    Definition: ge_sys_math.h:258

    Remove

    Elements can be removed from a BaseContainer:

    • BaseContainer::RemoveData(): Removes the element with the given ID.
    • BaseContainer::RemoveIndex(): Removes the element with the given index. See also Index.
    // This example removes some element from
    // the BaseContainer object.
    BaseContainer bc;
    bc.SetData(100, "foo");
    bc.SetData(200, "bar");
    // remove data entry 100
    if (bc.RemoveData(100))
    {
    GeData data = bc.GetData(100);
    // check if data has no type (data is not set)
    if (data.GetType() == DA_NIL)
    ApplicationOutput("Data removed"_s);
    }
    @ DA_NIL
    No value.
    Definition: c4d_gedata.h:37

    Functionality

    Several operations can be performed on a BaseContainer object.

    • BaseContainer::Sort(): Sorts the container entries by their ID.
      Note
      This function sorts the strings and remove any other value. (keeping the ID)
    • BaseContainer::MergeContainer(): Merges the BaseContainer with the given BaseContainer.
    • BaseContainer::FlushAll(): Clears all values in the BaseContainer.
    // This example merges the content of two
    // BaseContainer objects.
    BaseContainer bc;
    bc.SetData(100, "foo");
    bc.SetData(200, "bar");
    BaseContainer bc2;
    bc2.SetData(100, "100");
    bc2.SetData(300, "300");
    bc.MergeContainer(bc2);
    // this will result in the values
    // 100: "100"
    // 200: "bar"
    // 300: "300"

    Compare

    Two BaseContainer are identical if they have the same ID, the same number of entries and if the entries are also identical and in the same order.

    • BaseContainer::operator==: Returns true if the given BaseContainers are identical.
    • BaseContainer::operator !=: Returns true if the given BaseContainers are not identical.

    Detect Changes

    The dirty state of a BaseContainer changes incrementally when a value stored in the BaseContainer is changed.

    • BaseContainer::GetDirty(): Returns a number representing the dirty state.
    // This example checks the dirty state after a value was added and changed.
    BaseContainer bc;
    bc.SetData(100, "foo");
    UInt32 dirty = bc.GetDirty();
    ApplicationOutput("Dirty State: " + String::UIntToString(dirty));
    bc.SetData(100, "bar");
    dirty = bc.GetDirty();
    ApplicationOutput("Dirty State: " + String::UIntToString(dirty));
    maxon::UInt32 UInt32
    Definition: ge_sys_math.h:52

    BrowseContainer

    The BrowseContainer class can be used to browse through the values stored in a BaseContainer. See also Index.

    • BrowseContainer::BrowseContainer: the constructor defines which BaseContainer should be browsed.
    • BrowseContainer::Reset: Resets the browser to the construction state.
    • BrowseContainer::GetNext: Retrieves the next item in the container.
    // This example loops through all values of the given BaseContainer.
    Int32 id;
    GeData* dat = nullptr;
    // init BrowseContainer
    BrowseContainer browse(&bc);
    // loop through the values
    while (browse.GetNext(&id, &dat))
    {
    ApplicationOutput("id: " + String::IntToString(id));
    // check if the current data stores a String
    if (dat != nullptr)
    {
    if (dat->GetType() == DA_STRING)
    ApplicationOutput("value: " + dat->GetString());
    }
    }
    @ DA_STRING
    String.
    Definition: c4d_gedata.h:46

    Disc I/O

    A BaseContainer can be stored in a HyperFile.

    • HyperFile::ReadContainer(): Reads a BaseContainer from the HyperFile.
    • HyperFile::WriteContainer(): Writes a BaseContainer into the HyperFile.
    // This example stores a BaseContainer in a HyperFile on disc.
    AutoAlloc<HyperFile> hf;
    if (hf == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // open HyperFile to write
    {
    hf->WriteContainer(bc);
    hf->Close();
    }
    else
    {
    return maxon::IoError(MAXON_SOURCE_LOCATION, MaxonConvert(filename, MAXONCONVERTMODE::NONE), "Could not open file."_s);
    }
    PyCompilerFlags const char * filename
    Definition: ast.h:15
    WRITE
    Problems writing the file.
    Definition: ge_prepass.h:4
    ANY
    Definition: lib_substance.h:28
    maxon::Url MaxonConvert(const Filename &fn, MAXONCONVERTMODE convertMode)
    // This example reads a BaseContainer from a HyperFile on disc.
    AutoAlloc<HyperFile> hf;
    if (hf == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // open HyperFile to read
    if (hf->Open(123, filename, FILEOPEN::READ, FILEDIALOG::ANY))
    {
    BaseContainer bc;
    hf->ReadContainer(&bc, true);
    READ
    Problems reading the file.
    Definition: ge_prepass.h:3

    See also HyperFile Manual on BaseContainer.

    Further Reading