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
AutoAlloc<BaseDocument> virtualDoc;
if (virtualDoc == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// create and add a new cube
BaseObject* const cube = BaseObject::Alloc(Ocube);
if (cube == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
virtualDoc->InsertObject(cube, nullptr, nullptr);
// prepare bitmap
AutoAlloc<BaseBitmap> 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
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:3947
#define Ocube
Cube.
Definition: ge_prepass.h:1118
RENDERFLAGS
Definition: ge_prepass.h:4718
RENDERRESULT
Definition: ge_prepass.h:426
#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

Access

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

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

  • BaseDocument::GetNext(): Returns the next document in the list.
  • BaseDocument::GetPred(): Returns the previous document in the list.
// 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);
BaseDocument* document = GetFirstDocument();
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();
}
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
BaseDocument * GetActiveDocument()
BaseDocument * GetFirstDocument()
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:

  • BaseDocument::Alloc(): Creates a new BaseDocument.
  • BaseDocument::Free(): Deletes the given BaseDocument.

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)
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().

  • KillDocument(): Removes the given BaseDocument safely from the document list and frees all of its resources.
  • BaseDocument::Flush(): Clears the BaseDocument.

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");
NONE
Definition: asset_browser.h:1
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.

  • BaseDocument::GetDocPreviewBitmap(): Returns the preview image of the BaseDocument.
// This example shows the preview bitmap in the Picture Viewer.
BaseBitmap* const bitmap = doc->GetDocPreviewBitmap();
if (bitmap != nullptr)
{
ShowBitmap(bitmap);
}

Properties

Data

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

  • BaseDocument::GetData(DOCUMENTSETTINGS): Returns a BaseContainer with selected settings.
  • BaseDocument::SetData(): Merges the given BaseContainer with the document's settings.
  • BaseDocument::GetSettingsInstance(): Returns a pointer to the BaseContainer with the selected settings.
// This example switches the statue of the "Use Generators" setting.
const BaseContainer data = doc->GetData(DOCUMENTSETTINGS::GENERAL);
const Bool useGenerators = data.GetBool(DOCUMENT_USEGENERATORS);
// set new settings
BaseContainer settings;
settings.SetBool(DOCUMENT_USEGENERATORS, !useGenerators);
doc->SetData(DOCUMENTSETTINGS::GENERAL, settings);
@ DOCUMENT_USEGENERATORS
Definition: ddoc.h:24
GENERAL
General settings.
Definition: ge_prepass.h:0
maxon::Bool Bool
Definition: ge_sys_math.h:46

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);
@ DOCUMENT_INFO_AUTHOR
Definition: ddoc.h:48
DOCUMENT
Document settings mode.
Definition: lib_activeobjectmanager.h:15
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.

  • BaseDocument::GetFirstObject(): Returns the first BaseObject of the scene.
  • BaseDocument::InsertObject(): Inserts a BaseObject into the scene.
  • BaseDocument::SearchObject(): Searches for a BaseObject with the given name.
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);
return OK
Definition: apibase.h:2740

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.

  • BaseDocument::GetHighest(): Typically used to get the only useful instance of an object type.
// 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() + "\"");
#define Ostage
Stage.
Definition: ge_prepass.h:1075

Materials

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

  • BaseDocument::GetFirstMaterial(): Returns the first BaseMaterial in the list.
  • BaseDocument::InsertMaterial(): Inserts a BaseMaterial into the list.
  • BaseDocument::SearchMaterial(): Searches for a BaseMaterial with the given name.

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);
#define Mmaterial
Standard material.
Definition: ge_prepass.h:1007

Selections

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

  • BaseDocument::GetSelection(): Fills the given AtomArray with the selected objects and tags.
  • BaseDocument::SetSelection(): Adds the given element to the current selection or starts a new selection.
// This example prints the name and type of all selected scene elements.
AutoAlloc<AtomArray> selection;
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
#define Tbaselist2d
2D list.
Definition: ge_prepass.h:995
PyObject * element
Definition: unicodeobject.h:1016

