Open Search
    BaseDocument Manual

    About

    A BaseDocument represents a Cinema 4D scene with all its content. Cinema 4D can manage multiple open scenes simultaneously in a document list. It is possible to load, create, edit, render and save scenes in the background. A document contains:

    • Objects, materials and tags
    • Render settings
    • Document settings
    • Layers
    • Takes
    • Scene hooks
    • Undo actions
    Warning
    The active BaseDocument is the scene currently displayed in the editor. This active BaseDocument must not be edited from another thread than the main thread. Watch out for functions marked as "called in a thread context". If one needs to change the document from an asynchronous dialog, StopAllThreads() must be called before.

    BaseDocument objects are an instance of Tbasedocument.

    // This example shows how to create a virtual document, add a cube and render the document.
    // create document
    if (virtualDoc == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // create and add a new cube
    if (cube == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    virtualDoc->InsertObject(cube, nullptr, nullptr);
    // prepare bitmap
    if (bitmap == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    const Int32 width = 1280;
    const Int32 height = 720;
    const IMAGERESULT imageRes = bitmap->Init(width, height);
    if (imageRes != IMAGERESULT::OK)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // define render settings
    RenderData* const rdata = virtualDoc->GetActiveRenderData();
    if (rdata == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    BaseContainer renderSettings = rdata->GetDataInstanceRef();
    renderSettings.SetFloat(RDATA_XRES, width);
    renderSettings.SetFloat(RDATA_YRES, height);
    // render the document
    const RENDERRESULT res = RenderDocument(virtualDoc, renderSettings,
    nullptr, nullptr, bitmap, flags, nullptr);
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    // show result
    ShowBitmap(bitmap);
    PyCompilerFlags * flags
    Definition: ast.h:14
    RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
    Bool ShowBitmap(const Filename &fn)
    Definition: ge_autoptr.h:37
    Definition: c4d_basecontainer.h:48
    void SetFloat(Int32 id, Float r)
    Definition: c4d_basecontainer.h:615
    const BaseContainer & GetDataInstanceRef() const
    Definition: c4d_baselist.h:2517
    Definition: c4d_baseobject.h:248
    static BaseObject * Alloc(Int32 type)
    Definition: c4d_basedocument.h:143
    Py_UCS4 * res
    Definition: unicodeobject.h:1113
    @ RDATA_XRES
    Definition: drendersettings.h:152
    @ RDATA_YRES
    Definition: drendersettings.h:153
    maxon::Int32 Int32
    Definition: ge_sys_math.h:56
    IMAGERESULT
    Definition: ge_prepass.h:3920
    @ OK
    Image loaded/created.
    #define Ocube
    Cube.
    Definition: ge_prepass.h:1119
    RENDERFLAGS
    Definition: ge_prepass.h:4691
    @ NODOCUMENTCLONE
    Set to avoid an automatic clone of the scene sent to RenderDocument().
    RENDERRESULT
    Definition: ge_prepass.h:427
    @ OK
    Function was successful.
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:67
    unsigned long Py_ssize_t width
    Definition: pycore_traceback.h:88

    Access

    Cinema 4D can handle multiple open scenes in a document list:

    To navigate the document list GetNext() and GetPred() can be used:

    // This example iterates through all BaseDocuments in the document list.
    // The active BaseDocument is marked with a star.
    const BaseDocument* const activeDocument = GetActiveDocument();
    if (activeDocument == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    while (document != nullptr)
    {
    const GeMarker& docMarker = document->GetMarker();
    const GeMarker& activeDocMarker = activeDocument->GetMarker();
    // use GeMarker to compare identity of the BaseDocuments
    if (docMarker.IsEqual(activeDocMarker))
    {
    ApplicationOutput("Document: " + document->GetDocumentName().GetString() + " *");
    }
    else
    {
    ApplicationOutput("Document: " + document->GetDocumentName().GetString());
    }
    document = document->GetNext();
    }
    BaseDocument * GetActiveDocument()
    BaseDocument * GetFirstDocument()
    Definition: c4d_basedocument.h:497
    const BaseDocument * GetNext() const
    Definition: c4d_basedocument.h:533
    Filename GetDocumentName() const
    const GeMarker & GetMarker() const
    Definition: c4d_baselist.h:2590
    String GetString() const
    A unique marker that identifies an object.
    Definition: c4d_baselist.h:1445
    Bool IsEqual(const GeMarker &m) const
    Definition: c4d_baselist.h:1475
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204
    Note
    GetActiveDocument() and GetFirstDocument() only work in Cinema 4D versions that have an active document (not in Team Render Client, Command Line etc.). Use GetActiveDocument() only in combination with dialogs etc. but NEVER in NodeData based plugins or expressions.
    GeListNode::GetDocument() returns the BaseDocument that hosts a given entity. Use this method to access the document in a NodeData based plugin and all functions that are part of the execution or drawing pipeline. But never forget to check for nullptr, as there are situations where elements are not part of any document at all.

    Allocation/Deallocation

    A BaseDocument can be created with the usual tools:

    AutoAlloc can be used to handle a temporary document. A new document can be added to the document list:

    // This example creates a new BaseDocument and inserts it
    // into the list of documents.
    // create new document
    BaseDocument* const newDocument = BaseDocument::Alloc();
    if (newDocument == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // insert document as the active document.
    InsertBaseDocument(newDocument);
    SetActiveDocument(newDocument);
    // set document file name
    newDocument->SetDocumentName("new_document.c4d");
    // update Cinema
    void InsertBaseDocument(BaseDocument *doc)
    void SetActiveDocument(BaseDocument *doc)
    void EventAdd(EVENT eventflag=EVENT::NONE)
    void SetDocumentName(const Filename &fn)
    static BaseDocument * Alloc()
    Note
    BaseDocuments can also be created by loading Cinema 4D files. See Disc I/O below.

    Destroy

    A dynamically created BaseDocument should be destroyed with BaseDocument::Free(). To remove a BaseDocument from the document list use KillDocument().

    Copy

    BaseDocument is based on C4DAtom and can be cloned using C4DAtom::GetClone():

    // This example clones the given document add adds it to the document list.
    C4DAtom* const cloneAtom = doc->GetClone(COPYFLAGS::NONE, nullptr);
    BaseDocument* const cloneDocument = static_cast<BaseDocument*>(cloneAtom);
    if (cloneDocument == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    InsertBaseDocument(cloneDocument);
    SetActiveDocument(cloneDocument);
    cloneDocument->SetDocumentName("clone.c4d");
    Definition: c4d_baselist.h:1520
    @ NONE
    None.
    const char * doc
    Definition: pyerrors.h:226

    Preview Image

    When a scene is saved the current editor image is saved with the BaseDocument to create a thumbnail preview image.

    // This example shows the preview bitmap in the Picture Viewer.
    BaseBitmap* const bitmap = doc->GetDocPreviewBitmap();
    if (bitmap != nullptr)
    {
    ShowBitmap(bitmap);
    }
    Definition: c4d_basebitmap.h:435

    Properties

    Data

    Multiple settings are stored inside the BaseDocument. The different types of settings are defined in DOCUMENTSETTINGS, the parameter IDs in ddoc.h.

    // This example switches the statue of the "Use Generators" setting.
    const Bool useGenerators = data.GetBool(DOCUMENT_USEGENERATORS);
    // set new settings
    BaseContainer settings;
    settings.SetBool(DOCUMENT_USEGENERATORS, !useGenerators);
    doc->SetData(DOCUMENTSETTINGS::GENERAL, settings);
    void SetBool(Int32 id, Bool b)
    Definition: c4d_basecontainer.h:580
    Bool GetBool(Int32 id, Bool preset=false) const
    Definition: c4d_basecontainer.h:340
    @ DOCUMENT_USEGENERATORS
    Definition: ddoc.h:24
    maxon::Bool Bool
    Definition: ge_sys_math.h:51
    @ GENERAL
    General settings.

    and

    // This example accesses the document settings to set the "Author" setting.
    BaseContainer* const settings = doc->GetSettingsInstance((Int32)DOCUMENTSETTINGS::DOCUMENT);
    if (settings == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    settings->SetString(DOCUMENT_INFO_AUTHOR, "User"_s);
    void SetString(Int32 id, const maxon::String &s)
    Definition: c4d_basecontainer.h:651
    @ DOCUMENT_INFO_AUTHOR
    Definition: ddoc.h:48
    @ DOCUMENT
    Document settings.
    Note
    BaseDocument::GetSettingsInstance() won't work with DOCUMENTSETTINGS::GENERAL.

    Objects

    A BaseDocument hosts multiple BaseObject based scene objects. These objects are organized in an object tree.

    Note
    Using BaseDocument::InsertObject() will trigger the message MSG_DOCUMENTINFO_TYPE_OBJECT_INSERT.

    See also BaseObject Manual.

    // This example searches for an object named "Cube".
    // If it cannot be found a new cube with that name will be created.
    BaseObject* const object = doc->SearchObject("Cube"_s);
    if (object != nullptr)
    {
    ApplicationOutput("found \"Cube\""_s);
    return maxon::OK;
    }
    BaseObject* const cubeObject = BaseObject::Alloc(Ocube);
    if (cubeObject == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    cubeObject->SetName("Cube"_s);
    doc->InsertObject(cubeObject, nullptr, nullptr);
    void SetName(const maxon::String &name, Bool setDirty=true)
    Definition: c4d_baselist.h:2549
    return OK
    Definition: apibase.h:2735

    In some cases multiple instances of a certain object class can be inserted into the scene but only one instance will be used (e.g. the Sky object). This is typically the "highest" instance.

    // This example searches for the highest (and thus used) stage object
    BaseObject* const stageObject = doc->GetHighest(Ostage, false);
    if (stageObject == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    ApplicationOutput("Found stage object \"" + stageObject->GetName() + "\"");
    String GetName() const
    Definition: c4d_baselist.h:2543
    #define Ostage
    Stage.
    Definition: ge_prepass.h:1076

    Materials

    A BaseDocument hosts multiple BaseMaterial based materials. These materials are stored in a list and can be applied to objects in the scene.

    See also BaseMaterial Manual

    // This example searches for a material with the given name.
    // If the material cannot be found, a new material with that
    // name will be created and inserted into the document.
    // search material
    BaseMaterial* const material = doc->SearchMaterial("Green"_s);
    if (material)
    {
    ApplicationOutput("Found \"Green\""_s);
    return maxon::OK;
    }
    // create material
    BaseMaterial* const greenMaterial = BaseMaterial::Alloc(Mmaterial);
    if (greenMaterial == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    greenMaterial->SetName("Green"_s);
    // insert material into the document
    doc->InsertMaterial(greenMaterial);
    Definition: c4d_basematerial.h:28
    static BaseMaterial * Alloc(Int32 type)
    #define Mmaterial
    Standard material.
    Definition: ge_prepass.h:1008

    Selections

    Inside a scene multiple objects, materials or tags can be selected.

    // This example prints the name and type of all selected scene elements.
    if (selection == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    doc->GetSelection(selection);
    const Int32 cnt = selection->GetCount();
    if (cnt == 0)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    for (Int32 i = 0; i < cnt; ++i)
    {
    C4DAtom* const element = selection->GetIndex(i);
    // check if the given C4DAtom is a BaseList2D element
    const Bool validElement = element != nullptr;
    if (validElement && element->IsInstanceOf(Tbaselist2d))
    {
    BaseList2D* baseList2D = static_cast<BaseList2D*>(element);
    ApplicationOutput(baseList2D->GetName() + " (" + baseList2D->GetTypeName() + ")");
    }
    else
    {
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    }
    }
    Py_ssize_t i
    Definition: abstract.h:645
    Definition: c4d_baselist.h:2376
    String GetTypeName() const
    #define Tbaselist2d
    2D list.
    Definition: ge_prepass.h:996
    PyObject * element
    Definition: unicodeobject.h:1016

    Object selections can be managed separately:

    Note
    To get the position of the anchor of an object multi-selection one can use BaseDocument::GetHelperAxis().
    To correctly add objects to the selection of active objects with BaseDocument::SetActiveObject() one must update internal caches by calling BaseDocument::GetActiveObject() after an object was added to the selection.
    // This example gets all selected null objects.
    // For each null object a cube is created at its position.
    // The new cubes will be selected instead of the original nulls.
    // get all selected null objects
    if (selection == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    doc->GetActiveObjectsFilter(selection, true, Onull, NOTOK);
    const Int32 cnt = selection->GetCount();
    if (cnt == 0)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // clear object selection
    doc->SetActiveObject(nullptr);
    for (Int32 i = 0; i < cnt; ++i)
    {
    C4DAtom* element = selection->GetIndex(i);
    const BaseObject* const nullobject = static_cast<BaseObject*>(element);
    if (nullobject == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // create a cube
    if (cube == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    const Matrix nullMg = nullobject->GetMg();
    cube->SetMg(nullMg);
    doc->InsertObject(cube, nullptr, nullptr);
    doc->SetActiveObject(cube, SELECTION_ADD);
    }
    void SetMg(const Matrix &m)
    Definition: c4d_baseobject.h:516
    Matrix GetMg() const
    Definition: c4d_baseobject.h:510
    #define NOTOK
    Definition: ge_sys_math.h:263
    #define Onull
    Null.
    Definition: ge_prepass.h:1078
    #define SELECTION_ADD
    Adds to the current selection.
    Definition: c4d_basedocument.h:389

    Material selections can be managed separately, too:

    // This example gets the material that is assigned to the given object.
    // If a material is found, it will be selected.
    // get texture tag
    BaseTag* const tag = object->GetTag(Ttexture);
    if (tag == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // get material
    TextureTag* const ttag = static_cast<TextureTag*>(tag);
    BaseMaterial* const material = ttag->GetMaterial();
    // set active material
    if (material != nullptr)
    doc->SetActiveMaterial(material, SELECTION_NEW);
    Definition: c4d_basetag.h:52
    Definition: c4d_basetag.h:704
    BaseMaterial * GetMaterial(Bool ignoredoc=false) const
    #define SELECTION_NEW
    Starts a new selection.
    Definition: c4d_basedocument.h:388
    #define Ttexture
    Texture - TextureTag.
    Definition: ge_prepass.h:1411

    Finally tag selections can be managed:

    // This example loops through all selected tags.
    // If a tag is a Texture Tag, the given material is applied.
    // get all selected tags
    if (tags == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    doc->GetActiveTags(tags);
    const Int32 cnt = tags->GetCount();
    if (cnt == 0)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    for (Int32 i = 0; i < cnt; i++)
    {
    C4DAtom* const tag = tags->GetIndex(i);
    if (tag == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // check if texture tag
    if (tag->GetType() == Ttexture)
    {
    // set material
    TextureTag* ttag = static_cast<TextureTag*>(tag);
    ttag->SetMaterial(material);
    }
    }
    Int32 GetType() const
    Definition: c4d_baselist.h:1536
    void SetMaterial(BaseMaterial *mat)

    RenderData

    RenderData objects represent the render settings stored in a document. They allow access to the actual settings, multipass objects and post effects.

    See also RenderData Manual.

    // This example adds a new RenderData to the document and set this RenderData as the active one.
    RenderData* const renderData = RenderData::Alloc();
    if (renderData == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    renderData->SetName("Preview Render Settings"_s);
    doc->InsertRenderDataLast(renderData);
    doc->SetActiveRenderData(renderData);
    static RenderData * Alloc()

    Scene Hooks

    Scene hooks are used to add additional data to the document or to influence the execution pipeline. These scene hooks are stored in the document:

    // This example accesses the Dynamics scene hook to disable Dynamics globally.
    // gets the dynamics scene hook
    BaseSceneHook* const dynamicsHook = doc->FindSceneHook(180000100);
    if (dynamicsHook == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    BaseContainer& bc = dynamicsHook->GetDataInstanceRef();
    bc.SetBool(WORLD_ENABLED, false);
    Definition: c4d_basedocument.h:52
    @ WORLD_ENABLED
    Definition: dynworldobject.h:6

    Layers

    Layers are used to organize a document. A layer is represented by a LayerObject and these LayerObject objects are organized in a tree:

    See also Layer Manual.

    // This example gets the layer root object to access the first layer.
    GeListHead* const layers = doc->GetLayerObjectRoot();
    if (layers == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    LayerObject* const layer = static_cast<LayerObject*>(layers->GetFirst());
    if (layer != nullptr)
    ApplicationOutput("First Layer: " + layer->GetName());
    Definition: c4d_baselist.h:2208
    GeListNode * GetFirst()
    Definition: c4d_baselist.h:2265
    Definition: c4d_basedocument.h:252

    Takes

    Takes allow to handle multiple versions of a scene within the same document. The takes of a document are stored in a TakeData object:

    // This example simply creates a new take and makes it the current one.
    TakeData* const takeData = doc->GetTakeData();
    if (takeData == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    BaseTake* const newTake = takeData->AddTake("This is a new take", nullptr, nullptr);
    if (newTake == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    takeData->SetCurrentTake(newTake);
    Definition: lib_takesystem.h:335
    Definition: lib_takesystem.h:589
    BaseTake * AddTake(const String &name, BaseTake *parent, BaseTake *cloneFrom)
    Bool SetCurrentTake(BaseTake *take)

    See Take System Overview

    Changed Mode

    The change status of a document indicates that the scene was changed after the last time it was saved. The status is displayed with a little star (*) in the application title bar.

    // This example closes and frees the currently active document only if it is not "dirty".
    if (activeDoc == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // check dirty state of the document
    if (activeDoc->GetChanged() == false)
    KillDocument(activeDoc);
    void KillDocument(BaseDocument *&doc)
    Bool GetChanged()

    Document Name and Path

    A document is presented in the application using its filename. Because of this the name of the document cannot be obtained with BaseList2D::GetName() that returns a String and not a Filename.

    // This example checks the suffix of the current document name.
    const Filename docName = doc->GetDocumentName();
    const String suffix = docName.GetSuffix();
    // check if the suffix is defined
    if (suffix.IsPopulated())
    {
    if (suffix == "c4d")
    ApplicationOutput("Cinema 4D File"_s);
    else
    ApplicationOutput("Filetype: " + suffix);
    }
    else
    {
    ApplicationOutput("unsaved document"_s);
    }
    Manages file and path names.
    Definition: c4d_file.h:94
    String GetSuffix() const
    Definition: c4d_string.h:41
    Bool IsPopulated() const
    Definition: string.h:1451

    Level of Detail

    The level of detail defines how detailed certain objects are displayed in the editor. This is typically used in custom ObjectData based generators.

    // This example sets the LOD to the level set in the current render settings.
    // check if the document uses render LOD in the editor
    if (doc->GetRenderLod() == false)
    {
    RenderData* const renderData = doc->GetActiveRenderData();
    if (renderData == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    const BaseContainer bc = renderData->GetDataInstanceRef();
    const Float lod = bc.GetFloat(RDATA_LOD);
    // set new LOD
    doc->SetLOD(lod);
    }
    Float GetFloat(Int32 id, Float preset=0.0) const
    Definition: c4d_basecontainer.h:380
    @ RDATA_LOD
    Definition: drendersettings.h:61
    maxon::Float Float
    Definition: ge_sys_math.h:62
    Note
    The LOD buttons in the editor represent the values 25%, 50% and 100%.

    Time

    The current timeline position of a document and the timeline size is defined using BaseTime objects.

    Note
    Setting the current time will not animate the document. See paragraph Animate below.

    Current time:

    // This example jumps one second ahead and updates the document.
    const BaseTime now = doc->GetTime();
    const BaseTime target = now + BaseTime(1.0);
    doc->SetTime(target);
    // animate document
    doc->ExecutePasses(nullptr, true, true, true, BUILDFLAGS::NONE);
    Definition: c4d_basetime.h:25
    @ NONE
    None.

    Framerate:

    Note
    The framerate defined in the render settings is independent from the document framerate.
    In the viewport, and for a render in the viewport, it will return the project's setting FrameRate.
    Rendering elsewhere, it will return the RenderData FrameRate setting.
    // This example synchronizes the document framerate with the render framerate.
    RenderData* const renderData = doc->GetActiveRenderData();
    if (renderData == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    const BaseContainer bc = renderData->GetDataInstanceRef();
    const Int32 fps = bc.GetInt32(RDATA_FRAMERATE);
    doc->SetFps(fps);
    Int32 GetInt32(Int32 id, Int32 preset=0) const
    Definition: c4d_basecontainer.h:348
    @ RDATA_FRAMERATE
    Definition: drendersettings.h:171

    Timeline dimensions:

    Used Time:

    Loop Preview:

    // This example moves the timeline loop to the start of the timeline.
    const BaseTime minTime = doc->GetMinTime();
    // current loop duration
    const BaseTime loopDuration = doc->GetLoopMaxTime() - doc->GetLoopMinTime();
    // move loop to the start
    doc->SetLoopMinTime(minTime);
    doc->SetLoopMaxTime(minTime + loopDuration);

    Mode

    A document can be in different modes defining which elements should be edited (objects, points, edges, etc.).

    // This example sets the document mode based on the currently active selection tag.
    BaseTag* const tag = doc->GetActiveTag();
    if (tag == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // check tag type
    switch (tag->GetType())
    {
    case Tpointselection: doc->SetMode(Mpoints); break;
    case Tpolygonselection: doc->SetMode(Mpolygons); break;
    case Tedgeselection: doc->SetMode(Medges); break;
    }
    @ Medges
    Edge edit mode.
    Definition: c4d_basedocument.h:1922
    @ Mpolygons
    Polygon edit mode.
    Definition: c4d_basedocument.h:1923
    @ Mpoints
    Point edit mode.
    Definition: c4d_basedocument.h:1921
    #define Tpointselection
    Point selection - SelectionTag.
    Definition: ge_prepass.h:1423
    #define Tedgeselection
    Edge selection - SelectionTag. The edges are encodes like this: (4*poly)+edge, where edge goes from 0...
    Definition: ge_prepass.h:1440
    #define Tpolygonselection
    Polygon selection - SelectionTag.
    Definition: ge_prepass.h:1422

    Active Tool

    The currently active tool is stored in the document.

    // This example switches the mode and enables and configures the "Knife" tool.
    if (tool == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    doc->SetMode(Mpoints);
    BaseContainer * GetToolData(BaseDocument *doc, Int32 pluginid, Bool create=true)
    #define ID_MODELING_KNIFE_LINE
    Definition: modelingids.h:43
    @ MDATA_KNIFELINE_ANGLE_CONSTRAINT
    Definition: toolknifeline.h:16
    Note
    To edit the settings of the Move/Scale/Rotate tools the actual plugin instance has to be accessed with FindPlugin().

    Axis and Plane

    The helper axis represents the position of the handles used to move a multi-selection.

    // This example creates a null object at the position of the helper axis.
    // The currently selected objects (stored in "selection") are placed under that null object.
    // check if model mode
    if (doc->GetMode() != Mmodel)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // get helper object and matrix
    const BaseObject* const helperAxis = doc->GetHelperAxis();
    if (helperAxis == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    const Matrix matrix = helperAxis->GetMg();
    // create null object
    BaseObject* const nullObject = BaseObject::Alloc(Onull);
    if (nullObject == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    doc->InsertObject(nullObject, nullptr, nullptr);
    nullObject->SetMg(matrix);
    // make selected object child of the new null
    for (Int32 i = 0; i < objectCnt; ++i)
    {
    C4DAtom* element = selection->GetIndex(i);
    BaseObject* const baseObject = static_cast<BaseObject*>(element);
    if (baseObject == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    const Matrix position = baseObject->GetMg();
    baseObject->Remove();
    doc->InsertObject(baseObject, nullObject, nullptr);
    baseObject->SetMg(position);
    }
    void Remove()
    Definition: c4d_baselist.h:2066
    @ Mmodel
    Model mode.
    Definition: c4d_basedocument.h:1926

    Editor Windows

    An editor window is represented by a BaseDraw object. Such a BaseDraw object allows access to the currently used camera. The render view is the editor window used to define the camera that will be used while rendering the final image.

    See also BaseView / BaseDraw Manual.

    // This example accesses the active BaseDraw to get its camera.
    // Then it moves the active object into the view of that camera.
    BaseDraw* const baseDraw = doc->GetActiveBaseDraw();
    if (baseDraw == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    BaseObject* const cameraObject = baseDraw->GetEditorCamera();
    // move active object into the camera view
    const Matrix cameraMatrix = cameraObject->GetMg();
    Matrix targetPosition = activeObject->GetMg();
    targetPosition.off = cameraMatrix.off + (900.0 * cameraMatrix.sqmat.v3);
    activeObject->SetMg(targetPosition);
    Definition: c4d_basedraw.h:755
    BaseObject * GetEditorCamera()
    Definition: c4d_basedraw.h:864
    V off
    The translation vector.
    Definition: matrix.h:263
    SqrMat3< V > sqmat
    The 3×3 matrix for rotation, scale and shear.
    Definition: matrix.h:266

    Net Context

    If the document is currently handled inside a Team Render context can be checked using the net render context:

    // This example checks if the current context is a Team Render context.
    // If so, the error message will be printed just to the console, not displayed as a message box.
    const BaseDocument* const doc = op->GetDocument();
    NetRenderDocumentContext* const context = doc->GetNetRenderDocumentContext();
    if (context)
    ApplicationOutput("Some Error occured!"_s);
    else
    MessageDialog("Some Error occured!"_s);
    void MessageDialog(const maxon::String &str)
    void * context
    Definition: pycapsule.h:49
    PyObject * op
    Definition: object.h:520
    Definition: lib_net.h:829

    Functionality

    Animate

    Scene elements can be animated by setting keyframes with specific values at a specific time. The BaseDocument class offers functions to create such keyframes:

    // This example creates automatically keys for the given object if "Auto Key" is enabled.
    BaseObject* undoObject = static_cast<BaseObject*>(cubeObject->GetClone(COPYFLAGS::NONE, nullptr));
    if (undoObject == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // edit the object
    // create auto keys if "Auto Key" is enabled.
    doc->AutoKey(undoObject, cubeObject, true, true, true, true, true, true);
    BaseObject::Free(undoObject);
    static void Free(BaseObject *&bl)
    Bool SetParameter(const DescID &id, const GeData &t_data, DESCFLAGS_SET flags)
    C4DAtom * GetClone(COPYFLAGS flags, AliasTrans *trn) const
    Definition: c4d_baselist.h:1605
    #define ConstDescID(...)
    Definition: lib_description.h:594
    @ PRIM_CUBE_SUBY
    Definition: ocube.h:9
    @ PRIM_CUBE_SUBX
    Definition: ocube.h:8
    @ PRIM_CUBE_SUBZ
    Definition: ocube.h:10
    Represents a level within a DescID.
    Definition: lib_description.h:298

    See also Animation Tracks.

    To apply keyframe animation, expressions, generators and deformers the document has to be animated.

    // This example executes the document at different frames
    // and prints the position of the "Cube" object.
    // save current frame
    const BaseTime originalTime = doc->GetTime();
    for (Int32 i = 0; i < 30; ++i)
    {
    BaseTime time(i, doc->GetFps());
    doc->SetTime(time);
    doc->ExecutePasses(nullptr, true, true, true, BUILDFLAGS::INTERNALRENDERER);
    BaseObject* const cube = doc->SearchObject("Cube"_s);
    if (cube)
    {
    const Vector position = cube->GetMg().off;
    ApplicationOutput("Cube Position: " + String::VectorToString(position));
    }
    }
    // reset frame
    doc->SetTime(originalTime);
    static String VectorToString(const Vector32 &v, Int32 nnk=-1)
    Definition: c4d_string.h:573
    @ INTERNALRENDERER
    Rendering in the editor.

    When a new keyframe is created a default template is used. This template can be edited:

    // This example changes the default key of the document.
    if (key == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    Bool overdub;
    doc->GetDefaultKey(key, overdub);
    // new keys should use linear interpolation
    key->SetInterpolation(nullptr, CINTERPOLATION::LINEAR);
    doc->SetDefaultKey(key, overdub);
    PyObject * key
    Definition: abstract.h:289
    @ LINEAR
    Linear.

    The result of simulations is often iterative: The current frame depends on the results of previous calculations. To calculate the state of a particle simulation at a certain frame all frames before that have to be calculated:

    // This example reads the emitter end time from the given particle object.
    // The document time is set to this frame and SetRewind() is called to animate
    // all frame before that frame.
    GeData data;
    // access PARTICLEOBJECT_STOP parameter
    const DescID particleStopID = ConstDescID(DescLevel(PARTICLEOBJECT_STOP));
    if (particleEmitter->GetParameter(particleStopID, data, DESCFLAGS_GET::NONE) == false)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    const BaseTime endTime = data.GetTime();
    doc->SetTime(endTime);
    doc->SetRewind();
    Definition: lib_description.h:355
    Definition: c4d_gedata.h:83
    const BaseTime & GetTime() const
    Definition: c4d_gedata.h:516
    @ PARTICLEOBJECT_STOP
    Definition: oparticle.h:29

    Undo

    The undo system of Cinema 4D allows to store operations in undo actions that can be executed to undo and redo user interaction.

    See also Undo System Manual.

    // This example creates a cube object and adds it to the document with an undo step.
    if (cube == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    doc->StartUndo();
    doc->InsertObject(cube, nullptr, nullptr);
    doc->AddUndo(UNDOTYPE::NEWOBJ, cube);
    doc->EndUndo();
    @ NEWOBJ
    A new object, material, tag, or other classic API node instance has been inserted into the document....

    Undo actions can be executed:

    Pick Session

    A pick session can be used to select multiple objects.

    See PickSessionDataStruct.

    Send Messages

    Convert and Export

    The objects of a BaseDocument can be converted to polygon objects and associated sounds and textures can be collected:

    // This example prints the file paths of all textures of the given material selection.
    BaseContainer textures = doc->GetAllTextures(materials);
    BrowseContainer browse(&textures);
    Int32 id;
    GeData* data;
    // loop through elements of the BaseContainer
    while (browse.GetNext(&id, &data))
    {
    // check if the found element is a Filename
    if (data != nullptr)
    {
    if (data->GetType() == DA_FILENAME)
    ApplicationOutput("Texture: " + data->GetFilename().GetString());
    }
    }
    Definition: c4d_gedata.h:760
    const Filename & GetFilename() const
    Definition: c4d_gedata.h:510
    Int32 GetType() const
    Definition: c4d_gedata.h:436
    @ DA_FILENAME
    Filename.
    Definition: c4d_gedata.h:48
    • IsolateObjects(): Creates a new document that contains only copies of the given objects and their materials.
    // This example creates a new BaseDocument containing the objects from the given selection.
    // The new document is added to the document list and set as the active document.
    BaseDocument* const newDoc = IsolateObjects(doc, selection);
    if (newDoc == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    newDoc->SetDocumentName("isolated_objects.c4d");
    BaseDocument * IsolateObjects(BaseDocument *doc, const AtomArray &t_objects)

    Disc I/O

    A BaseDocument can be created by reading if from a file on disc. It is possible to load *.c4d files and supported import file formats.

    • LoadFile(): Used to load a file. A loaded Cinema 4D file will be automatically added to the document list.
      Note
      LoadFile() does not work with a Filename in Memory Read Mode, in this case use LoadDocument() instead.
      // Demonstrates the synchronous and asynchronous loading of a file with LoadFile().
      // Open a file selection dialog.
      "Select scene file to load (c4d, fbx, obj, etc)."_s);
      if (!res)
      return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Error in file selection process."_s);
      // Load the file synchronously, the operation is blocking.
      if (!LoadFile(filename, false))
      return maxon::IoError(MAXON_SOURCE_LOCATION,
      MaxonConvert(filename, MAXONCONVERTMODE::READ), "Could not read passed file."_s);
      // This section will be reached once the loading has finished. And since the FileSelect dialog was
      // restricted to scene files, a new document will have opened at this point which can be
      // retrieved and modified.
      BaseDocument* const activeDoc = GetActiveDocument();
      const Filename oldName = activeDoc->GetDocumentName();
      doc->SetDocumentName(Filename("New Document.abc"_s));
      "Loaded document with the file name '@', and changed the name to '@'.",
      oldName, activeDoc->GetDocumentName());
      // Load the same file asynchronously, the operation is non-blocking.
      if (!LoadFile(filename, true))
      return maxon::IoError(MAXON_SOURCE_LOCATION,
      MaxonConvert(filename, MAXONCONVERTMODE::NONE), "Could not read passed file."_s);
      // This section will be reached immediately after the second call of LoadFile(). There is no
      // guarantee that the file has finished loading at this point. While the active document is still
      // retrievable, modifying its attributes as for example changing its file name can result in
      // GUI errors or crashes. There are currently no means in the public API to determine if the
      // loading of a file loaded asynchronously with LoadFile() has finished or not.
      // GetActiveDocument() will still point to the (to be) loaded document, but it should not be
      // touched after invoking asynchronous loading.
      BaseDocument* const alsoActiveDocument = GetActiveDocument();
      ApplicationOutput("Loading '@' asynchronously.", filename);
      PyCompilerFlags const char * filename
      Definition: ast.h:15
      Bool LoadFile(const Filename &name, Bool allowAsync)
      maxon::Url MaxonConvert(const Filename &fn, MAXONCONVERTMODE convertMode)
      @ READ
      Check for file read operation.
      @ NONE
      No check if file exists under case-sensitive drives.
      @ LOAD
      Load dialog.
      @ SCENES
      3D scene files.
    • LoadDocument(): Will load a given Cinema 4D file into a BaseDocument object. Do not forget to set the scene filter flags.
    • MergeDocument(): Loads and merges the given Cinema 4D file into the given BaseDocument.
      // Demonstrates the progress callback functionailty of LoadDocument() and MergeDocument().
      // The example must run on the main thread as it will invoke GUI operations.
      return maxon::UnexpectedError(
      MAXON_SOURCE_LOCATION, "The example must run on the main thread."_s);
      // Open a file selection dialog.
      "Select scene file to load (c4d, fbx, obj, etc)."_s);
      if (!res)
      return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Error in file selection process."_s);
      // ProgressDelegate is an alias for maxon::Delegate<Bool(Float percent)> and conveys progress
      // information in percent for LoadDocument() and MergeDocument() operations with a callback
      // function, the delegate.
      // This feature can be used to display the progress of a loading operation or to cancel loading
      // operations when certain criteria are met. The delegate can either be a formally declared
      // delegate function or a lambda as shown here. The syntax and functionality of progress
      // delegation is the same for the methods LoadDocument and MergeDocument.
      // Define the elements of the scene file which should be loaded and the error string for the
      // loading operation.
      maxon::String errorString ("");
      // A helper variable used to throttle the console output of the delegate.
      maxon::Int32 lastProgress = 0;
      // Load the document, the last argument is the ProgressDelegate, for which here a lambda is
      // being passed.
      BaseDocument* const loadedDocument = LoadDocument(filename, filter, nullptr, &errorString,
      // The example delegate will set the status bar of Cinema 4D to the loading progress. Returning
      // #true in the delegate will continue the operation, #false will cancel it.
      [&lastProgress](Float percent) -> Bool
      {
      // The loading progress as an integer value in the interval [0, 100].
      const maxon::Int32 progress = static_cast<maxon::Int32>(percent * 100.0);
      // Set the main status bar of Cinema 4D to the current progress.
      StatusSetBar(progress);
      // When console output is required, the standard ApplicationOutput() cannot be used as its
      // execution will be delayed until LoadDocument() has finished. Its place can take
      // _ApplicationOutput in asynchronous drawing mode, but here the output must be throttled as
      // otherwise 1,000s or 10,000s of redraw calls will saturate Cinema 4D.
      if (progress > lastProgress)
      {
      FormatString("Progress: @%", progress), 0, nullptr);
      lastProgress = progress;
      }
      return true;
      });
      // Clear the status bar once the loading has finished.
      // The loading has failed.
      if (!loadedDocument)
      return maxon::IoError(
      // The loading has succeeded.
      ApplicationOutput("Finished loading the file '@'.", filename);
      BaseDocument * LoadDocument(const Filename &name, SCENEFILTER loadflags, BaseThread *thread, maxon::String *errorString=nullptr, const ProgressDelegate &progressDelegate=ProgressDelegate())
      void StatusSetBar(Int32 p)
      Bool GeIsMainThreadAndNoDrawThread()
      void StatusClear()
      Clears the status bar text.
      Definition: string.h:1237
      int32_t Int32
      32 bit signed integer datatype.
      Definition: apibase.h:190
      SCENEFILTER
      Definition: ge_prepass.h:298
      @ MERGESCENE
      Flag to inform a plugin that this is a merge operation, i.e. the document that is inserted to is an e...
      @ OBJECTS
      Load/save objects.
      @ MATERIALS
      Load/save materials.
      void _ApplicationOutput(maxon::TARGETAUDIENCE t, maxon::WRITEMETA lvl, const maxon::String &str, Int line, const Char *file)
      #define FormatString(...)
      Definition: string.h:2168
      The list of recently opened scene files is accessed with:
    • GetRecentDocumentsList(): Returns the list of recently opened scene files.
    // This example loads the given c4d file and prints its min. and max. frame to the console.
    // check if the Filename references a "c4d" file
    if (filename.CheckSuffix("c4d"_s))
    {
    if (loadedDoc == nullptr)
    return maxon::IoError(MAXON_SOURCE_LOCATION, MaxonConvert(filename, MAXONCONVERTMODE::NONE), "Could not load document."_s);
    const Int32 fps = loadedDoc->GetFps();
    const Int32 startFrame = loadedDoc->GetMinTime().GetFrame(fps);
    const Int32 endFrame = loadedDoc->GetMaxTime().GetFrame(fps);
    BaseDocument::Free(loadedDoc);
    // convert to String to print the data to the console
    const String fileStr = filename.GetString();
    const String startFrameStr = String::IntToString(startFrame);
    const String endFrameStr = String::IntToString(endFrame);
    // print to console
    ApplicationOutput("Document " + fileStr + ": " + startFrameStr + " - " + endFrameStr);
    }
    BaseTime GetMinTime() const
    Int32 GetFps() const
    BaseTime GetMaxTime() const
    static void Free(BaseDocument *&bl)
    Int32 GetFrame(Float fps) const
    Definition: c4d_basetime.h:107
    static String IntToString(Int32 v)
    Definition: c4d_string.h:497
    • SaveDocument(): Saves the document to a Cinema 4D file or to a supported export file format.
    • SaveProject(): Saves the document like the "Save Project with Assets" command.
    // This example creates a new BaseDocument, adds an cube to it to save it to file.
    if (tempDoc == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    if (cube == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    tempDoc->InsertObject(cube, nullptr, nullptr);
    return maxon::IoError(MAXON_SOURCE_LOCATION, MaxonConvert(savepath, MAXONCONVERTMODE::NONE), "Could not save document."_s);
    Bool SaveDocument(BaseDocument *doc, const Filename &name, SAVEDOCUMENTFLAGS saveflags, Int32 format)
    #define FORMAT_C4DEXPORT
    Cinema&#160;4D export.
    Definition: ge_prepass.h:3530
    @ DONTADDTORECENTLIST
    Do not add the saved document to the recent file list.

    Render

    A BaseDocument can be rendered independently from the GUI and the Picture Viewer into a BaseBitmap (see BaseBitmap Manual).

    // This example loads the given c4d file.
    // One frame of the loaded document is rendered and displayed in the Picture Viewer.
    BaseDocument* const loadedDoc = LoadDocument(filename, flags, nullptr);
    if (loadedDoc == nullptr)
    return maxon::IoError(MAXON_SOURCE_LOCATION, MaxonConvert(filename, MAXONCONVERTMODE::NONE), "Could not load document."_s);
    // auto free the loaded document
    docFree.Assign(loadedDoc);
    RenderData* const rdata = loadedDoc->GetActiveRenderData();
    if (rdata == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    BaseContainer renderSettings = rdata->GetDataInstanceRef();
    // just render one frame
    const BaseTime startFrame = renderSettings.GetTime(RDATA_FRAMEFROM, BaseTime());
    renderSettings.SetTime(RDATA_FRAMETO, startFrame);
    // prepare target bitmap
    if (bitmap == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    const Int32 width = renderSettings.GetInt32(RDATA_XRES);
    const Int32 height = renderSettings.GetInt32(RDATA_YRES);
    const IMAGERESULT imageRes = bitmap->Init(width, height);
    if (imageRes != IMAGERESULT::OK)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // render the image
    const RENDERRESULT res = RenderDocument(loadedDoc, renderSettings,
    nullptr, nullptr, bitmap, renderFlags, nullptr);
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // show result
    ShowBitmap(bitmap);
    Definition: ge_autoptr.h:155
    void Assign(TYPE *p)
    Definition: ge_autoptr.h:234
    void SetTime(Int32 id, const BaseTime &b)
    Definition: c4d_basecontainer.h:672
    BaseTime GetTime(Int32 id, const BaseTime &preset=BaseTime()) const
    Definition: c4d_basecontainer.h:456
    RenderData * GetActiveRenderData()
    @ RDATA_FRAMETO
    Definition: drendersettings.h:165
    @ RDATA_FRAMEFROM
    Definition: drendersettings.h:164

    Messages

    On certain events (load, save, render,...) a MSG_DOCUMENTINFO message is sent to elements contained in a document.

    // This example catches MSG_DOCUMENTINFO in a ObjectData::Message() function.
    // When the document is loaded the value of a old (legacy) parameter is copied
    // into a new parameter.
    {
    DocumentInfoData* const msg = static_cast<DocumentInfoData*>(data);
    if (msg == nullptr)
    return false;
    // switch message sub-type
    switch (msg->type)
    {
    {
    BaseObject* const op = static_cast<BaseObject*>(node);
    if (!op)
    return false;
    BaseContainer& bc = op->GetDataInstanceRef();
    bc.SetInt32(NEW_PARAMETER, bc.GetInt32(OLD_PARAMETER));
    ApplicationOutput("document is loaded"_s);
    break;
    }
    }
    break;
    }
    void SetInt32(Int32 id, Int32 l)
    Definition: c4d_basecontainer.h:587
    #define MSG_DOCUMENTINFO_TYPE_LOAD
    Document was loaded.
    Definition: c4d_baselist.h:479
    #define MSG_DOCUMENTINFO
    Sent as broadcast message by the document when it is loaded, saved , merged etc. The corresponding da...
    Definition: c4d_baselist.h:468
    struct _node node
    const char const char * msg
    Definition: object.h:438
    Message struct for the MSG_DOCUMENTINFO message.
    Definition: c4d_baselist.h:1153

    Futher document related messages:

    Further Reading