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
    • Login
    1. Maxon Developers Forum
    2. LingZA
    3. Topics
    L
    • Profile
    • Following 1
    • Followers 0
    • Topics 16
    • Posts 25
    • Best 2
    • Controversial 0
    • Groups 0

    Topics created by LingZA

    • L

      Is there any way to get MMB wheel scrolling in viewport?

      Cinema 4D SDK
      • c++ python • • LingZA
      2
      0
      Votes
      2
      Posts
      457
      Views

      ferdinandF

      Hey @LingZA,

      Thank you for reaching out to us. There are multiple questions in this topic, which always makes things tricky to answer.

      Is there any way to stop MMB wheel to zoom the camera? I need to scroll the MMB wheel in the viewport to change my tool's params? Is there any way to get MMB wheel scrolling in viewport?

      In general, Cinema 4D has no input device control & emulation layer, so you cannot intercept an input device from sending (stop the mouse wheel to zoom) or emulate inputs (get the mouse wheel scrolling).

      You can get the state of an input device. For MMB that would be the GUI message BFM_INPUT with BFM_INPUT_DEVICE being BFM_INPUT_MOUSE and BFM_INPUT_CHANNEL being BFM_INPUT_MOUSEMIDDLE. When you fail to read BFM_INPUT_MOUSEMIDDLE in your plugin, please share executable code, so that we can reproduce the problem.

      When necessary, you can send code confidentially to us via sdk_support(at)maxon(dot)net.

      Cheers,
      Ferdinand

    • L

      How to dynamically change the "STEP"of "REAL" tool description in c++?

      Cinema 4D SDK
      • c++ • • LingZA
      2
      0
      Votes
      2
      Posts
      352
      Views

      i_mazlovI

      Hi @LingZA ,

      To achieve this in C++ you need to set DESC_STEP parameter of the corresponding BaseContainer, e.g. bc->SetFloat(DESC_STEP, 1.0f);.

      For getting the editable BaseContainer you need to use GetParameterI() function on your description, please refer to the Description Manual.

      Cheers,
      Ilia

    • L

      How to use GetChildren() in c++?

      Cinema 4D SDK
      • c++ • • LingZA
      3
      0
      Votes
      3
      Posts
      563
      Views

      L

      @ferdinand
      That is great! Thanks!

    • L

      How to press the "Apply" button in the DescriptionToolData?

      Cinema 4D SDK
      • c++ python • • LingZA
      2
      0
      Votes
      2
      Posts
      379
      Views

      ferdinandF

      Hello @LingZA,

      Thank you for reaching out to us. Thank you for posting your solution, much appreciated! I have provided below a variant of your example which without having the C++ Example Pick Object Tool installed.

      In case someone is wondering how to find out such a thing, you would have to look into the description of a tool, e.g. the extrude tool ...

      toolextrude.res:

      CONTAINER xbeveltool { NAME xbeveltool; GROUP MDATA_BEVEL_GROUP_OPTION { DEFAULT 1; LONG MDATA_BEVEL_MASTER_MODE // ... } INCLUDE ToolBase; // Includes the gadgets that are common to all description tools. }

      to find out that they all include all ToolBase which then looks like this:

      toolbase.res:

      CONTAINER ToolBase { NAME ToolBase; GROUP MDATA_MAINGROUP { DEFAULT 1; } GROUP MDATA_COMMANDGROUP { DEFAULT 1; GROUP { // SEPARATOR { LINE; } BOOL MDATA_INTERACTIVE { } SEPARATOR { } GROUP { COLUMNS 2; DEFAULT 1; BUTTON MDATA_APPLY { FIT_H; } BUTTON MDATA_NEWTRANSFORM { FIT_H; } } } } SUBCONTAINER ID_SNAPSETTINGS { } }

      Cheers,
      Ferdinand

      Code:

      """Actives and runs the extrude tool. """ import c4d ID_EXTRUDE_TOOL: int = 1011183 def main() -> None: c4d.CallCommand(ID_EXTRUDE_TOOL) tool = c4d.plugins.FindPlugin(ID_EXTRUDE_TOOL, c4d.PLUGINTYPE_TOOL) tool[c4d.MDATA_INTERACTIVE] = True c4d.EventAdd() if tool is not None: c4d.CallButton(tool, c4d.MDATA_APPLY) c4d.CallButton(tool, c4d.MDATA_NEWTRANSFORM) c4d.EventAdd() if __name__ == '__main__': main()
    • L

      Which are tool plugin flags for Brush Selection tool, even Move tool?

      Cinema 4D SDK
      • 2024 python • • LingZA
      5
      0
      Votes
      5
      Posts
      826
      Views

      i_mazlovI

      Hi @LingZA ,

      Sorry for the delayed answer.

      Could you please explain the result that you're trying to achieve?

      It looks now that you would like to implement a modeling tool similar to Bevel, when you would like to firstly select points/edges/polys and secondly apply some changes to them. If that's the case, then you need to implement the part of your tool that selects objects. Please have a look at BaseSelect. You can also explore Flatten Polygons example.

      You can find a sample code snippet below that simply selects all of the edges of the polygon. You need to be in "Edges" mode for that. Additionally you can emulate the polygon highlighting yourself.

      Regarding the flags:

      PLUGINFLAG_TOOL_EDITSTATES - designates that the tool supports deformed editing

      PLUGINFLAG_TOOL_SWITCHACTION - allows to adjust the active tool. This works in tandem with the MSG_TOOL_SWITCHACTION message type. Namely, when the modifier (aka qualifier) key is pressed, the plugin receives this message such that it can react on this key press.

      PLUGINFLAG_TOOL_NO_TOPOLOGY_EDIT - flag that informs cinema that the tool doesn't perform any topology modifications (i.e. doesn't add/remove/reassign of the polygons)

      PLUGINFLAG_TOOL_TWEAK - if you click on the element that isn't currently selected, it will select it for you (so your tool can work with this selection), and will deselect it once your tool finishes

      PLUGINFLAG_TOOL_TWEAK_NO_HIGHLIGHT - same as above but without highlighting the temporarily selected element

      PLUGINFLAG_TOOL_DRAW_MULTIPLANE - some legacy flag that is (or at least should be) deprecated

      Cheers,
      Ilia

      Cinema_4D_EZZRKgKU0Y.gif

      import c4d PLUGIN_ID = 1234321 # Be sure to use a unique ID obtained from www.plugincafe.com class MyTool(c4d.plugins.ToolData): def __init__(self): self.selectionRadius = 10 self.highlightedPolygon: int = -1 def GetState(self, doc): if doc.GetMode() != c4d.Medges: return False return c4d.CMD_ENABLED def MouseInput(self, doc, data, bd, win, msg): # Only handle left click if msg[c4d.BFM_INPUT_CHANNEL] != c4d.BFM_INPUT_MOUSELEFT: return True # Get active object op = doc.GetActiveObject() if not op: return True if self.highlightedPolygon < 0: return True # Initialize helping Neighbor struct nbr = c4d.utils.Neighbor() nbr.Init(op) polyInfo = nbr.GetPolyInfo(self.highlightedPolygon) # get polygon information bs = c4d.BaseSelect() opPolygon: c4d.CPolygon = op.GetPolygon(self.highlightedPolygon) # Iterate over sides for side in range(4): # Skip last edge if polygon is a triangle if side == 2 and opPolygon.c == opPolygon.d: continue # Select edge edgeIdx = polyInfo['edge'][side] bs.Select(edgeIdx) # Apply selection op.SetSelectedEdges(nbr, bs, c4d.EDGESELECTIONTYPE_SELECTION) c4d.EventAdd() return True def Draw(self, doc, data, bd, bh, bt, flags): selectionColor = c4d.GetViewColor(c4d.VIEWCOLOR_SELECTION_PREVIEW) if flags & c4d.TOOLDRAWFLAGS_HIGHLIGHT: # if the DrawPass is the Highlight one if self.highlightedPolygon >= 0: # Get active object op = doc.GetActiveObject() if not op: return True bd.SetMatrix_Matrix(op, op.GetMg()) # draw in global coordinates # Get points and polygon from the object opPoints: list[c4d.Vector] = op.GetAllPoints() opPolygon: c4d.CPolygon = op.GetPolygon(self.highlightedPolygon) points = [opPoints[idx] for idx in (opPolygon.a, opPolygon.b, opPolygon.c, opPolygon.d)] colors = [selectionColor for _ in points] if len(points) == 3 or len(points) == 4: bd.DrawPolygon(points, colors) # draw the polygon highlight # Draw the outline bd.SetPen(c4d.Vector(0, 1, 0)) for point1Idx in range(-1, len(points) - 1): point1, point2 = points[point1Idx], points[point1Idx + 1] bd.DrawLine(point1, point2, c4d.NOCLIP_D) return c4d.TOOLDRAW_HIGHLIGHTS def GetCursorInfo(self, doc, data, bd, x, y, bc): self.highlightedPolygon = -1 # If the cursor has left a user area, simply return True if bc.GetId() == c4d.BFM_CURSORINFO_REMOVE or doc.GetMode() != c4d.Medges: return True # Get active object op = doc.GetActiveObject() if not op: return True # Calculates the width and height of the screen bd: c4d.BaseDraw = doc.GetActiveBaseDraw() frame = bd.GetFrame() l, r, t, b = frame["cl"], frame["cr"], frame["ct"], frame["cb"] width, height = r - l + 1, b - t + 1 # Initialize viewport select vpSelect = c4d.utils.ViewportSelect() vpSelect.Init(width, height, bd, [op], c4d.Medges, True, c4d.VIEWPORTSELECTFLAGS_IGNORE_HIDDEN_SEL) c4d.SpecialEventAdd(c4d.EVMSG_UPDATEHIGHLIGHT) # pushing highlighting event to cinema # Looking for the nearest polygon and saving it's index in self.highlightedPolygon polyInfo = vpSelect.GetNearestPolygon(op, int(x), int(y), self.selectionRadius) if not polyInfo or 'i' not in polyInfo: return True polygonIdx = polyInfo['i'] if (polygonIdx < 0 or polygonIdx >= op.GetPolygonCount()): return True self.highlightedPolygon = polygonIdx return True if __name__ == "__main__": c4d.plugins.RegisterToolPlugin(id=PLUGIN_ID, str="MyTool", info=0, icon=None, help="", dat=MyTool())
    • L

      Undo for InsertUnder() is not right. Why?

      Cinema 4D SDK
      • python • • LingZA
      4
      0
      Votes
      4
      Posts
      627
      Views

      ferdinandF

      Thanks! Sorry, I am so careless that I ignore the message "Needs to be called before the change.".

      No worries, you are not the first one who trips over Undo call order, including myself at some point 😉

    • L

      Is it possible to change active view?

      Cinema 4D SDK
      • python • • LingZA
      2
      0
      Votes
      2
      Posts
      447
      Views

      ferdinandF

      Hello @lingza,

      Thank you for reaching out to us. In short, what you want to do is unfortunately not possible.

      To unpack things a bit, I understood your question as such that you have multiple view panels in your layout and each view panel contains multiple views. The screen below shows two view panels with four views each for example.

      Screenshot 2022-10-06 at 11.20.38.png

      You then want to toggle a view panel from showing all its views (depending on the panel layout) to singular one, e.g., "minimize and maximize" the Perspective view in the second panel. For that you wanted to use c4d.CallCommand(13640) and therefore need to set the active view (the view with the grey border).

      Internally, there is a non-public method called BaseDocument::SetActiveView which handles setting the selected viewport and one has more or less all tools in the Python SDK to replicate it (you more or less just have to set BIT_ACTIVE and send some messages). And while doing this will have some effect on the selection state of viewports, it will not be identical to what you can achieve with mouse interactions, and running then your CallCommand(13640) on such 'semi-selected' viewport will not have the desired effect.

      In the end, the viewport selection state is bound to a very specific call chain in our internal API. Which is probably the reason why the method BaseDocument::SetActiveView remains non-public.

      FYI: This is not a Python issue, the same applies to C++, I tried it there too, to the same effect.

      Cheers,
      Ferdinand

    • L

      Why does "Symbols Parser" not work?

      Cinema 4D SDK
      • python • • LingZA
      3
      0
      Votes
      3
      Posts
      527
      Views

      L

      Great!!! It runs.
      You are right. Thank you so much!
      I think your answer is worth being written in the API document to make the workflow more clear.

    • L

      How can I update the deformer when I move the objects in the viewport?

      Cinema 4D SDK
      • python • • LingZA
      3
      0
      Votes
      3
      Posts
      502
      Views

      ferdinandF

      Hello @lingza,

      Thank you for reaching out to us. There are in principle two ways how you can do this:

      Do not use an InExcludeData and make the dependencies of your deformer direct children of the deformer. A deformer will automatically be invoked when either the direct parent or children are modified. This is IMHO a much simpler solution, but you are of course restricted in where you can put these dependencies in a scene, as they must be children of the deformer. When you want to go with InExcludeData, you must overwrite ObjectData.CheckDirty to manually flag the deformer as dirty when necessary. You iterate over all objects in the InExcludeData and based on their dirty count decide if the deformer is dirty or not. Find a draft for the method at the end of my posting.

      Cheers,
      Ferdinand

      The result:
      modifierdirty.gif

      The code:

      def CheckDirty(self, op: c4d.BaseObject, doc: c4d.documents.BaseDocument) -> None: """Called by Cinema 4D to let a modifier flag itself as dirty. Args: op: The object representing the modifier hook. doc: The document containing the modifier. """ # When we want to track dependencies we must keep a cache for what we consider to be the # last no-dirty state of things. This could be done in many ways, I have chosen here a # dict of (bytes, int) tuples. # # The general idea is to store the last known dirty state data for each item in the # InExcludeData as such: # # { Object_A: 193, Object_B: 176, Object_C: 25, ...} # # But BaseList2d instances itself are not hashable, i.e., cannot be keys in a dict, and # doing something like `myDict[id(someObject)] = someValue` would be a really bad idea, # as objects are managed in the backend by Cinema 4D and can be reallocated all the time, # so id(myBaseList2d) is not a safe way to identify objects. Instead we are using # C4DAtom.FindUniqueID to get the unique MAXON_CREATOR_ID marker of each item and then # use that marker to store the dirty flags. # The dirty cache data structure attached to the plugin class and the InExcludeData parameter # in question. self._linklistDirtyCache: dict[bytes: int] data: c4d.InExcludeData = op[c4d.ID_LINKLIST] if not isinstance(data, c4d.InExcludeData): return # Now we iterate over all items in the InExcludeData to see if their dirty state has changed. isDirty: bool = False for i in range(data.GetObjectCount()): node: c4d.BaseList2D = data.ObjectFromIndex(doc, i) if not isinstance(node, c4d.BaseList2D): continue # Get the MAXON_CREATOR_ID unique ID of this node. mem: memoryview = node.FindUniqueID(c4d.MAXON_CREATOR_ID) if not isinstance(mem, memoryview): continue uuid: bytes = bytes(mem) # Get the current and cached dirty state of that item. currentDirtyCount: int = node.GetDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX) cachedDirtyCount: typing.Optional[int] = self._linklistDirtyCache.get(uuid, None) # When there is either no cache or the cache differs from the current value, we update # our cache and set isDirty to True. if (currentDirtyCount is None) or (cachedDirtyCount != currentDirtyCount): isDirty = True self._linklistDirtyCache[uuid] = currentDirtyCount # When isDirty is True, we flag ourselves as dirty, which will cause ModifyObject to be called. if isDirty: op.SetDirty(c4d.DIRTYFLAGS_DATA) print (f"Modifier has been set dependency dirty: {self._linklistDirtyCache.values()}")
    • L

      Is there a "msgId" when I add a child to an object?

      Cinema 4D SDK
      • python • • LingZA
      2
      0
      Votes
      2
      Posts
      345
      Views

      M

      Hi @LingZA there is not such event in Cinema 4D object system. Moreover if there would be one it will be on the Message method which is responsible to receive various event rather than GetDParameter which have the duty to override the value when C4DAtom.GetParameter is called.

      With that said the way to do that is to let Cinema 4D handle it for you, as Cinema 4D will call GetDDescription when it is needed. So you should check directly in GetDDescription if the object have a child. But it does not work when the attribute manager is locked with a specific object since GetDDescription is called only at the beginning when the object should be displayed. So to workaround this issue you can set the description of the object to be dirty, this will force Cinema 4D to update the description and therefor call GetDDescription.

      A concrete example bellow where a Float parameter is added if there is no child

      class DynamicParametersObjectData(c4d.plugins.ObjectData): def __init__(self): self.has_children = False def GetDDescription(self, node, description, flags): """Called by Cinema 4D when the description (UI) is queried. Args: node (c4d.GeListNode): The instance of the ObjectData. description (c4d.Description): The description to modify. flags: return: The success status or the data to be returned. Returns: Union[Bool, tuple(bool, Any, DESCFLAGS_DESC)]: The success status or the data to be returned. """ # Loads the parameters from the description resource before adding dynamic parameters. if not description.LoadDescription(node.GetType()): return False # If there is a child just return and don't add the float parameter if node.GetDown(): return True # Add a Float Parameter bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_REAL) bc.SetString(c4d.DESC_NAME, "Dynamic REAL") descid = c4d.DescID(c4d.DescLevel(1100, c4d.DTYPE_REAL, node.GetType())) description.SetParameter(descid, bc, c4d.DescID(c4d.DescLevel((c4d.ID_OBJECTPROPERTIES)))) # After dynamic parameters have been added successfully, return True and c4d.DESCFLAGS_DESC_LOADED with the input flags return True, flags | c4d.DESCFLAGS_DESC_LOADED def GetVirtualObjects(self, op, hh): """This method is called automatically when Cinema 4D ask for the cache of an object. Args: op (c4d.BaseObject): The Python Generator c4d.BaseObject. hh (c4d.HierarchyHelp): Not implemented. Returns: c4d.BaseObject: The newly allocated object chain, or None if a memory error occurred. """ if op is None or hh is None: raise RuntimeError("Failed to retrieve op or hh.") # Force Cinema 4D to call GetDDescription and therefor update the description if there is a child and the saved state is not in sync with scene state has_children = bool(op.GetDown()) if (self.has_children) != has_children: op.SetDirty(c4d.DIRTYFLAGS_DESCRIPTION) self.has_children = has_children returnObj = c4d.BaseObject(c4d.Osphere) if returnObj is None: raise MemoryError("Failed to create a sphere.") return returnObj if __name__ == "__main__": c4d.plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="Py-DynamicParametersObject", g=DynamicParametersObjectData, description="opydynamicparametersobject", icon=c4d.bitmaps.InitResourceBitmap(c4d.Onull), info=c4d.OBJECT_GENERATOR)

      Cheers,
      Maxime.

    • L

      Is there a fixed Manager ID like c4d.CONSTANT?

      Cinema 4D SDK
      • python • • LingZA
      2
      0
      Votes
      2
      Posts
      252
      Views

      ManuelM

      Hi,

      Those IDs should not change but there are not guaranties. There are no symbols to define those IDs.

      You can use the following code to displays all the registered Managers.

      import c4d from c4d import gui def main(): pluginList = c4d.plugins.FilterPluginList(c4d.PLUGINTYPE_MANAGERINFORMATION, True) for plugin in pluginList: print (plugin, plugin.GetID()) # Execute main() if __name__=='__main__': main()

      Cheers,
      Manuel

    • L

      Is there a successful example of c4d.gui.SplineCustomGui?

      Cinema 4D SDK
      • python • • LingZA
      3
      1
      Votes
      3
      Posts
      633
      Views

      L

      @m_adam
      Thanks so much!
      You are a very professional guy!!!

    • L

      How can I set a selection after I create a selection tag?

      Cinema 4D SDK
      • python • • LingZA
      3
      0
      Votes
      3
      Posts
      496
      Views

      ferdinandF

      Hello @LingZA,

      without any further questions or other postings, we will consider this topic as solved and flag it as such by Friday, 17/06/2022.

      Thank you for your understanding,
      Ferdinand

    • L

      How can I create a tag which has same outputs as Vertex Map tag?

      Cinema 4D SDK
      • python • • LingZA
      4
      0
      Votes
      4
      Posts
      547
      Views

      ferdinandF

      Hello @lingza,

      well as lined out, you cannot implement a VertexmMapTag which is the same as a normal VertexMapTag but has extra parameters to realize your desired functionality.

      You can solve this problem with either the pattern I described under point 3 in my last posting, or by implementing a ToolData plugin which simply generates the tag. The solution using a driver tag has the advantage that the user can continuously tweak the output of the vertexmap, while a tool must be picked up again.

      Actually, I mean that I want to create a tag which contains the vertex weights, then vertex weights are used by ZRemesher after I put the tag into Density Map linkbox.
      So I don't need a "vertex map" indeed, but I need a tag I describe above.

      This is unfortunately not true. You will need a vertex map tag, as this parameter, the Density Map parameter, will accept only a VertexMapTag. It will not know what to do with a CustomDataTag . I would recommend having a look at the project file I have posted above, it contains a practical example for the pattern of a tag driving a vertex map.

      Cheers,
      Ferdinand

    • L

      How can get the visibility of the every point/edge/face?

      Cinema 4D SDK
      • python • • LingZA
      3
      0
      Votes
      3
      Posts
      509
      Views

      L

      Thanks so much!!!

      Your answer makes me understand that PolygonObject.GetPolygonS(self) and PolygonObject.GetPolygonH(self) respectively represent selection states in a list from BaseSelect and visibility states in a list from BaseSelect.