So far we already covered IDE-setup and debugging – new let’s go and actually build something!
This is meant to be a simple template of the most common plugin type in Cinema 4D – the CommandData plugin.
Smart HN-Options is a very simple tool that allows to globally change the parameters of every HyperNURBS object within the scene.
I had this lying around some time now and thought it would made for an excellent example since its small, very basic and couldn’t have been a Script Manager script as it needs to ask the user for multiple parameters on each run.
The code is commented and self-explanatory – i hope – but let’s go through the abstract structure quickly:
STEP 1: PYP-File and Package
As with each python plugin, we start by creating a sub-folder in /Plugins and a *.pyp file within it – in this case the SmartHNOptions.pyp.
First we add the directory that file resides in to the python search path, so the interpreter will pick up our packages and modules:
import os import sys # add this plugin to the python search path folder = os.path.dirname(__file__) if folder not in sys.path: sys.path.insert(0, folder)
The SmartHNOptions.pyp will also have to register our plugin with Cinema 4D, but let’s do that later and finish the general structure first.
Your plugins should exist of at least one package which should be named after the plugin – try to come up with unique names here so you don’t collide with other plugins.
I called it smarthnoptions and placed an empty __init__.py file within the folder immediately – without that file the package will be ignored.
STEP 2: RES-Folder
Then we create another subfolder next to the smarthnoptions package – the res folder.
The res folder includes everything Cinema 4D will need to create and handle the GUI for your plugin – symbols, strings, the layout and images or other assets.
You just have to follow conventions here – the res folder always includes the c4d_symbols.h - the header file which includes an enumeration of symbols used to identify every GUI-object or string you use – and at least two folders:
dialogs and strings_us (only if your CommandData plugin actually has a dialog – otherwise you may skip the dialog folder(s)). strings_us also includes another dialog directory.
For each dialog there is a [dialog name].res file within the dialog folder and a [dialog name].str within strings_us/dialog.
The *.res file describes the dialogs layout, the *.str file the strings used by those GUI-elements.
Last but not least there is a c4d_strings.str file directly within the strings_us folder – this one is used for all strings you need to load on runtime (error-messages etc).
As you might have already guessed, the strings_us folder has the ‘_us’ extension because this is the default – but you can add a ‘strings_de’ folder for example and localize your plugin to German – or French, Italian, Japanese…
This about covers the res folder – have a look at the provided files and I encourage you to read up on the topic in the documentation (misc/pluginstructure.html).
STEP 3: Hack away…
Let’s finish the boring part and lay out the python part of our plugin:
We will need a convenient way to reference to GUI-elements by their correct symbol ID which was specified within the c4d_symbols.h.
So I created a ids.py file and basically copied the constants from the enum into it.
Thus we can import that file and refer to GUI-elements by their constant name and don’t have to juggle a lot of abstract numbers.
If you are building a huge plugin, you might want to consider parsing the c4d_symbols.h, but that’s a future post…
Then I created a cmddata.py – short for CommandData (avoid using names from the Cinema 4D API!).
# this class is the basic plugin
It includes a class that derives from c4d.plugins.CommandData and is the plugin in itself – once executed (Execute()) it creates the dialog.
The dialog however is another *.py file – maindialog.py which derives from c4d.gui.GeDialog – it will load it’s layout from the maindialog.res and start the actual script which I called worker.py.
Now we head back to the SmartHNOptions.pyp and import the ids, cmddata and maindialog.
Note this detail: the maindialog is injected the GeResource object __res__ into its module scope, this will enable API functions such as LoadDialogResource() or GeLoadString() to access the plugins resources.
# make the GeResource object available to modules which need
#access to the *.res or *.str files
maindialog.__res__ = __res__
And finally – once the file is executed, we quickly load the icon and register the plugin with Cinema 4D.
# register the plugin
if __name__ == "__main__":
# load an icon
icon = c4d.bitmaps.BaseBitmap()
icon.InitWith(os.path.join(os.path.dirname(__file__), "res", "icon.tif"))
# get the plugin title from the string resource
title = c4d.plugins.GeLoadString(ids.STR_TITLE)
c4d.plugins.RegisterCommandPlugin(ids.PLUGINID, title, 0, icon, title, cmddata.CMDData())
From here on, things should be obvious from the source and comments – please let me know if you have any questions or suggestions.
Happy plugin coding!