C++ Plugin Development 

for Cinema4D R8

Download the files here.

Introduction

This tutorial is aimed at people interested in developing C++ plugins for Cinema4D R8, and who are looking for some pointers to help get started. This is an introductory tutorial, and as such there is a lot that it doesn't cover. It hopes to provide some practical information regarding plugins in C4D and how to get started in development.

Maxon supply an SDK which conains numerous example plugins with source, which are a very good source of information. The documentation is also prety good as a reference source, though some areas have very shallow coverage. What seems to be lacking is any easy way to get started, or any step by step tutorials related to plugin development.

The approach taken in this tutorial is to start with the SDK and then to explain:
  • How to go about isolating a single plugin from the large number in the SDK.
  • How to change it so that it is effectively a new plugin which doesn't conflict with the SDK, and can be used as a framework for developing a new plugin.
  • A simple modification to the plugin, showing where changes need to be made to support it.
  • Which files are required for a final distribution..
Instructions are provided for both PC/Windows (using Visual C++) and for Mac (using CodeWarrior).
A downloadable file is provided containing the final files for the project, for both PC and Mac.


Preparation

It is assumed that you have alreaded downloaded and installed the SDK in the Plugins folder of your Cinema4D installation.

If you are using CodeWarrior on a Mac, then you shouldn't have any problems, and you can skip to the next section.

For PC/Windows using VC++ , the API files need to be modified to repair incorrect end of line markers in the files, which VC++ can't handle, and the default configuration needs to be changed.

The following is based on a post I made on Plugin Cafe regarding these problems (these only apply to VC++, CodeWarrior has no problems reading these files...):

If you haven't got the Intel compiler, then in '(C4DR8)\Plugins\cinema4dsdk\cinema4dsdk.dsw' and in '(C4DR8)\Resource\_api_lib\_api_v8.dsw' you need to do this:
Build -> Set active config to debug or release (Not intel - which is the default).

To get rid of the 'fatal error C1070: mismatched #if/#endif pair' errors, you need to fix the line endings,
The brute force way of doing this is as follows, though if you look on
Plugin Cafe you will find some easier options.
For EVERY '*.h' AND '*.cpp' file in '_api', and for EVERY '*.h' file in 'res/description', and 'modules/objects/res/description', and ALL THEIR SUBDIRECTORIES, open each file in PFE (Programmers File Editor - others might work), add a line, delete it, then resave. This fixes the line endings.

Unfortunately, CodeWarrior can no longer be used under Windows to build the Windows versions of the plugins (though it can be used under Windows to build the Mac versions. Most annoying...).

Building the SDK Examples

Windows:
Using VisualC++, you should be able to do the following to build the SDK examples:
1. Open 'cinema4dsdk.dsw' in Visual C++
2. Build->Configurations: Select Win32 Release or Win32 Debug.
3. Build->Rebuild All

This should finish without errors, producing the 'cinema4dsdk.cdl' file, which is the Windows plugin file containing all the SDK examples.