Object selections can be managed separately:

  • BaseDocument::GetActiveObject(): Returns the currently selected BaseObject.
  • BaseDocument::GetActiveObjects(): Returns the current multi-selection of BaseObject objects.
  • BaseDocument::GetActivePolygonObjects(): Returns the currently selected polygon objects.
  • BaseDocument::GetActiveObjectsFilter(): Returns the currently selected BaseObjects that match the given filters.
  • BaseDocument::GetRealActiveObject(): Returns the "real" active object. Either the active object, the helper axis of a multi-selection or the position of a workplane in workplane mode.
  • BaseDocument::SetActiveObject(): Adds or removes the given BaseObject to the selection or starts a new selection.
  • BaseDocument::GetTargetObject(): Returns the target object (the last selected object).
  • BaseDocument::SetTargetObject() Sets the given object as the target object.
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
AutoAlloc<AtomArray> selection;
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
BaseObject* const cube = BaseObject::Alloc(Ocube);
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);
}
#define NOTOK
Definition: ge_sys_math.h:258
#define Onull
Null.
Definition: ge_prepass.h:1077
#define SELECTION_ADD
Adds to the current selection.
Definition: c4d_basedocument.h:411
maxon::Mat3< maxon::Vector64 > Matrix
Definition: ge_math.h:159

Material selections can be managed separately, too:

  • BaseDocument::GetActiveMaterial(): Returns the currently selected BaseMaterial.
  • BaseDocument::GetActiveMaterials(): Returns the current multi-selection of BaseMaterial objects.
  • BaseDocument::SetActiveMaterial(): Adds or removes the given BaseMaterial to the selection or starts a new selection.
// 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);
#define SELECTION_NEW
Starts a new selection.
Definition: c4d_basedocument.h:410
#define Ttexture
Texture - TextureTag.
Definition: ge_prepass.h:1420

Finally tag selections can be managed:

  • BaseDocument::GetActiveTag(): Returns the currently selected BaseTag.
  • BaseDocument::GetActiveTags(): Returns the current multi-selection of BaseTag objects.
  • BaseDocument::SetActiveTag(): Adds or removes the given BaseTag to the selection or starts a new selection.
// This example loops through all selected tags.
// If a tag is a Texture Tag, the given material is applied.
// get all selected tags
AutoAlloc<AtomArray> 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);
}
}

RenderData

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

  • BaseDocument::GetActiveRenderData(): Returns the active RenderData.
  • BaseDocument::SetActiveRenderData(): Sets the given RenderData as the active one.
  • BaseDocument::GetFirstRenderData(): Returns the first RenderData.
  • BaseDocument::InsertRenderData(): Adds the given RenderData object to the document.
  • BaseDocument::InsertRenderDataLast(): Adds the given RenderData object to the document at last position.

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);

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:

  • BaseDocument::FindSceneHook(): Returns the instance of the scene hook with the given ID that is 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);
@ 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:

  • BaseDocument::GetLayerObjectRoot(): Returns the GeListHead root object of the layer 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());

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:

  • BaseDocument::GetTakeData(): Returns the TakeData object storing the takes of the document.
// 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);

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.

  • BaseDocument::GetChanged(): Returns true if the scene was changed.
  • BaseDocument::SetChanged(): Sets the scene as changed.
// This example closes and frees the currently active document only if it is not "dirty".
BaseDocument* activeDoc = GetActiveDocument();
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)

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.

  • BaseDocument::GetDocumentName(): Returns the document name (filename including suffix).
  • BaseDocument::GetDocumentPath(): Returns the document's save path.
  • BaseDocument::SetDocumentName(): Sets the document's name.
  • BaseDocument::SetDocumentPath(): Sets the document's save path.
// 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);
}

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.

  • BaseDocument::GetLOD(): Returns the document LOD value.
  • BaseDocument::SetLOD(): Sets the document LOD value.
  • BaseDocument::GetRenderLod(): Returns true if the render LOD should be applied in the editor.
  • BaseDocument::SetRenderLod(): Defines if the render LOD should be applied in the editor.
  • CalcLOD(): Helper function to modify a user chosen subdivision value.
