Group Details Private

administrators

  • RE: How to add parameter groups to Nodes dynamically?

    Hey @peter_horvath,

    just for verboseness, you are talking about a parameter group such as the "Base" group shown below on the Redshift Standard Material node?

    2e791e1d-29d8-47cb-8109-15812d3947cf-image.png

    • You are not talking about "tabs", e.g., "Outputs", which are technically also groups, right?
    • Does the group you want to reference already exist?

    On the data description level groups are referenced as IntenernedId's, specifically over maxon::DESCRIPTION::UI::BASE::GROUPID. Groups are also not part of the data model you are operating there with, you cannot find a node for a group in a graph (I am sure you are aware, just being verbose).

    I had quick look at our code base and:

    • I do not see any alias for DESCRIPTION::UI::BASE::GROUPID on the node side of things.
    • When we deal with this internally, we query the data description database for a given node to read/modify the description. This will not work for what you want to do here (at least I think so).

    Sometimes you can just blindly set an attribute on a node and the presenter part picks then up on that (presenter as in MVP). You can 'hack' the folding state of a port bundle like this for example. But I do not see anything similar in place here. The core problem is that you are limited to the model domain of MVP in the public API.

    Will ask the node team if there is a way.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Browsing field layers causes dangling/not alive references

    Hey @baca,

    feel free to send us a mail to sdk_support(at)maxon(dot)net in case you cannot share code publicly. But we have to have a look at your code to see what is going on. When you say this worked before, we either have a soft regression (you did something which you should not but it somehow worked and we now broke that) or a strong one (we broke something that should work) on our hands. And for that we will need code to see what is going on.

    And I would not say that the performance penalty is dramatic, it more likely will be neligable. But if everyone would do that everywhere, Cinema 4D would come to a crawl. I would say you can ship your plugin with that "fix" when it does not cause any issues for you. But we should work towards solving this properly.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Browsing field layers causes dangling/not alive references

    Hey @baca,

    Well, "expected" is a difficult term in the context of 'not alive'. Let me first unpack things a bit:

    What means 'not alive'?

    • Cinema 4D is a C++ based application. So, even when you write Python code, you are operating with C++ data in the backend.
    • When there is a scene element node: c4d.BaseList2D in your Python code, for example a field layer, then there is somewhere in the memory of Cinema 4D a block which is the original C++ data, let's call the block MEM_CPP. The block is a ::BaseList2D (the C++ type), not a c4d.BaseList2D (the Python type).
    • What the Python wrapper now does, it creates a Python object for that C++ object (MEM_CPP), a c4d.BaseList2D at MEM_PY (your node) which points to that MEM_CPP for all its operations so that you can effectively drive the C++ object from Python.

    A 'not alive' node now means that the Python object lost its connection to the C++ object. I.e., it is what is commonly called a dangling pointer/reference. The Python object does not know anymore to whom to forward all the instructions its gets. There are cases where this makes sense or at least is obvious. When you have for example an async dialog and you get and store all objects in the scene in that dialog as a class attribute self._objects: list[c4d.BaseList2D] when it is opened. And then try to use that list over the lifetime of that dialog. It is obvious that this can go "out of whack" because they user could have simply deleted objects since he or she opened the dialog.

    But the somewhat uncomfortable reality is that Cinema 4D also reallocates scene elements a lot. So when you have an object "Cube" in your scene, you might look at it one second and it sits at the memory location X and then you look a second later at it and it suddenly sits at Y. For the user nothing really has changed but in memory happend what is somewhat equal to the user manually deleting the object and then recreating it from scratch with all its settings. The details of when and why this happens are irrelevant at the end of the day. In C++ this means that you should be cautious with pointers (as the object might have been deleted) and in Python this means that object can go "dead".

    You should always operate on fresh scene data. When you want to browse the field layers of some object in your scene, retrieve that object from the document for each time you want to browse the layers. In node plugins the retrieving part often becomes obsolete as we often get relevant nodes passed in for each call by Cinema 4D.

    With that all being said, there is definitively also some weirdness in the Python wrapper where things tend to die without a obvious reason why, especially when passing them out of functions. This can happen when the node which is being passed out is not yet attached to a document (there is probably some bug or at least design flaw in the Python wrapper). I also have seen problems with yielding (as opposed to returning).

    About your Questions

    1. No, this happening is generally not expected. But it depends a bit on the context of what you are doing. When the scene element which you are browsing the field layers for is not attached to a document, because you for example cloned the element, then I would still say this is a bug but I would not be surprised as this problem is not new. Can you share a bit more code and context of what you are doing?
      1. How are you calling the function?
      2. Is owner of node, i.e., the thing which has the FIELDS parameter, attached to a document?
      3. Do you clone stuff apart from your workaround?
      4. Most importantly, is this indeed a regression, i.e., can you demonstrate that the same code runs in a pre 2024.4 version?
    2. No, cloning is not the 'proper way', at least when we are somewhat strict. Cloning the node means that you create a copy. This not only costs performance as Cinema 4D has to duplicate all that memory, but more importantly any changes to such cloned field layer will not be propagated to your scene (because you work on a copy). When you just want to read data and do not mind some small performance penalty, this will technically work. But this is a hack and not "not nice code".
    3. From the context it sounds a bit like that the node is still alive when being yielded in your function, but then ends up dead on the side of the recipient who called that function (i.e., the very oddness/bug I talked about above).

    Without more context and code, it is hard to give a good answer here.

    I have forked this question because while the follow up question was absolutely okay there, this could get lengthy or might end up being flagged as a bug. And we are then better served with our own topic.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Drag Object in GeDialog.AddEditText

    Hey @pyxelrigger,

    sure you can use the string custom GUI. You could also use a base link or a filename field which be the more natural solutions for this. But you asked for AddEditText and that is what I answered.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Drag Object in GeDialog.AddEditText

    Hello @pyxelrigger,

    Thank you for reaching out to us. Please share your code in the future, especially when you have a demo. In the days of AI it is not that time consuming anymore to pump out a basic setup, but it still costs me time to write the query to ask the AI to write me a GeDialog with an edit field in it and then fix the little mistakes the AI makes.

    What you want to do is not directly possible. The edit field of a dialog does not support drag and drop events for scene elements. You are comparing it with the multiline edit of the console and with a string parameter in a description, which are both entirely different things.

    What you can do, is implement the drag handling yourself. At least to some degree. You cannot mimic the drag-and-drop mouse cursor because the edit field over-rules you there. You can only set the drag cursor when you implement the gadget yourself. You could implement for example a text field with a GeUserArea which lets you both type and drag, and then also displays the correct drag cursor.

    Here is a quick and dirty version, which simply handles the drag event on a dialog level.

    Cheers,
    Ferdinand

    Result

    4d4b7b45-1969-4018-94b7-5f72f1c60cce-image.png

    Code

    """Demonstrates how to handle drag events in a GeDialog.
    """
    import c4d
    from c4d import gui
    
    class MyDialog(gui.GeDialog):
        """A simple dialog that displays a text edit field.
        """
        ID_TEXTEDIT: int = 1000
    
        def CreateLayout(self) -> bool:
            """Called by Cinema 4D to let the dialog populate its controls.
            """
            self.SetTitle('My Dialog')
            self.AddEditText(MyDialog.ID_TEXTEDIT, c4d.BFH_SCALEFIT, 200, 26)
            return True
    
        def InitValues(self) -> bool:
            """Called by Cinema 4D to let the dialog initialize its controls.
            """
            self.SetString(MyDialog.ID_TEXTEDIT, "Initial text")
            return True
    
        def Message(self, msg: c4d.BaseContainer, result: c4d.BaseContainer) -> bool:
            """Called by Cinema 4D to convey events to the dialog.
    
            We use it here to handle drag events.
            """
            # This is an on-going drag event, i.e., the user is actively dragging something over the 
            # dialog and the user is hitting the edit text field.
            if (msg.GetId() == c4d.BFM_DRAGRECEIVE and 
                self.CheckDropArea(MyDialog.ID_TEXTEDIT, msg, True, True)):
                # Set the cursor: Does not work because we do not own the gadget implementation, the 
                # edit text field overwrites our cursor.
                # self.SetDragDestination(c4d.MOUSE_POINT_HAND)
    
                # We unpack the drag data from the drag message. The drag data is a dictionary with two
                # keys: 'type' and 'object'. The 'type' key holds the type of the drag data (e.g., 
                # files). The 'object' key holds the actual drag data (e.g., a list of files).
                dragData: dict = self.GetDragObject(msg)
                dragType: int = dragData.get('type', c4d.NOTOK)
                dragObject: any = dragData.get('object', None)
                if dragType == c4d.NOTOK or dragObject is None:
                    return c4d.gui.GeDialog.Message(self, msg, result)
                
                text: str | None = None
    
                # An atom array (a C++ thing which does not exist in Python) is a list of scene elements.
                # Objects, tags, layers, shaders, materials, etc. are currently dragged over the dialog.
                if dragType == c4d.DRAGTYPE_ATOMARRAY:
                    text = (", ".join([obj.GetName() for obj in dragObject]) 
                            if len(dragObject) > 1 else dragObject[0].GetName())
                # Unknown file types, images, or scenes are currently dragged over the dialog.
                if dragType in (c4d.DRAGTYPE_FILES, c4d.DRAGTYPE_FILENAME_IMAGE, 
                                c4d.DRAGTYPE_FILENAME_OTHER, c4d.DRAGTYPE_FILENAME_SCENE):
                    dragObject = list(dragObject) if not isinstance(dragObject, list) else dragObject
                    text = (", ".join(dragObject) if len(dragObject) > 1 else dragObject[0])
                
                # We set the text in the edit text field when we had a valid drag event.
                if text is not None:
                    self.SetString(MyDialog.ID_TEXTEDIT, text)
    
            return c4d.gui.GeDialog.Message(self, msg, result)
    
    
    dialog: MyDialog = MyDialog()
    if __name__=='__main__':
        dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, xpos=-2, ypos=-2, defaultw=400, default=400)
    
    posted in Cinema 4D SDK
  • RE: Cannot copy BaseLink from one parameter to another in ShaderData Read in C4D 2024

    Hm,

    okay, so you say this Vray plugin node does not use disk level 0 in its 2024 version anymore? I did not check your registration call, my alarm bells just went off when I saw the 0 because even a 2023 Vray plugin should not have a disk level of zero. Given how well established VRay is, I would expect here at least a disk level of 1 or 2 for this particular node. Did you have major rewrite of Vray or has this node been particularly uneventful in its change history that it still had a disk level of 0 in 2023?

    And this is not about the disk level code you write in your code, but the branching Cinema 4D takes when there is a disk level of zero. A lot of code simply does not run when your current disk level is zero. But when you say your plugin has now a disk level of one, or that you generally increment your disk levels properly, this all does not really matter.

    The Tech team touched one part of the non-public underpinning of BaseLink for 2024. But I currently do not see how this could only impact links that are the values of orphaned parameters. Will have a look next week again.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Render Queue

    Hello @supermije,

    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: Asking Questions.

    About your First Question

    This forum is about development support, not end-user issues. Please use our Support Center for all end user issues.

    Cheers,
    Ferdinand

    posted in General Talk
  • RE: Post build event settings on windows and mac

    Hello @BruceC,

    Thank you for reaching out to us. There are as far as I know no options to add custom build events with the public project tool.

    For the source processor there are the sourceprocessor.buildevent files which contain the XML for the source processor build event. But for Xcode there is no equivalent and I doubt that you can extend this for VS in a manner that you can add your own event files, I would assume that the source processor event is hardcoded.

    When you really have to customize your projects in this manner, you have two options:

    1. Do it manually every time (not great, I know).
    2. Write yourself a wrapper around the source processor which fiddles with its output once it is done. So you run your wrapper which then runs the PT and after that pokes around in the project files to add your events.

    While 2. can probably be done reasonably fast with some knowledge about VS and Xcode project files, I would point out that the days of the source processor (at least in this form) are counted. I cannot give any ETAs here, but I would avoid putting time into custom project tool solutions, when you are not uncomfortable with this work-time becoming obsolete in a year or so. For me this would be three days. I could probably write "something" in that time, not sure though if it would be good enough for production, as these "tools" tend to cost more time than one plans for 😉 .

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Support for Material X?

    Hello @dgould,

    Thank you for reaching out to us. Unfortunately, your question has been off topic for the forum you have posted in. Please check the Forum Overview for an overview of the scope of the different forums.

    As a result, your posting has been moved into General Talk.

    Regarding your Posting

    The SDK team cannot make any statements about the roadmap of Cinema 4D. For questions about current and possibly future features of Cinema 4D, please reach out to us via our Support Center.

    Thank you for your understanding,
    Ferdinand

    posted in General Talk
  • RE: How to store BaseShader to HyperFile

    Hey @gheyret,

    okay, I had a brief look, and I could not get the shader deserialization to work either. Not sure why, I think I was passing the wrong disk level. This is too much of a complex problem as that I could answer this on the side, we will have a closer look after our company meeting.

    I would recommend to use c4d files in the mean time to store your shaders as materials in a file. Alternatively, you could also store them as assets if you want to get all fancy.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK