administrators

Private

Posts

  • RE: 2025 SDKs missing files

    Hello @atg,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.

    About your First Question

    I can see why would think that, but you mixed things there a bit up. The CMake SDK build system was introduced with 2025.2.0 and became the standard with 2026.0.0. Between 2025.2 and 2025.3 we supported both build systems as a grace period for developers to get accustomed.

    Chances are very good, that you can just copy the CMake setup, i.e., the cmake folder and files such as CMakeLists.txt, CMakePresets.json, and sdk_modules.txt to a 2025.0 folder and it will generate a correct build system for you.

    But the supported range is only 2025.2+. For older projects you would have to use the old project tool based build system. Since I know what you are trying to do, I would recommend trying copying before you get into the old build system of ours.

    Cheers,
    Ferdinand

    edit: You will only find the old project tool tooling in old extended SDKs which supported it, such as 2025.2 or 2025.0.1

  • RE: CUSTOMGUI_QUICKTAB trigger twice when click

    hey @Gene,

    So, you were just trying to add information for future readers? That is of course very welcome and explains my inability to extract a question from your posting.

    I would not have been that generous with the word bug either. Since this has never been fixed, chances are high that we came to the same conclusion internally.

    In general, you should not expect Command calling patterns to make perfect sense in every case. There are multiple cases where Command is triggered more often than one would think at first glance. I would also not try to interpret some deeper sense into all that.

    Cheers,
    Ferdinand

  • RE: CUSTOMGUI_QUICKTAB trigger twice when click

    Hey @Gene,

    Thread-necromancy is often not so good, because it almost always derails the original topic and often also lacks in clarity. I also here do not understand what your concrete question is?

    When I click on the Quicktab, the first event returns True, while the second returns False.

    What do you mean by "the event returns true"? It is you, the developer, who returns the result for an event (or you do not handle it at all). Are you talking about something like BFM_ACTION_VALUE?

    If I drag over two entries on the Quicktab gadget (click on one entry, then drag to the next entry and let go of the mouse,) Command triggers three times, msg[c4d.BFM_ACTION_INDRAG] returns True the first two times and False for the last one. Also, the first entry returns True for its IsSelected() check on mouse down. After dragging, the the second entry's IsSelected() is True. Second entry's IsSelected() is also true when I let go of the mouse.

    I do not see any question here, so what is the goal?

    Regarding Command triggering twice, is it because of the mouse events?

    GeDialog.Command is just a convenience wrapper for GeDialog.Message events (most from the BFM_ACTION family). If you want the full picture, use Message. I struggle to see a tangible question which I could answer, what do you want to achieve?

    Yes, some controls fire multiple times in Command, it is impossible (and also somewhat futile) to reconstruct the reason for each of them. Someone thought at some point it would be convenient to forward this kind of event to Command for some feature in Cinema 4D.

    I am not familiar with the exact issue discussed in this topic, but at a glance, what Maxime wrote then looks a bit overkill with the hashing, I would just store the last selected element and be done with it. Alternatively you could design your code so that you do not tie any heavy logic to a tab being activated (which is IMHO not a great idea in general), so that you do not mind when such code runs multiple times.

    Cheers,
    Ferdinand

    class MyDialog (c4d.gui.GeDialog):
        ID_TAB_1: int = 10000
        ID_TAB_2: int = 10001
    
        IDS_TABS: tuple[int, ...] = (ID_TAB_1, ID_TAB_2)
    
        def __init__(self) -> None:
            self._activeTab: int = MyDialog.ID_TAB_1
    
        def Command(self, cid: int, msg: c4d.BaseContainer) -> bool:
            """
            """
            if cid == self._activeTab:
                return True
            elif cid in MyDialog.IDS_TABS:
                self._activeTab = cid
    
            if cid is MyDialog.ID_TAB_1:
                foo()
            elif cid is MyDialog.ID_TAB_2:
                bar()
    
            return True
    
  • RE: How to detect Global Illumination state via Python API?

    Hey @mfersaoui,

    Thank you for reaching out to us. The question is a bit ambiguous. What it entails when 'Global Illumination is enabled' (or not), differs from render engine to render engine. There is neither an abstracted switch to toggle GI in all render engines, nor a flag which would signal of GI is enabled or not.

    So, the first thing you would have to do, is read RDATA_RENDERENGINE and then branch of based on that. For the standard renderer, you would then check if the GI post effect is loaded and enabled. For Redshift you would get the RS post effect and then check there if has GI enabled.

    You can find the post effect symbols here: VideoPost Types

    Cheers,
    Ferdinand

    Some example code for searching the post effects in some render data.

    # Get the active render data of the document.
    renderData: c4d.documents.RenderData = doc.GetActiveRenderData()
    
    # Set the active render engine to Redshift.
    renderData[c4d.RDATA_RENDERENGINE] = c4d.VPrsrenderer
    
    # Iterate over all video post effects and remove any effect not compatible with the Redshift 
    # render engine and finally make sure the Redshift video post effect itself is present. We do 
    # not remove the effects in place in the loop, as that would mess up the iteration because nodes
    # effectively work as a linked list.
    removeEffects: list[c4d.documents.BaseVideoPost] = []
    foundRedshiftEffect: bool = False
    for effect in mxutils.IterateTree(renderData.GetFirstVideoPost(), True):
        # This is the Redshift video post effect.
        if effect.GetType() == c4d.VPrsrenderer:
            foundRedshiftEffect = True
            continue
        # This is some effect not compatible with Redshift.
        elif not effect.RenderEngineCheck(c4d.VPrsrenderer):
            removeEffects.append(effect)
    
    # Remove all the video post effects we marked for removal.
    for effect in removeEffects:
        effect.Remove()
    
    # And add the Redshift video post effect if it was not found yet. Note that there is no hard
    # guarantee that a render engine uses the same ID for its video post effect as the render 
    # engine ID (VPrsrenderer in this case). But it is a very common convention, check with your
    # render engine vendor for details.
    if not foundRedshiftEffect:
        redshiftEffect: c4d.documents.BaseVideoPost = mxutils.CheckType(
            c4d.documents.BaseVideoPost(c4d.VPrsrenderer))
        renderData.InsertVideoPost(redshiftEffect)
    
  • RE: Advice on implementing undo/redo in a Tool

    Hey @SteveHill3D,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.

    About your First Question

    You could look at our edgecuttool.cpp C++ SDK example, it demonstrates both the usage of undos and cinema::InteractiveModeling_Restart, i.e., rolling updates. In some cases InteractiveModeling_Restart will not cut it you have to un-roll your undos yourself or even not use undos at all for rolling updates and instead work with a tool finalization logic.

    By chance I just wrote an example for the latter for the upcoming Python SDK. You will not be able to run it, as the customer release version is missing the Python API to deal with SDS weights, but you can have a look at its code. The idea is simple: Establish a ground truth and operate based on that. But for modelling tools and especially tools that add or remove geometry using undos and InteractiveModeling_Restart should be preferred when possible, as it will be usually faster, as the cinema core can pull some tricks you cannot as a third party.

    Cheers,
    Ferdinand

    Please understand that this example is a preview and might be subject to change.
    py-cmd_tool_finalization_2026_2.zip

  • RE: Tile rendering with Cinema 4D

    Hey @karthikbp,

    Thank you for reaching out to us. And sorry, I somehow overlooked your topic. Yes, that is how I would have done it too, via RDATA_RENDERREGION_LEFT, etc. The 2026.2 Python SDK will contain new rendering examples, that could be something I could add, as tile rendering is something that comes up from time to time.

    As a fair warning: Your code will not respect OCIO, i.e., the images will have the wrong colors. Since you marked this as 2026, where OCIO is the color management standard, this would apply to all documents. See open_color_io_2025_2.py for an example how to do it correctly. The next release will streamline things there quite a bit.

    Cheers,
    Ferdinand

  • RE: EventAdd doesn't work with a modal dialog in C4D 2026

    Hey @aturtur,

    Thank you for reaching out to us. EventAdd will never really work in script manager scripts in the sense you mean it, unless you use hacks like dangling async dialogs (which as I always point out are a really bad idea).

    The reason is that Script Manager scripts are blocking, i.e., all scene and GUI execution is being halted until the script finishes. You can hack yourself around this with a dangling async dialog, i.e., a dialog that lives beyond the life time of its script. But that is not a good idea, you should implement some form of plugin to host your asnyc dialog, as you otherwise risk crashes.

    A modal dialog is just an extension of this. It is right in the name, it is modal, i.e., synchronous. All scene and GUI execution is being halted while this dialog is open and only resumes once it closes. When you want updates while your dialog is open, you need an async dialog (and a plugin which hosts it).

    Cheers,
    Ferdinand

    Since you also might misunderstand the nature of EventAdd() I am also putting here the C++ docs I updated a few weeks ago, to better reflect the nature of it (not yet live):

    /// @brief Enqueues an update event for the active document.
    /// @details Only must be called when modifying the active document and is without meaning for other documents. The typical example of using `EventAdd` is after adding or removing elements from the active document; and wanting these changes to be reflected in the UI. The function itself is technically thread-safe, but the vast majority of operations that require calling `EventAdd` are not thread-safe and must be called from the main thread (and therefore calling this function is usually main thread bound). The function also does not enqueue a dedicated event item, but rather sets a flag that is checked when the next update event is processed. Therefore, calling `EventAdd` multiple times in one function scope is unnecessary overhead which must be avoided. Because such multiple event flags cannot be consumed while a function on the main thread is still running, and instead the event will only be consumed after that function returns.
    /// @code
    /// Result<void> AddCubes()
    /// {
    ///   CheckState(maxon::ThreadInterface::IsMainThread(), "AddCubes must be called from the main thread."_s);
    ///
    ///   // EventAdd(); // We could also technically call it here with the same effect. The event
    ///                  // will only happen after this function returns.
    ///
    ///   BaseDocument* doc = GetActiveDocument();
    ///   for (int i = 0; i < 10; ++i)
    ///   {
    ///     BaseObject* cube = BaseObject::Alloc(Ocube);
    ///     if (!cube)
    ///       return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Failed to allocate cube object."_s);
    ///
    ///	    doc->InsertObject(cube);
    ///
    ///     // Calling EventAdd here would have no extra effect, since this event cannot be consumed while
    ///     // our main thread function is still running. And such extra calls on a large scale can cause
    ///     // considerable overhead.
    ///   }
    ///
    ///   // Notify C4D that the active document has changed. The very end of a function or scope is the
    ///   // canonical place to call EventAdd().
    ///   EventAdd();
    /// }
    /// @endcode
    /// @see The article @link page_manual_coremessages Core Messages@endlink for more information.
    /// @param[in] eventflag					The event to add: @enumerateEnum{EVENT}
    
  • RE: Render Token Questions

    @tommyf said in Render Token Questions:

    The frame padding I was referring to are in regards to the frame numbering that is written out when selecting a render pattern in the output settings that you would find under Render Settings > Save > Name where the one we typically use is Name.0000.TIF.

    Yes, that was already my hunch, as described above, and you cannot alter this numbering with render tokens, you can only add your own. When you want to change this numbering, you would have to write yourself a post processor as lined out above. Technically, you could also just run this outside of Cinema 4D, e.g.,

    commandline.exe -someScene.c4d ...
    c4dpy.exe renameScript.py -someScene.c4d
    # Or just even just a CPython instance (or any other scripting language), the problem here is
    # that you could not access the the render settings of the scene and would have to rely on conventions.
    python  renameScript.py -someScene.c4d
    

    Based on how you answered my questions it sounds like as long as I load the plugin script that contains the registration code that I could create custom tokens that way. I can also therefore create my own $frame token with my own frame padding (python str.zfill method) for frame numbers however there is no way to override the 4 digit frame padding that comes from the render settings name field.

    Yes. But you could not name it $frame, because that would collide with the builtin token of the same name.

    When the pattern my_render_frame-000001_001.tif works for you, I would definitely go for the render token. When you absolutely have to change the postfix set by Cinema 4D, that is possible too, but much more work. The work lies there not in actually renaming the files, that is somewhat trivial. The work lies in supporting all the ways a rendering can happen. When you are locked into using the commandline on your farm only, that would simplify things and drive down the costs of doing this (i.e., you would not support picture viewer, teams, editor, etc. renderings).

    Cheers,
    Ferdinand

  • RE: Xref Material reference

    Hello @Jespersather,

    thank you for reaching out to us. This is a developer forum, not an end user support forum. We cannot help you here with your end user issues. Please use our Support Center to get end user support for Cinema 4D.

    I have moved your topic into General Talk.

    Cheers,
    Ferdinand

  • RE: Render Token Questions

    Hello @tommyf,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.

    About your First Question

    Thank you for reaching out to us. Please do not hijack other threads with your questions and split up multiple questions into multiple topics in the future. Please read our support procedures, I have forked your questions.

    Do the token registrations get stored within the project files themselves or do they get stored in local machine or user settings for c4d. Meaning that if we wanted to implement this for our render farm we'd have to register the token on each one of the machines.

    Implementing a custom render token can be done with our C++ or Python API (here is an example for Python). So, you will need such plugin on each machine where you want to use that token. Not quite sure how the rest of your question is meant, 'registering a token (or any other plugin)' just means that the plugin is present when Cinema 4D is booting.

    Depending on how 1 is answered is it possible to support multiple $frame padding configurations?

    Since you do not explain what you would consider '4 to 6 digit frame padding', I can only speculate. My guess would be that you want to replace the frame counter provided by Cinema 4D in file names, e.g., transform my_render_001.tif, my_render_002.tif, etc. into my_render_0001.tif, my_render_0002.tif, etc.

    If that is what you mean, then no, that is not possible with tokens. The frame counter is something added by Cinema 4D you cannot influence as a user (as it depends on the render settings).

    You could either implement a token which adds your own frame counter to a file name (my_render_frame-0001_001.tif, my_render_frame-0002_002.tif, etc.) or you could write a postprocessor which hooks into MSG_MULTI_RENDERNOTIFICATION to catch a finished rendering and then post-process the files it created on disk. But the latter could get complicated.

    Also depending on how 1 is answered, are the token registrations permanent or are we going to have to register the custom token every time we launch c4d or whenever we want to change it.

    As explained above, I do not really understand what you are asking for. A registration is not something you do manually as a human, but rather some code that runs.

    Cheers,
    Ferdinand