// 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);
}
@ RDATA_LOD
Definition: drendersettings.h:61
maxon::Float Float
Definition: ge_sys_math.h:57
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:

  • BaseDocument::GetTime(): Returns a BaseTime storing the current time.
  • BaseDocument::SetTime(): Sets the current time of the document using a BaseTime object.
  • SetDocumentTime(): Sets the given document's 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);

Framerate:

  • BaseDocument::GetFps(): Returns the document's framerate.
  • BaseDocument::SetFps(): Sets the document's 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);
@ RDATA_FRAMERATE
Definition: drendersettings.h:171

Timeline dimensions:

  • BaseDocument::GetMinTime(): Returns the start time of the document's timeline.
  • BaseDocument::SetMinTime(): Sets the start time of the document's timeline.
  • BaseDocument::GetMaxTime(): Returns the end time of the document's timeline.
  • BaseDocument::SetMaxTime(): Sets the end time of the document's timeline.

Used Time:

  • BaseDocument::GetUsedMinTime(): Returns the lower bound of used time for the whole document or the given object.
  • BaseDocument::GetUsedMaxTime(): Returns the upper bound of the used time for the whole document or the given object.

Loop Preview:

  • BaseDocument::GetLoopMinTime(): Returns the lower bound of the document's loop preview.
  • BaseDocument::SetLoopMinTime(): Sets the lower bound of the document's loop preview.
  • BaseDocument::GetLoopMaxTime(): Returns the upper bound of the document's loop preview.
  • BaseDocument::SetLoopMaxTime(): Sets the lower bound of the document's 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.).

  • BaseDocument::GetMode(): Returns the current mode.
  • BaseDocument::SetMode(): Sets the current mode.
  • BaseDocument::IsEditMode(): Checks if the current mode is ::Mpoints, ::Medges or ::Mpolygons.
  • BaseDocument::IsAxisEnabled(): Returns true if the axis modifier is enabled and the axis should be edited.
// 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:1983
@ Mpolygons
Polygon edit mode.
Definition: c4d_basedocument.h:1984
@ Mpoints
Point edit mode.
Definition: c4d_basedocument.h:1982
#define Tpointselection
Point selection - SelectionTag.
Definition: ge_prepass.h:1432
#define Tedgeselection
Edge selection - SelectionTag. The edges are encodes like this: (4*poly)+edge, where edge goes from 0...
Definition: ge_prepass.h:1449
#define Tpolygonselection
Polygon selection - SelectionTag.
Definition: ge_prepass.h:1431

Active Tool

The currently active tool is stored in the document.

  • BaseDocument::GetAction(): Returns the ID of the currently used tool.
  • BaseDocument::SetAction(): Sets the currently used tool.
  • GetToolData(): Returns the BaseContainer storing the settings of the tool of the given ID.
// This example switches the mode and enables and configures the "Knife" tool.
BaseContainer* const tool = GetToolData(doc, ID_MODELING_KNIFE_LINE);
if (tool == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
tool->SetBool(MDATA_KNIFELINE_ANGLE_CONSTRAINT, true);
doc->SetMode(Mpoints);
#define ID_MODELING_KNIFE_LINE
Definition: modelingids.h:43
BaseContainer * GetToolData(BaseDocument *doc, Int32 pluginid, Bool create=true)
@ 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.

  • BaseDocument::GetHelperAxis(): Returns a BaseObject representing the helper axis.
// 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);
}
@ Mmodel
Model mode.
Definition: c4d_basedocument.h:1987
  • BaseDocument::GetSplinePlane(): Returns the plane that should be used for new splines. Depends on the currently selected editor window.

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.

  • BaseDocument::GetActiveBaseDraw(): Returns the BaseDraw of the currently active editor window.
  • BaseDocument::GetRenderBaseDraw(): Returns the BaseDraw that should be used as the render view. This function should be used in NodeData based plugins.
  • BaseDocument::GetBaseDrawCount(): Returns the number of current editor windows.
  • BaseDocument::GetBaseDraw(): Returns the BaseDraw with the given index.
  • BaseDocument::ForceCreateBaseDraw(): Called to enforce at least one BaseDraw is available.
  • BaseDocument::GetDrawTime(): Returns the editor redraw time.

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);
V off
The translation vector.
Definition: matrix.h:263

