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. dskeithbuck
    3. Posts
    • Profile
    • Following 0
    • Followers 0
    • Topics 13
    • Posts 35
    • Best 8
    • Controversial 0
    • Groups 0

    Posts made by dskeithbuck

    • RE: Modifying Scene On First Open or Before Save?

      @C4DS @kbar @ferdinand - Thank you so much for the in-depth responses.

      @kbar I'll see if I can get my employer to pony up for a license for Call Python as that seems like the simplest root. Although, this is potentially a light enough lift that I can finally make the transition into C++ development.

      @ferdinand Helpful to know that I won't be able to interrupt the save process (probably a good thing from the user POV).

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • Modifying Scene On First Open or Before Save?

      Hi!

      Is there a method to easily detect when a project is first created and then modify the document? Same for the moment just after the user has invoked the Save Command but before the document has actually saved?

      I'm hoping to apply custom settings on load (tweaking color parameters), and to perform a sanity check on the scene before saving (and possibly interrupt the save process if errors/issues are found).

      I'm thinking that some sort of MessageData plugin is the ticket, but I didn't find a message that is called on scene load/save.

      Other than that, I'm thinking that we can write custom scripts for loading/saving documents but I don't love that as it will require modifying keyboard shortcuts and still won't fix issues when someone drag & drops in assets to open them.

      Some sort of Node Data object might help w/ the saving/loading but we'd have to manually add it to projects.

      Thanks!

      Possibly Related?

      • Script Write to Annotation Tag on Save | PluginCafé
      • c4d.plugins.SceneSaverData — Cinema 4D SDK 24.111 documentation
      • Script Write to Annotation Tag on Save - Plugin Cafe Forums
      • SceneHookData Class Reference : Cinema 4D C++ SDK
      • Save Project As... new project name | PluginCafé
      posted in Cinema 4D SDK s24 python
      dskeithbuckD
      dskeithbuck
    • RE: Left-Hand Local Coordinates to Right-Hand Local Coordinates?

      Thank you @zipit and @m_magalhaes for your replies! @zipit your response put me on the right track. The issue was that I was trying to do all of the conversions using C4D's left-handed coordinate matrices, and it was auto-fixing my "malformed" matrices.

      I ended up porting the Three.js Matrix4 and Euler classes from JS to python and using them in my script.

      So, the final code (leaving out the ported methods) looked something like:

              mg = self.op.GetMg()
              parent_mg = self.op.GetUpMg()
      
              c4d_to_three = c4d.Matrix(
                  off=c4d.Vector(0),
                  v1=c4d.Vector(1, 0, 0),
                  v2=c4d.Vector(0, 1, 0),
                  v3=c4d.Vector(0, 0, -1)
              )
      
              # Convert to new coordinate space
              # http://www.techart3d.com/2016/02/convert-left-handed-to-right-handed-coordinates/
      
              mg_three_coords = c4d_to_three * mg * c4d_to_three
              parent_mg_three_coords = c4d_to_three * parent_mg * c4d_to_three
      
              mg_mat4 = Matrix4(mg_three_coords)
              parent_mg_mat4 = Matrix4(parent_mg_three_coords)
      
              inv_parent_mg_mat4 = parent_mg_mat4.Clone()
              inv_parent_mg_mat4 = inv_parent_mg_mat4.Inverse()
      
              node_local = inv_parent_mg_mat4.Clone()
              node_local = node_local.MultiplyMatrices(inv_parent_mg_mat4, mg_mat4)
      
              position, scale, rotation = node_local.Decompose()
      
              if position != c4d.Vector(0):
                  self.props["position"] = position
      
              if scale != c4d.Vector(1):
                  self.props["scale"] = scale
      
              if rotation != c4d.Vector(0):
                  self.props["rotation"] = rotation
      
      posted in General Talk
      dskeithbuckD
      dskeithbuck
    • Copying All Compatible Properties from One Object to Another?

      Hi,

      Is there a preferred way of copying all compatible object properties from an object of one type, to an object of another type? Things, I'm thinking of:

      • Name
      • Matrix
      • Layers
      • Visibility
      • Tags
      • Animation
      • Compatible Properties / Animation - So probably, PSR, but maybe also Visibility or Time Tracks, etc.

      I think I know how to approach this manually, but don't want to duplicate efforts if there's an API method, or existing snippet that does this as I'm afraid of leaving out something critical, and/or future proofing against future API additions.
      Thanks!

      Donovan

      posted in Cinema 4D SDK python s22
      dskeithbuckD
      dskeithbuck
    • RE: Best Practices for Reporting Errors to Users?

      @s_bach & @zipit - Thank you both for the thoughtful replies!

      I think I'll opt for the status bar for most user-facing feedback, and console logging for anything bigger. Watching the "What could possibly go wrong?" talk now.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • Best Practices for Reporting Errors to Users?

      Hi,

      I've been seeing a lot more usage of code like raise ValueError("Invalid path selected") in the Python examples. As I understand it, these errors tend to get surfaced in the Console - which is useful to developers, but less useful to Users.

      Here's a simple script that asks a user to select an image in a folder containing multiple images.

      import c4d
      
      def get_images_path():
          image_path = c4d.storage.LoadDialog(
              type=c4d.FILESELECTTYPE_IMAGES,
              title="Select an image in the folder you want to bulk rename",
              flags=c4d.FILESELECT_LOAD
          )
          
          if not image_path:
              raise ValueError("Valid image path not selected.")
          
          return image_path
      
      def main():
          images_path = get_images_path()
          
          c4d.gui.MessageDialog(images_path)
      
      if __name__=='__main__':
          main()
      

      How should I gracefuly accept a user hitting "Cancel"? How should I provide the user with a helpful error if they've selected the wrong filetype (let's for example pretend I'm looking for .png files rather than misc image formats)?

      Should we use popup messages? Status bar updates? Console prints?

      Do I need to do something like:

      try:
          images_path = get_images_path()
      except ValueError as error:
          c4d.gui.MessageDialog(error)
      

      ...every time I call any method that might throw an error? Or is there a way to auto-promote exceptions/errors as alert dialogs/status updates?
      Thanks,

      Donovan

      posted in Cinema 4D SDK python
      dskeithbuckD
      dskeithbuck
    • Selecting Objects in Order

      I encountered what I believed was a bug in doc.SetActiveObjects(object, c4d.SELECTION_ADD). The objects that I selected would return a different order than I expected when I used doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER|c4d.GETACTIVEOBJECTFLAGS_CHILDREN).


      Here's the bug report I wrote up:

      Issue

      doc.SetActiveObject() does not seem to track object selection order.

      To Reproduce

      1. Create a new project file.
      2. Add 3 cubes: A, B, C
      3. Select them in order: A, B, C
      4. Create a new script, and paste this in:
      """Name-en-US: Print and Reverse Selection
      Description-en-US: Prints the names of all objects in the order they were selected. Then attempts to reverse selection order.
      """
      
      import c4d
      from c4d import gui
      
      def main():
          # Get Active Objects
          active_objects = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER|c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
          if not active_objects:
              return
          
          # Collect the names of all objects, deselect as you go.
          names = []
          for obj in active_objects:
              names.append(obj.GetName())
              doc.SetActiveObject(obj, c4d.SELECTION_SUB)
          
          # Print the name of the objects based on their initial selection order.
          print names
          
          # Reselect the objects in reverse order
          for obj in reversed(active_objects):
              doc.SetActiveObject(obj, c4d.SELECTION_ADD)
          
          # Let C4D know something has changed
          c4d.EventAdd()
      
      if __name__=='__main__':
          main()
      
      1. Run this script.

      The console prints: ['a', 'b', 'c']

      1. Run this script again.

      BUG: The console again prints: ['a', 'b', 'c']

      EXPECTED: The console prints the new reverse selection order. ['c', 'b', 'a']

      Reference

      Documentation

      • c4d.documents.BaseDocument — Cinema 4D SDK 21.026 documentation

      Related Posts

      • active Objects SELECTIONORDER | PluginCafé
      • Adding to document selection issue | PluginCafé
      • selection order and shift-select | PluginCafé

      Turns out, it isn't a bug, but is instead a documentation issue. By calling doc.GetActiveObject() after each selection (as described here) you can update the selection caches and the selection order will appropriately update.

          # Reselect the objects in reverse order
          for obj in reversed(active_objects):
              doc.SetActiveObject(obj, c4d.SELECTION_ADD)
              
              # Update selection caches, needed if you want to use SELECTIONORDER
              # Reference: https://developers.maxon.net/forum/topic/9307/12387_adding-to-document-selection-issue/3
              doc.GetActiveObject()
      

      Request

      Please add this information to the doc.SetActiveObject, doc.SetSelection, and doc.GetActiveObjects sections of the Python and C++ documentation, and mention it as a possible fix for the Shift Select bug which I've encountered previously.

      Thank you,

      Donovan

      posted in Cinema 4D SDK python
      dskeithbuckD
      dskeithbuck
    • RE: Styling BitmapButtons

      @zipit said in Styling BitmapButtons:

      While I cannot say much about your problem, here are some bits that you might (or might not) find useful.

      Thank you for taking the time to respond!

      1. Have you tried / is it possible for your task to define your dialog resource as a file system rather than by code?

      My interface includes a large list of dynamic elements. I'm not sure that I'll be able to give each a unique ID unless I create them with code. But I'll see if I can restructure at least some of this.

      Although I cannot find the exact passage right now, it says somewhere in the docs, that you should use files, since it is the only way to get all features, except for menus, which are only constructable by code.

      Gotcha. Good to know. The docs have really improved, but there's lots of little tidbits like this that you'll only see if you read every page of every parent class rather than seeing all of the relevant info in the method definition.

      1. I came to the (unconfirmed) conclusion, that some of the more exotic CustomGui data types are apparently not fully supported for dialog resources (the same definition for a SPLINE gadget worked just fine in a description resource) and wrote my own little thing.

      Ah. That makes sense as well. I think for now I'll live with the stylistic limitations of the current BitmapButton as it's easier than writing my own.
      Thanks!

      Donovan

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • Styling BitmapButtons

      Hi,

      I'm hoping to add some Bitmap Buttons to a project I'm working on, but I'm having difficulty styling them (and initially: creating them).

          def AddIconButton(self, button_id, title, icon_id, tooltip, border=c4d.BORDER_ROUND):
              """
              Reference: https://developers.maxon.net/forum/topic/11462/understanding-setcommanddragid/2
              """
      
              bc = c4d.BaseContainer()
              bc.SetBool(c4d.BITMAPBUTTON_BUTTON, True)
              bc.SetInt32(c4d.BITMAPBUTTON_ICONID1, icon_id)
              bc.SetInt32(c4d.BITMAPBUTTON_OUTBORDER, border)
              bc.SetString(c4d.BITMAPBUTTON_TOOLTIP, tooltip)
              bc.SetString(c4d.BITMAPBUTTON_STRING, title)
              icon_width_height = 24
              bc.SetInt32(c4d.BITMAPBUTTON_FORCE_SIZE, icon_width_height)
              button = self.AddCustomGui(button_id, c4d.CUSTOMGUI_BITMAPBUTTON, title, c4d.BFH_LEFT, 0, 0, bc)
      
              return button
      

      A lot of the styling flags seem to have no impact. Specifically:

      • BITMAPBUTTON_BORDER
      • BITMAPBUTTON_STRING

      I created some simple test code to show each of the styles and the buttons looked identical:

      
              bitmapbutton_border_styles = [("BORDER_NONE", c4d.BORDER_NONE),
              ("BORDER_THIN_IN", c4d.BORDER_THIN_IN),
              ("BORDER_THIN_OUT", c4d.BORDER_THIN_OUT),
              ("BORDER_IN", c4d.BORDER_IN),
              ("BORDER_OUT", c4d.BORDER_OUT),
              ("BORDER_GROUP_IN", c4d.BORDER_GROUP_IN),
              ("BORDER_GROUP_OUT", c4d.BORDER_GROUP_OUT),
              ("BORDER_OUT2", c4d.BORDER_OUT2),
              ("BORDER_OUT3", c4d.BORDER_OUT3),
              ("BORDER_BLACK", c4d.BORDER_BLACK),
              ("BORDER_ACTIVE_1", c4d.BORDER_ACTIVE_1),
              ("BORDER_ACTIVE_2", c4d.BORDER_ACTIVE_2),
              ("BORDER_ACTIVE_3", c4d.BORDER_ACTIVE_3),
              ("BORDER_ACTIVE_4", c4d.BORDER_ACTIVE_4),
              ("BORDER_GROUP_TOP", c4d.BORDER_GROUP_TOP),
              ("BORDER_ROUND", c4d.BORDER_ROUND),
              ("BORDER_SCHEME_EDIT", c4d.BORDER_SCHEME_EDIT),
              ("BORDER_SCHEME_EDIT_NUMERIC", c4d.BORDER_SCHEME_EDIT_NUMERIC),
              ("BORDER_OUT3l", c4d.BORDER_OUT3l),
              ("BORDER_OUT3r", c4d.BORDER_OUT3r),
              ("BORDER_THIN_INb", c4d.BORDER_THIN_INb),
              ("BORDER_MASK", c4d.BORDER_MASK),
              ("BORDER_TEXT_DOTTED", c4d.BORDER_TEXT_DOTTED),
              ("BORDER_WITH_TITLE_MONO", c4d.BORDER_WITH_TITLE_MONO),
              ("BORDER_WITH_TITLE_BOLD", c4d.BORDER_WITH_TITLE_BOLD),
              ("BORDER_WITH_TITLE", c4d.BORDER_WITH_TITLE)]
      
              for border_id_name, border_id in bitmapbutton_border_styles:
                  self.AddIconButton(0, border_id_name, ICON_NEW_PROJECT, border_id_name, border=border_id)
      

      Ideally, I'd love a button that matches the look/feel of docked icons w/ text:
      69f1aaa2-626f-4699-9e3e-ef2e4290bff1-image.png

      Any suggestions?

      Also, FWIW, some sample code for how to add BitmapButtons inside of the BitmapButton class would be really helpful. I struggled for quite a while trying to create a button using c4d.gui.BitmapButtonCustomGui() but was stumped when I couldn't figure out how to add it to a dialog.
      Thank you,

      Donovan

      posted in Cinema 4D SDK python
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @m_adam said in Distributing Python Plugins that have Dependencies:

      As an Idea but didn't try and will not have the time to do it today (so if you try, do it at your own risks), but you could try to install things using directly the python executable from the resource folder

      I'm moving onto different parts of development, but I'll likely want to investigate this later and will post an update if I do. Thanks!

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @m_adam said in Distributing Python Plugins that have Dependencies:

      While I know is not the perfect solution, and is a really quick and dirty I would say find bellow a script to setup a build with some python module.

      Hi Maxime,

      Your script got me most of the way there, but I ran into some issues.

      It installs libraries to the default location for system python libraries rather than C4D's lib folder. So, I started modifying it to install to userprefs/python27/lib using the --target flag. But I ran into issues with spaces in the pathname. Which led me to switch to calling with a list of commands/parameters rather than a string.

      After some tweaking, I arrived at this:

      """Install C4D Python Modules
      Installs python modules in C4D's embedded python installation
      
      ## Authors
      
      Maxime of Maxon Computer
      Donovan Keith of Buck Design
      
      Reference:
      https://developers.maxon.net/forum/topic/11775/distributing-python-plugins-that-have-dependencies/8
      
      ## Requirements
      
      Cinema 4D R21+
      
      ## Usage Instructions
      
      1. Copy this file onto your desktop.
      2. Open `terminal` (Mac OS) or `cmd` (Windows) and navigate to your Cinema 4D installation.
      3. `$ c4dpy`
          1. This will run a Cinema 4D specific version of python.
          2. If prompted to login, do so.
          3. If you get an HTTP/authentication error:
              1. Open Cinema 4D.
              2. Edit > Preferences and click on "Open Preferences Folder"
              3. Go up one level in finder/explorer.
              4. Look for a folder with the same name and a `_p` suffix.
              5. Delete this folder.
              6. Try running `c4dpy` again from the console.
      4. Exit the interactive python session by typing `exit()`
      5. Run this script.  
      `>>> c4dpy "/path/to/this/script/install_c4dpy_modules.py"`
      
      ## Known Limitations
      
      1. Hasn't been tested on Mac OS
      2. Is checking the `c4dpy` installation for whether a python module has been installed, but is installing in the `c4d` installation.
      
      """
      
      print "C4D Py Requirements Installer"
      
      import subprocess
      import urllib
      import sys
      import c4d
      import os
      import ssl
      import shutil
      import importlib
      import maxon
      
      currentDir = os.path.dirname(__file__)
      c4dpyPath = sys.executable
      c4dpyTempFolder = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_STARTUPWRITE)
      
      # Because we're using `c4dpy`, it will pull a different prefs folder from the user's c4d installation.
      # `Maxon Cinema 4D R21_64C2B3BD_p` becomes `Maxon Cinema 4D R21_64C2B3BD`
      c4dTempFolder = c4dpyTempFolder[:-2] if c4dpyTempFolder.endswith("_p") else c4dpyTempFolder
      
      c4dDir = maxon.Application.GetUrl(maxon.APPLICATION_URLTYPE.STARTUP_DIR).GetPath()
      if os.name != "nt" and not c4dDir.startswith(os.sep):
          c4dDir = os.sep + c4dDir
      
      # Just using the `--user` flag with `pip` will install to the System python dir, rather than the
      # C4D embedded python's dir. So we specify exactly where we want to install.
      c4dUserPythonLibPath = os.path.join(c4dTempFolder, "python27", "libs")
      
      try:
          import pip
          print "pip already installed"
      except ImportError:
          print('start downloading get-pip.py')
      
          url = 'https://bootstrap.pypa.io/get-pip.py'
          pipPath = os.path.join(c4dTempFolder, "get-pip.py")
      
          # Quick hack for MAC until https://developers.maxon.net/forum/topic/11370/urllib2-urlopen-fails-on-c4d-for-mac/8 is fixed
          f = os.path.join(c4dDir, "resource", "ssl", "cacert.pem")
          context = ssl.create_default_context(cafile=f)
      
          # Downloads pip
          urllib.urlretrieve(url, pipPath, context=context)
      
          print('start installing pip')
      
          if os.name == "nt":
              subprocess.call([c4dpyPath, pipPath, "--no-warn-script-location", "--user"], shell=True)
          else:
              os.system("{0} {1} {2} {3}".format(c4dpyPath, pipPath, "--no-warn-script-location", "--user"))
      
          shutil.rmtree(pipPath, ignore_errors=True)
      
      def installModule(moduleName):
          try:
              importlib.import_module(moduleName)
              print "{0} already installed".format(moduleName)
          except ImportError:
      
              try:
                  print('start installing {0}'.format(moduleName))
      
                  # We build up the command as list rather than a string so that Windows will properly handle paths that include spaces
                  cmd = [c4dpyPath, '-m', 'pip', 'install', moduleName, '--target', c4dUserPythonLibPath]
                  subprocess.call(cmd)
              except subprocess.CalledProcessError as e:
                  print e.output
              else:
                  print('{0} installation is done'.format(moduleName))
      
      # Add any modules you want installed to this list.
      required_modules = ["requests"]
      
      for module in required_modules:
          installModule(module)
      
      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @m_adam It's a _p suffix. Deleting it eliminated the error messages and allowed me to log in. Thank you!

      Is there any chance that c4dpy.exe can get its license from the C4D installation without having to manually enter it in the command prompt? It's not too much of an issue for me, but I imagine seeing the terminal will be a bit intimidating for end users.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @m_adam said in Distributing Python Plugins that have Dependencies:

      Just call c4dpy file.py.

      I'm not having much luck running or calling c4dpy in R21.

      Microsoft Windows [Version 10.0.17763.737]
      (c) 2018 Microsoft Corporation. All rights reserved.
      
      C:\Users\donovan>cd "C:\Program Files\Maxon Cinema 4D R21"
      
      C:\Program Files\Maxon Cinema 4D R21>c4dpy
      Error running authentication: invalid http response 400.  (https://id.maxon.net/oauth2/access?scope=openid+profile+email&grant_type=refresh_token&refresh_token=[[REDACTED]]&client_secret=[[REDACTED]]) [http_file.cpp(313)]
      ----
      Enter Maxon Account Settings (ENTER to keep input):
      License Check error: invalid http response 400.  (https://id.maxon.net/oauth2/access?scope=openid+profile+email&grant_type=refresh_token&refresh_token=[[REDACTED]]&&client_id=[[REDACTED]]&client_secret=[[REDACTED]]) [http_file.cpp(313)]
      Error: Invalid License
      

      I'm able to open Cinema 4D and don't have any licensing issues there. I also did a complete uninstall/reinstall of C4D and had the same issues.

      Thank you for writing that script, it seems like it will do the trick if I can get c4dpy to run.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: HTTP Requests with `maxon` API

      @m_adam said in HTTP Requests with `maxon` API:

      Hi @dskeithbuck thanks a lot for trying to use the new Maxon API.

      Thank you so much for the working sample code, that answers my question. I look forward to switching over to the Maxon API for URL requests once these kinks get worked out.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: HTTP Requests with `maxon` API

      @zipit said in HTTP Requests with `maxon` API:

      I also don't think that your code does establish a connection as you said.

      Perhaps you're right, I tried a bunch of different things before landing here. With one of my tests I was getting a 404 error which implied that network requests were being made.

      May I also ask why you are not using pythons own urllib? While its reputation is (rightfully) somewhat bad, it certainly will be enough to fetch some JSON.

      I'm connecting to a localhost server being run by another application. As I understand it urllib creates a brand new HTTP connection every time I pass data back and forth which is leading to some unfortunate latency. The requests library can make a connection that stays open and all future transactions are much faster.

      I'm hoping to install this plugin cross-platform on a large number of machines and I want to avoid trying to package requests and all of its dependencies if possible which is why I was excited to see that the maxon API seemed to have some of the same abilities as requests.
      Thanks for taking a look!

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • HTTP Requests with `maxon` API

      Hi,

      As mentioned in this thread I'm looking to bring JSON data into Cinema 4D via HTTP GET request. I noticed in the C++ docs that there's a NetworkHttpHandlerInterface Class. I also noticed in the python docs that the maxon API implements a url type.

      What's the state of these implementations and can they be used to make a connection to an HTTP server and request data? I think I've managed to successfully connect to a remote server, but I can't figure out how to read the data or make more specific requests.

      """Name-en-US: Simple HTTP Requests
      Description-en-US: Prints the result of connecting to wikipedia.org
      """
      
      import c4d
      from c4d import gui
      
      import maxon
      
      def main():
          url = maxon.Url("https://www.wikipedia.org/")
          connection = url.OpenConnection()
          print connection
      
      
      if __name__=='__main__':
          main()
      

      If it's possible, could someone share some example code for how to use the maxon API to print the results of an HTTP GET request in python. If it's not yet possible, may I request that it be added to the SDK?
      Thank you,

      Donovan

      posted in Cinema 4D SDK python
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @m_adam Thanks, I'll have a look at pip and/or an installer script. I'm a bit concerned about adding anything directly to the resource/modules/python/libs folder as there's a chance some other plugin or script will have installed/need a different version of the same library. But, I suppose that I can report this as an installation error to the user and let them sort out which is more important for them to have installed.

      I'll be sure to let you know if I come to a resolution.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • RE: Distributing Python Plugins that have Dependencies

      @zipit Request's dependency chain isn't too bad, but a couple of those libraries also have dependencies which is where it starts to get a little ugly. I'll give it another go.

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • Distributing Python Plugins that have Dependencies

      I'm working on a python plugin that will rely on HTTP communication in order to ingest/export data. My research has led me to the requests python library. Unfortunately, it's not part of the standard Python library so I'll need to import it.

      I've found my way to Niklas Rosenstein's localimport module and the minified version I can drop at the top of a *.pyp file in order to import a library without polluting the global sys.modules.

      This works great if I'm importing 1 or 2 simple python modules, however requests has a number of dependencies on other python modules, each of which is dependent on yet another set of python modules. This would be easy enough if I was the only person that needed this plugin. I'd just use pip to automatically download and install of the dependencies in a requirements.txt. However, I can't easily do that with C4D's embedded python installation, and I'm certain I can't trust most end users to do the same.

      I assume not, but is there a simple way to setup something like a virtualenv with C4D's python installation that automatically downloads and installs all modules my plugin needs without polluting the global sys.modules? I've tried installing all of the dependencies on my machine's python installation and then copying them into ./res/modules and then using localimport but I run into a recursion depth error.

      Any suggestions or workarounds would be greatly appreciated.
      Thanks,

      Donovan

      posted in Cinema 4D SDK
      dskeithbuckD
      dskeithbuck
    • Getting the State of Modifier Keys (ctrl/cmd, shift, alt)

      This is a snippet I like to use for easily accessing the state of modifier keys when a user runs a script. I figured I would post it here as I couldn't easily track it down when I needed it today and thought it might be useful to other folks as well.

      def get_modifiers():
          """Returns state of modifier keys: ctrl, shift, alt
          
          Example Usage:
          ctrl, shift, alt = get_modifiers()
          """
      
          bc = c4d.BaseContainer()
          if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc):
              ctrl = bc[c4d.BFM_INPUT_QUALIFIER] & c4d.QCTRL
              shift = bc[c4d.BFM_INPUT_QUALIFIER] & c4d.QSHIFT
              alt = bc[c4d.BFM_INPUT_QUALIFIER] & c4d.QALT
              
          return ctrl, shift, alt
      
      posted in General Talk python
      dskeithbuckD
      dskeithbuck