Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    How to use GenerateDragArray() with Node Editor?

    Cinema 4D SDK
    windows 2024 python
    3
    6
    723
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • DunhouD
      Dunhou
      last edited by

      Hi community,

      I want to simulate the drag and create a <Image> node inside node editor, like the picture below but from treeview, but If I use AddChild() it will automictically create a node when I select but not drag.

      How can I do this?

      drag.gif

          def GetDragType(self, root, userdata, obj: TreeViewBaseObject):
              if not userdata.prop["use_drag"]:
                  return c4d.NOTOK
              # this will crash
              # if c4d.IsCommandChecked(CID_NODE_EDITOR) and obj.asset_type == "image":
              #     return c4d.DRAGTYPE_FILENAME_IMAGE
              return c4d.DRAGTYPE_ATOMARRAY
      
          
          def GenerateDragArray(self, root, userdata, obj: TreeViewBaseObject):
              shader = c4d.BaseShader(c4d.Xbitmap) # basic shader
              shader[c4d.BITMAPSHADER_FILENAME] = obj.path
              elements = [shader]
      

      Cheers~
      DunHou

      https://boghma.com
      https://github.com/DunHouGo

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by

        Hi @Dunhou, sadly this is not possible out of the box, since the node Editor is a new dialog relying on a complete different technology then the old one. And this new UI does not use the same drag and drop architecture than the rest of Cinema 4D which is sadly not compatible between each other yet.

        I will ping the responsible developer to see if there is any workaround, but I doubt.

        In the meantime, you can manually create the texture node like so:

        import c4d
        import maxon
        
        # --- Temporary add NodeSpaceHelpersInterface.GetNodeSpaceData() 
        # This is going to be added in 2024.2 as maxon.NodeSpaceHelpersInterface.GetNodeSpaceData() --------------------------
        @maxon.interface.MAXON_INTERFACE_NONVIRTUAL(maxon.consts.MAXON_REFERENCE_STATIC, "net.maxon.nodes.interface.nodespacehelpers")
        class NodeSpaceHelpersInterface:
            
            @staticmethod
            @maxon.interface.MAXON_STATICMETHOD("net.maxon.nodes.interface.nodespacehelpers.GetNodeSpaceData")
            def GetNodeSpaceData(spaceId):
                pass
        # --- End of fix -----------------------------------------------------------------------------------
        
        
        
        def main() -> None:
            mat = doc.GetFirstMaterial()
            if not mat:
                return
            nMat = mat.GetNodeMaterialReference()
            
            # Get the first available nimbus ref
            nimbusRefs = nMat.GetAllNimbusRefs()
            if not nimbusRefs:
                raise ValueError("Cannot retrieve the nimbus ref for that node space")
            
            nimbusRef = nimbusRefs[0][1]
            
            graph = nimbusRef.GetGraph()
            if graph is None:
                raise ValueError("Cannot retrieve the graph of this nimbus ref")
        
            # Retrieve the nodespace id from the graph
            spaceContext = graph.GetRoot().GetValue(maxon.nodes.NODESPACE.NodeSpaceContext)
            nodeSpaceId = spaceContext.Get(maxon.nodes.NODESPACE.SPACEID)
            
            # Retrieve the nodespace data, and its default picture node with the associated port Id
            spaceData = NodeSpaceHelpersInterface.GetNodeSpaceData(nodeSpaceId)
            assetId = spaceData.Get(maxon.nodes.NODESPACE.IMAGENODEASSETID)
            portData = spaceData.Get(maxon.nodes.NODESPACE.IMAGENODEPORTS)
            outColorPortId = portData[0]      # The result port.
            inTexturePortId = portData[1]     # The URL of the input image.
            inStartFramePortId = portData[2]  # The index of the starting frame.
            inEndFramePortId = portData[3]    # The index of the ending frame.
            
            # Add a new default Texture Node, as a Drag and Drop operation will perform
            texturePath = maxon.Url(r"C:\Users\m_adam\Desktop\maxon_logo.jpg")
            with graph.BeginTransaction() as transaction:
                newNode = graph.AddChild(maxon.Id(), assetId)
                
                # We need to convert the NodePath to a string, this is a bug that is going to be fixed in 2024.2
                inTexturePort = newNode.GetInputs().FindChild(str(inTexturePortId))
                inTexturePort.SetDefaultValue(texturePath)
                outColorPort = newNode.GetOutputs().FindChild(str(outColorPortId))
                
                transaction.Commit()
        
        
        
        if __name__ == '__main__':
            main()
        

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        DunhouD 1 Reply Last reply Reply Quote 0
        • DunhouD
          Dunhou @m_adam
          last edited by

          Thanks for you answer @m_adam, I wonder what is the difference between this SpaceData and just use AddChild method, I test it and looks like AddChild().

          Cheers~
          DunHou

          https://boghma.com
          https://github.com/DunHouGo

          1 Reply Last reply Reply Quote 0
          • M
            m_adam
            last edited by

            Hi sorry for the delay, spaceData in my code represent a maxon.DataDictionary or maxon equivalent of a python dict. Which have the duty to store various information about a certain nodespace, like which asset need to be used as texture node, which asset id should be used as end node, etc...
            So with that's said I do not really understand your question, as AddChild is a method to create a new node within a graph, so for me it's 2 unrelated thing.

            Cheers,
            Maxime.

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

            ferdinandF 1 Reply Last reply Reply Quote 1
            • ferdinandF
              ferdinand @m_adam
              last edited by ferdinand

              Hey @Dunhou, @m_adam,

              sorry for jumping in here. What Maxime glanced a bit over (because he is so deep in the subject matter as a Nodes Team member), is the purpose of what he is doing there; which might have led to confusion.

              The Nodes API uses the concept of a node space. It works similar to the concept of a space in math, as for example the idea of a vector space. Just as for the mathematical concept, a node space defines sets of legal operands, i.e., which nodes you can use when you create a node graph for this space.

              In his example, Maxime is retrieving the node space ID for a given graph and then accesses information which is tied to that node space (normally NodeSpaceInterface, but Maxime is using here a helper data structure instead). A NodeSpaceInterface has multiple functions, and one of them is storing the settings for that node space, the so called 'space data'. One thing one can find in these space data, is the definition of the so called IMAGENODEASSETID. This is the ID of the node which is used in this node space to express a texture/bitmap. If you want to know more details, you can have a look at this C++ manual.

              So, in short, what Maxime is doing here, is he is abstractly retrieving the template(i.e., type) ID of the node which is used in the node space of a given graph to represent a texture (and also port information). This has the advantage that his code will work for any node space (i.e., render engine). But you could also just hardcode that info and then could just use AddChild. But in this case you would have to at least check if the given graph is part of the node space you are targeting (which would be stored in spaceContext).

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              DunhouD 1 Reply Last reply Reply Quote 2
              • DunhouD
                Dunhou @ferdinand
                last edited by

                Thanks for that @ferdinand @m_adam ,

                yes, Ferdinand is right, Maxime's point is too "pro" for me, and with some maxon decorators I never used in some way mess me up, with Ferdinand's "rookie" like explain that I can understand this more, thanks for your both respected work.

                Cheers~
                DunHou

                https://boghma.com
                https://github.com/DunHouGo

                1 Reply Last reply Reply Quote 1
                • First post
                  Last post