Net Context

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

  • BaseDocument::GetNetRenderDocumentContext(): Returns a NetRenderDocumentContext object during NET rendering.
  • BaseDocument::SetNetRenderDocumentContext(): Only used internally.
// 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

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:

  • BaseDocument::RecordKey(): Creates a key at the given time for the given parameter.
  • BaseDocument::AutoKey(): Creates keys automatically if auto key mode is enabled.
  • BaseDocument::Record(): Creates keyframes for all selected objects. Parameters must be added to the keyframe selection.
// 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
cubeObject->SetParameter(ConstDescID(DescLevel(PRIM_CUBE_SUBX)), 10, DESCFLAGS_SET::NONE);
cubeObject->SetParameter(ConstDescID(DescLevel(PRIM_CUBE_SUBY)), 10, DESCFLAGS_SET::NONE);
cubeObject->SetParameter(ConstDescID(DescLevel(PRIM_CUBE_SUBZ)), 10, DESCFLAGS_SET::NONE);
// create auto keys if "Auto Key" is enabled.
doc->AutoKey(undoObject, cubeObject, true, true, true, true, true, true);
BaseObject::Free(undoObject);
#define ConstDescID(...)
Definition: lib_description.h:592
@ PRIM_CUBE_SUBY
Definition: ocube.h:9
@ PRIM_CUBE_SUBX
Definition: ocube.h:8
@ PRIM_CUBE_SUBZ
Definition: ocube.h:10

See also Animation Tracks.

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

  • BaseDocument::AnimateObject(): Animates the given object at the given frame.
  • BaseDocument::ExecutePasses(): Animates the whole document. One might have to call BaseDocument::ExecutePasses() multiple times to fully animate up to a given frame.
  • RunAnimation(): Controls the animation of the given document.
// 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);
INTERNALRENDERER
Rendering in the editor.
Definition: ge_prepass.h:1
maxon::Vec3< maxon::Float64, 1 > Vector
Definition: ge_math.h:140

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

  • BaseDocument::GetDefaultKey(): Returns the default key template.
  • BaseDocument::SetDefaultKey(): Sets the default key template.
// This example changes the default key of the document.
AutoAlloc<CKey> key;
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
Definition: lib_birender.h:1

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:

  • BaseDocument::SetRewind(): The document will be animated from frame 0 to the current frame when an update event EVMSG_CHANGE is triggered. Typically triggered in NodeData::SetDParameter(). During this rewind no caches are build.
  • BIT_DOCUMENT_CHECKREWIND: Will cause the document to animate from 0 if the current time is earlier than the last execution time.
// 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();
@ 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.

  • BaseDocument::StartUndo(): Starts an undo action. Must be paired with BaseDocument::EndUndo().
  • BaseDocument::AddUndo(): Adds an undo operation to the current action.
  • BaseDocument::GetUndoPtr(): Returns the pointer to the element of the last operation.
  • BaseDocument::FindUndoPtr(): Returns the pointer to the element of the last operation of the given undo type.
  • BaseDocument::EndUndo(): Ends an undo action.

See also Undo System Manual.

// This example creates a cube object and adds it to the document with an undo step.
BaseObject* const cube = BaseObject::Alloc(Ocube);
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 Cinema API node instance has been inserted into the document....
Definition: ge_prepass.h:7

Undo actions can be executed:

  • BaseDocument::DoUndo(): Performs the undo action.
  • BaseDocument::DoRedo(): Performs the redo action.
  • BaseDocument::FlushUndoBuffer(): Flushes the undo buffer.

Pick Session

