|
|
C++ Plugin Development
for Cinema4D R8
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
|
|