Provides an overview of the major changes introduced with Cinema 4D 2025.0 API.
The major change of the 2025 API is the introduction of the cinema
namespace. The introduction was necessary to better separate product namespaces. The cinema
namespace contains all Cinema 4D specific concepts, while the already existing maxon
namespace is meant to contain concepts that in principle could be used in other products as well. The cinema
namespace is the new home of the Cinema 4D API and replaces what was formerly known as the Classic API and encompassed all entities in the formerly global anonymous namespace. E.g., the Classic API type BaseContainer
became cinema::BaseContainer
, and the classic API BaseList2D
became cinema::BaseList2D
, and so on.
opposed to the maxon API and namespace which contains general purpose concepts.
The cinema namespace is the new home of the Cinema 4D API and replaces what was formerly known as the Classic API and encompassed all entities in the global anonymous namespace. E.g., the Classic API type BaseContainer
became cinema::BaseContainer
, and the classic API BaseList2D
became cinema::BaseList2D
, and so on. See Managing Namespaces for details on how to update your existing code to the new namespace.
With now two top level namespaces, cinema
and maxon
, it is important to understand how to manage them in your code. There are in principle three ways to do this:
using
directives to make types from a namespace available in the global namespace.This is in most cases the best option to update your code as it is the fastest way to update files and a project. The following pre-2025 code shown below,
can be updated by adding a using namespace cinema;
directive at the top of the file. This will make all Cinema 4D API types available in the global namespace; given that they are being included. The updated code would look like this:
Note that we could also add a using namespace maxon;
at the top to also make the maxon API types available in the global namespace. As long as there are no naming conflicts, the compiler will be able to resolve the types correctly.
But when we use multiple namespace in this manner and at the same time include header files containing colliding identifiers, the compiler will not be able to resolve the types correctly. This is because the using
directive makes all types from the namespace available in the global namespace, and the compiler will not be able to resolve ambiguous definitions when an identifier is defined in both namespaces. An example for this is the type Asset
which can refer both to cinema::Asset
and maxon::Asset
. As long as we include only one of the types in the file, the compiler will be able to resolve the type correctly, as shown below.
But as soon as we also include the header file for the classic API type, Asset
, the compiler will not be able to resolve the type correctly and throw an error.
While it is probably rare that we include both types in the same file, indirectly including both types through umbrella includes can happen. In such cases, it is best to qualify the types with the respective namespace to resolve the ambiguity.
An exception from this are the atomic types such as cinema::Int32
, maxon::Int32
, cinema::Bool
, maxon::Bool
, cinema::String
, or maxon::String
which are defined in both namespaces and can be used interchangeably; the types in the cinema
namespace are just an alias for the types in the maxon
namespace. This is also why the Bool
in Init
function of MyPlugin
does not have to be qualified with cinema::
or maxon::
.
To summarize:
RegisterMyHook()
which then call internally one or many plugin hook registration functions such as RegisterObjectPlugin()
. These functions are usually meant to live in the global namespace as they tend to be called from the main file with a forward declaration. A using directive in either the main.cpp/.h
or the file containing the custom registration function RegisterMyHook()
definition can lead to problems.A more controlled way to manage namespaces is to wrap code in namespaces or to add qualifiers to all types. This gives you more control over which parts of your code are affected by the namespace. The following example shows how to wrap code in a namespace.
using
directive. In the example shown above, we implicitly use the maxon
namespace in the cinema
namespace scope, Result
, Asset
, and OK
are all members of the maxon
namespace.using namespace cinema;
directive and a namespace cinema
scope in the same file is perfectly valid, the compiler will not try to interpret things as cinema::cinema::
in the namespace scope.using
directive in the global namespace.using
directives and namespace scopes to limit the scope of the using
directive to a specific namespace scope. E.g., namespace bar { using namespace foo; }
will make all types from the foo
namespace available in the bar
namespace scope.using
directive, the compiler will not be able to resolve ambiguous definitions when including header files with colliding identifiers from different namespaces. In such cases, it is best to qualify the types with the respective namespace to resolve the ambiguity.The most controlled way to manage namespaces is to add qualifiers to all types. This is the most time-consuming way but gives you the most control over which parts of your code are affected by the namespace. There are no drawbacks here except for the additional typing effort. The updated code would look like this:
Other than that, there are only minor changes that need to be made to your existing code.
cinema.frameworks/source/description/ddoc.h
is in most source code being pushed into the cinema
namespace, although itself contains no namespace nor are other descriptions being placed in the cinema
namespace. This happens due to operatingsystem.h
which includes ddoc.h
inside a cinema namespace. Most projects will indirectly include operatingsystem.h
before they had a chance to include ddoc.h
, causing for example the identifier for the document frame rate to be cinema::DOCUMENT_FPS
and not DOCUMENT_FPS
as it was before. ConstDescID
behaves slightly irregularly when used inside the global anonymous namespace. maxon.Opt.GetValueOrDefault()
has been renamed to maxon.Opt.GetOrDefault()
.