A pick session can be used to select multiple objects.

  • BaseDocument::GetPickSession(): Gets the data structure of the current pick session.
  • BaseDocument::StartPickSession(): Starts a pick session.
  • BaseDocument::StopPickSession(): Ends the pick session.

See PickSessionDataStruct.

Send Messages

  • BaseDocument::SendInfo(): sends a MSG_DOCUMENTINFO message to all document elements. This is typically not needed for plugins.

Convert and Export

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

  • BaseDocument::Polygonize(): Returns a copy of the document in which all objects are converted to polygon objects. The source code is available in c4d_basedocument.cpp.
  • BaseDocument::CollectSounds(): Creates a downmix of all sounds of the document's sound mix.
  • BaseDocument::GetAllTextures(): Sends the MSG_GETALLASSETS message to collect the assets of the given selection or the whole document.
  • GetAllAssets(): Retrieves all assets from a document.
// 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());
}
}
@ DA_FILENAME
Filename.
Definition: c4d_gedata.h:47
  • 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.
    Filename filename;
    "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);
    SCENES
    Filter for scene files only.
    Definition: asset_browser.h:6
    PyCompilerFlags const char * filename
    Definition: ast.h:15
    LOAD
    Load.
    Definition: c4d_filterdata.h:1
    READ
    Problems reading the file.
    Definition: ge_prepass.h:3
    Bool LoadFile(const Filename &name, Bool allowAsync)
    maxon::Url MaxonConvert(const Filename &fn, MAXONCONVERTMODE convertMode)
  • 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.
    Filename filename;
    "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);
    OBJECTS
    Filter for object assets only.
    Definition: asset_browser.h:1
    MATERIALS
    Filter for material assets only.
    Definition: asset_browser.h:2
    Definition: string.h:1287
    MERGESCENE
    Flag to inform a plugin that this is a merge operation, i.e. the document that is inserted to is an e...
    Definition: ge_prepass.h:5
    int32_t Int32
    32 bit signed integer datatype.
    Definition: apibase.h:175
    SCENEFILTER
    Definition: ge_prepass.h:297
    void _ApplicationOutput(maxon::TARGETAUDIENCE t, maxon::WRITEMETA lvl, const maxon::String &str, Int line, const Char *file)
    #define FormatString(...)
    Definition: string.h:2218
    BaseDocument * LoadDocument(const Filename &name, SCENEFILTER loadflags, BaseThread *thread, maxon::String *errorString=nullptr, const ProgressDelegate &progressDelegate=ProgressDelegate())
    void StatusClear()
    Clears the status bar text.
    void StatusSetBar(Int32 p)
    Bool GeIsMainThreadAndNoDrawThread()
    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))
{
BaseDocument* loadedDoc = LoadDocument(filename, SCENEFILTER::NONE, nullptr);
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);
}
  • 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.
AutoAlloc<BaseDocument> tempDoc;
if (tempDoc == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
BaseObject* const cube = BaseObject::Alloc(Ocube);
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);
DONTADDTORECENTLIST
Do not add the saved document to the recent file list.
Definition: ge_prepass.h:3
#define FORMAT_C4DEXPORT
Cinema 4D export.
Definition: ge_prepass.h:3563
Bool SaveDocument(BaseDocument *doc, const Filename &name, SAVEDOCUMENTFLAGS saveflags, Int32 format)

Render

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

  • RenderDocument(): Renders the given BaseDocument using the given render settings.
// 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
AutoFree<BaseDocument> docFree;
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
AutoAlloc<BaseBitmap> 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);
@ 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.

  • MSG_DOCUMENTINFO: The message that is sent.
  • DocumentInfoData: The data that is sent with that message.
// 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;
}
#define MSG_DOCUMENTINFO_TYPE_LOAD
Document was loaded.
Definition: c4d_baselist.h:493
#define MSG_DOCUMENTINFO
Sent as broadcast message by the document when it is loaded, saved , merged etc. The corresponding da...
Definition: c4d_baselist.h:482
struct _node node
const char const char * msg
Definition: object.h:438

Futher document related messages:

Further Reading