Mac: (I'm actually doing this under windows on a PC - but this is still building for a Mac.)
Do the following to build the SDK examples:
1. Open 'cinema4dsdk.prj' in CodeWarrior.
2. Select 'CINEMA4D SDK (Debug)' or 'CINEMA4D SDK (Final)' in the 'Targets' tab of the project view.
3. Project->Remove Object Code (Recursive, All targets)
4. Project->Make


This should finish without errors, producing the 'cinema4dsdk.xdl' file, which is the Mac plugin file containing all the SDK examples.

Start Cinema4D, and make sure that the SDK examples appear in the plugins menu. Exit Cinema4D again.

I now assume that you have successfully built the SDK examples.

Do not proceed until you are able to do this.



Choose a plugin type

Now, having verified that we can build the SDK examples successfully, we want to start developing a new plugin. The SDK contains examples for the various different types of plugins that can be made, so pick one of a type that you are interested in developing.

For the purposes of this tutorial, I am going to assume that we want to develop a 'tag' plugin, but the process is similar for other types.

The SDK 'tag' plugin example is called 'Look at Camera', and it does as it suggests. We will create a project containing only this plugin, which can then have its functionality changed to whatever you want.

Delete unwanted files

First, copy the entire 'cinema4dsdk' directory and rename it 'myTag'. This should still be in the Plugins folder under C4D.
Go into this directory.

Delete all files in the top level, except for the directories and the project files. You should be left with these:
res                 (directory)
source              (directory)
CINEMA4DSDK.dsp     (Windows VC++ project file)
cinema4dsdk.dsw     (Windows VC++ workspace file)
cinema4dsdk.prj     (Mac CodeWarrior project file)

Go into 'source', and delete everything except the 'tag' directory, and the file 'Main.cpp'.

Delete everythin in the 'obj' directory.

Go into 'res/description', delete everything except 'Tlookatcameraexp.h' and 'Tlookatcameraexp.res'.

Delete 'res/dialogs', and 'res/scene'.
Delete 'res/strings_us/dialogs'
Delete everything in 'res/strings_us/description' except 'Tlookatcameraexp.str'

Delete all files in 'res' except for the remaining directories, and the files 'LookAtCamera.tif', and 'c4d_symbols.h'

Ok, we've now got rid of most of the files that are not relevant to our plugin. We now need to start editing the few that are left.

Edit Source Code

Ok, this section is pretty lengthy. Get a cup of coffee, and go for it...

Open 'source/Main.cpp'. This is where Cinema4D starts when attempting to use your plugins. It calls the function 'bool PluginStart(void)'. This function then attempts to register all of the plugins that are contained in this project. It returns true if there were no problems or false if there were. Your plugin's registration function is where your plugin is initialised ready for use.

Find the 'PluginStart' function in 'Main.cpp', and delete everything except the following lines:

Bool PluginStart(void)
{
    // tag / expression plugins
    if (!RegisterLookAtCamera()) return FALSE;

    return TRUE;
}

In the section labelled 'forward declarations', delete all lines except 'Bool RegisterLookAtCamera(void);'

Note that there is another function called 'void PluginEnd(void)' which does nothing. This is automatically called when plugins are shutdown on exit, and this is where any resources (e.g. memory) that you grabbed in your registration function should be released. (You can think of the PluginStart function as a kind of constructor, and the PluginEnd one as a kind of destructor.)

Delete the line
'if (!RegisterExampleDataType()) return FALSE;'
from the 'PluginMessage' function.

Finally, replace both places where it says 'RegisterLookAtCamera' with 'RegisterMyTagPlugin'.

We are now finished with 'Main.cpp'. Notice how little there is in it now! On startup, C4D will call 'PluginStart'. In turn, that will call 'RegisterMyTagPlugin', which doesn't exist yet.



Now rename 'source/tag/LookAtCamera.cpp' as 'source/tag/myTagPlugin.cpp', and open it.

Do a search and replace to replace all instances of 'LookAtCamera' with 'MyTagPlugin'.

Replace 'lookatcameraexp' with 'mytagplugin'.

Replace 'lookatcamera.tif' with 'mytagplugin.tif'.

Replace 'IDS_LOOKATCAMERA' with 'IDS_MYTAG'.

Replace 'ID_LOOKATCAMERATAG' with 'ID_MYTAGPLUGIN'

IMPORTANT:
Find the line that now reads:
#define ID_MYTAGPLUGIN  1001165

Change it to read
#define ID_MYTAGPLUGIN  1000001

This is very important! This is the ID number assigned to the plugin. Every plugin MUST have a unique ID number, because if two have the same
number then C4D will refuse to load them. Worse than this, it is possible for internal data for on plugin which is stored in your document to be interpreted by another plugin as data intended for it.

Plugin numbers 1000001 to 1000010 are reserved for development. You can use them for any plugins that you are developing, but if you want to give your plugin to _anyone_ else then you should get a unique number yourself from plugincafe.

We don't want to actually change what this tag does yet, so we leave the other contents of the file unchanged.

This file contains all of the code that determines what the plugin does.
Looking at the class definition at the top, we have (reformatted a bit):

class MyTagPlugin : public TagData {
public:
  virtual Bool Init(GeListNode *node);
  virtual LONG Execute(PluginTag *tag, BaseDocument *doc, BaseObject *op, BaseThread *bt, LONG priority, LONG flags);

  static NodeData *Alloc(void) { return gNew MyTagPlugin; }
};


What this says is that we are defining a new class called 'MyTagPlugin', which is of type 'TagData'. 'TagData' is the base type for all tag plugins, and provides default functionality (which does nothing, in effect).
The two method (function) prototypes below that say that we are providing our own versions of those functions, which should be used instead of the versions provided by 'TagData'.

The 'Alloc' line defines a function which creates a new instance of a plugin of our type. This function should always look like this.

Later in the file are the actual definitions of the 'Init' and 'Execute' methods. This is where you need to make changes to change the actual function of the plugin.

I promised that we would make a modification to the plugin, so here it is. We are going to add an extra control that lets you disable the plugin. Ok, not very exciting, but the idea here is to see how it is done.
Find the 'Execute' definition, and after the line containing just a '{', add the following line:
if (!tag->GetData().GetBool(POWER_SWITCH)) return TRUE;

This says that if the control labelled POWER_SWITCH is turned off, then exit, and don't bother with the rest of the processing.

The final function listed in the file is 'RegisterMyTagPlugin(void)', remember that? This is the function that is called in 'Main.cpp' during startup. This function provides basic information about the plugin to C4D, so that it knows how to use it. The parameter saying "mytagplugin.tif" is the name of the icon that will be used to represent this plugin. It is important that this refers to a file that actually exists, otherwise the plugin will not register, but C4D will not give you any clues that that is the problem...

While you remember, rename 'res/LookAtCamera.tif' to 'res/mytagplugin.tif'.



Rename 'res/description/Tlookatcameraexp.res' as 'res/description/Tmytagplugin.res', and change it's contents to the following:
CONTAINER Tmytagplugin
{
    NAME Tmytagplugin;
    INCLUDE Texpression;

    GROUP ID_TAGPROPERTIES
    {
        BOOL LOOKATCAMERAEXP_PITCH { }
        BOOL POWER_SWITCH { }
    }
}

This describes the controls that the tag provides. In this case there are two controls, which are both BOOLs (i.e. an on/off controls), which are labelled LOOKATCAMERAEXP_PITH, and POWER_SWITCH within the plugin.
Note that LOOKATCAMERAEXP_PITCH was there already, but POWER_SWITCH is a new line, which we added to provide us with our new control.

This 'POWER_SWITCH' is the control that is being referred to by the line in 'myTagPlugin.cpp', in the 'Execute' method, when it says: 'tag->GetData().GetBool(POWER_SWITCH)'.


Rename 'res/description/Tlookatcameraexp.h' as 'res/description/Tmytagplugin.h', and change its contents to the following:
#ifndef _Tmytagplugin_H_
#define _Tmytagplugin_H_
enum
{
    LOOKATCAMERAEXP_PITCH           = 1000,
    POWER_SWITCH                    = 1001
};
#endif

Note those names again. This file just assigns a number to each name that you use in your plugin. It doesn't really matter what the numbers are, as long as they are unique within a plugin. It doesn't matter if different plugins use the same values (they probably will) so we don't need to change anything. Again we have added a line for the new POWER_SWITCH control. IMPORTANT: Remember to add the comma after '1000' in this file. Only the last number misses the comma, which is why there wasn't one already.


Rename 'res/strings_us/description/Tlookatcameraexp.str' as 'res/strings_us/description/Tmytagplugin.str', and change its contents to the following:
STRINGTABLE Tmytagplugin
{
    Tmytagplugin        "My Look At Camera Expression";
    LOOKATCAMERAEXP_PITCH    "Change Pitch Rotation";
    POWER_SWITCH        "My All-powerful Power Switch";
}

Again, we've added a line for POWER_SWITCH. This file is where names are attached to the control. These are the names that you will actually see in the user interface within Cinema4D. The first one is the name for the plugin itself.


Open 'res/strings_us/c4d_strings.str'.
Delete everything except the 'IDS_LOOKATCAMERA' line, and change that so that the file now contains:
// C4D-StringResource
// Identifier    Text

STRINGTABLE
{
    IDS_MYTAG        "My Look At Camera Plugin";
}

This provides a text name for the plugin.


Open 'res.c4d_symbols.h'. Change the contents to the following:
enum
{
    // string table definitions
    IDS_MYTAG = 10000,

    DUMMY_
};

Again, this provides an internal numeric ID for the plugin label, whilst the previous file provided a readable string ID for the same plugin.

Finally, we're done with the source file edits. Once you become familar with the files and what they are for, you can make these changes pretty quickly.

Update Project Files

Finally, we need to change the project files. This is the only platform dependent part.

Windows:
Rename 'CINEMA4DSDK.dsp/dsw' to 'myTagPlugin.dsp/dsw'.
Open 'myTagPlugin.dsw' in VC++.
In response to 'Browse for project cinema4dsdk, select file 'myTagPlugin.dsp'.

Go to file view in the project manager.
Select the 'Source Code' directory and delete it (and everything in it).
Right-click and add a new folder called 'Source'.
Select it, right-click and select 'add files'.
Add 'source/Main.cpp', 'source/tag/myTagPlugin.cpp', and 'res/c4d_symbols.h'.
Build->Set Active Configuration: Win32 Release (or Debug)
Project->Settings: Win32 Release, Link Tab: Output name: myTagPlugin.cdl
Project->Settings: Win32 Debug, Link Tab: Output name: myTagPlugin_deb.cdl
Build! (F7)

This should produce a file 'myTagPlugin.cdl', or 'myTagPlugin_deb.cdl' which is the main plugin file.
Note: If you have both of these file present at the same time, they will conflict because C4D will attempt to load them
both. Build one or the other, not both.


Mac:
Rename 'cinema4dsdk.prj' to 'myTagPlugin.prj'.
Open it in codeWarrior.
Select Files view.
Select 'Source', and remove it (and hence all files inside it).
Create group 'Source'.
Add 'source/Main.cpp', 'source/tag/myTagPlugin.cpp', and 'res/c4d_symbols.h'. Allow them to be added to both the debug and release targets.
Select the Targets tab, and select either Final or Debug, and double click to open settings panel.
Change Target->Target Name to 'myTagPlugin (Final)' or 'myTagPlugin (Debug)'
Change Target->PPC Target to 'myTagPlugin.xdl' or 'myTagPlugin_deb.xdl'
Build! (F7)

This should produce a file 'myTagPlugin.xdl', or 'myTagPlugin_deb.xdl' which is the main plugin file.
Note: If you have both of these file present at the same time, they will conflict because C4D will attempt to load them
both. Build one or the other, not both.

Testing Time

Start Cinema4D, create a cube, right-click on the cube and select 'New Expression -> My Look At Camera Plugin Expression'.
In the attribute manager you should see the controls, with the new 'Power Switch option'. Try it out, it should work as advertised. When turned off, the plugin doesn't do anything. When turned on, it behaves like the normal plugin tag.

Success!

Distribution

Note that if you wanted to distribute the plugin (once you've changed the plugin ID number - you MUST do this), you must also provide people with the 'res' directory, as C4D uses those files in addition to the binary.

So, a final distribution containing only what is required for the plugin would consist of the following files:-

res/description/Tmytagplugin.h      Describes the User Interface in C4D   
res/description/Tmytagplugin.res    Describes the User Interface in C4D
res/strings_us/description/Tmytagplugin.str  Provides names for UI elements
res/strings_us/c4d_strings.str      Provides names for plugins
res/c4d_symbols.h                   Contains internal ID numbers for plugins  
res/myTagPlugin.tif     The icon used for the plugin
myTagPlugin.cdl         The PC/Windows version of the plugin itself
myTagPlugin.xdl         The Mac version of the plugin itself

Plus any extra documentation or example files you wanted to provide.

I hope this tutorial has been useful. and helps you to get started with plugin development for Cinema4D!

I have provided a download file which contains all of the source files required for this, and the Mac and PC/Windows project files, together with the built plugin for both platforms.

Download the files here.


    Cheers - Steve Baines   February 2003

Home