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