Developing a Tools plug-in for OpenFX


The Designer program has two main ways of building, Geometry creating modules..

Building and Files

Each designer geometry plugin is built as a Windows DLL, it will have one or more C or C++ language source file, one or more project specific header files, a Visual Studio project file, a resource file (.RC) ,  a module definition file (.DEF) a file with filename extension (.AFX for actions plugin, .DFX for a tools plugin).  The project will build to a .DLL of the same name as the MFX/DFX file.  The build files can have any location, but the AFX/DFX and DLL files must be placed in the "PLUGINS" folder.

The plugin source files need to include two header files that are located in the "DESIGN" folder.  These are "struct.h" and "dstruct.h" . These define the Designer's data structures and provide prototypes for the Designer's internal functions that can be used from within a plugin.  The Designer's functions that the developer can use are not defined in a library, they are accessed through a pointer that is passed to the plugin at run time. However, they can be used in the plugin as if they were ordinary functions. There is no need to link any of the plugins with a special library. (We will return to the source code later.) 

In the case of an Actions plugin, the resource file (.RC) will usually contain a dialog box description to allow the user to set up the action.  To get a feel for a plugin action we shall look at a plugin called Simple Plot. The SimplPlt tool allows the user to draw a 2 dimensional curve, interact with that curve and then trun that curve into a mesh curve in the Designer module.

The simplplt appears to the user as a window that overlaps the main Designer window:

simplplt.png (34432 bytes)


The files associated with the SimplPlt tool are:

these are located in the design folder, and

located in the plugins folder.

The build project file is located in the "design\vc7" folder

The build process will create a DLL file called delaunay.dll in the plugins folder.  The simplplt.dfx file is just a place holder to allow the Choose Tools dialog box to present to the user a list of available tools.

Building is done in Visual Studio .using the simplplt project. (You can see this in the Designer build Solution (.SLN) file that contains all the modelling plugin projects as well as the main designer.  If you want to start writing a new Tools plugin then we suggest you copy the files from this plugin to a new set. Modify the .VCPROJ files using a simple text editor to reflect the name change and then add that to the designer solution. (or set up an individual solution to contain it.)  

This concludes all we have to say about building. Most of the other plugins in OpenFX follow a similar strategy.

The plugin-code

The plugin code follows the basic design of a Windows DLL . In this section we will examine the parts of the Delaunay action source file that are common to all tools plugins. The most important items to be aware of are the name of the function called by OpenFX's designer module to execute the action called _Xmodeler(), the include files that define the OpenFX designer datastructures "struct.h" and the external function definition and global variable definition header file "dstruct.h"

The OpenFX method of accessing global variables and main program functions   (VERY IMPORTANT)

OpenFX uses a pointer mechanism for allowing the plugins to access functions in the main program and program global variables. Since all OpenFX plugins are DLLs that are loaded into the main applications address space. The plugin DLLs are NOT loaded when the main application starts (many of the built-in actions are also implemented as DLLs that ARE loaded when the program starts) they are loaded when required and unloaded when they have finished.
In the case of plugins that are used in the Designer and Animator AND are needed by the Renderer (e.g. shaders) then the Renderer loads all the needed plugins when it reads the script file during initialisation. The Renderer unloads the plugins when it is finished with the script.

When the Designer requires an external action to be performed it calls  the function _Xmodeler(), with three arguments:

BOOL _Xmodeler (HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){

The first two arguments are handles for the Designer's container window and the Designers information/status window at the bottom of the screen. Getting these handles allows the plugin to send messages to the designer, for example to write some informative text into the status window. The third parameter is the most important.   The "lpevi" parameter is a pointer to the X__STRUCTURE data structure. The X__STRUCTURE structure is a global structure that contains pointers to the main data that the Designer module is currently holding, all the lists of vertices, edges, faces, skeleton, materials, maps etc.  the X__STRUCTURE also has pointers to many of the Designers internal functions, such as those that create vertices, manipulate dialog boxes, etc. etc.

Part of this structure looks like this:

typedef struct tagX__STRUCTURE {
unsigned long *Nvert,*Nedge,*Nface,*Nskel,
sruct tagVERTEX **MainVp;
long *dummyv[60];
void (*fpDA)(short);
void (*fpCV)(void);
void *dummyf[52];

The designer keeps only one copy of this structure, it is initialised at start-up and passed to all the plugins.  By using the members of this structure any plugin can access all the Designer internal data and functions. This method is very simple and very flexible, just by using up some of the dummyV and dummyF variables extra variables and functions can be made available to the plugins in future releases of OpenFX without compromising the behaviour of existing plugins even at the binary level.

In order that the contents of this structure can be made available to all functions and files in a plugin the pointer passed in to _Xmodeler should always be copied into the global variable:


This global variable is located in the standard include file "dstruct.h". Thus, the standard entry point for all plugins will resemble something like:

BOOL _Xmodeler(HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){
// remainder of code...
return TRUE;  // if effect worked  FALSE if it failed.

Accessing variables and functions in a DLL module through direct use of the lpEVI structure pointer is very tiresome.  For example to use the Designer's number of selected  vertices variable (called "NvertSelect")  it would be necessary to use the code (  (*(lpEVI->NvertSelect))    )   to  gain access to this variable.   This is very messy!  To overcome this issue and provide an interface to the designer's functions that make them look (in the code) just like normal function calls, a number of #defines are included in the header file "dstruct.h" , which is one of the two ".h" files that every plugin must include.

Using these defines, calls to functions and use of global variables can be used as if they were part of the main Designer module code.  for example,

To increase the memory space for holding mesh edge data, and then add an edge to this list the code below can be used.:


if(!UpdateEdgeHeap(Nedge+3))return NULL;
  CreateEdge(vp,w0); e0=Nedge-1;

Keeping this very important information in mind we can return to considering the simplplt plugin action and look at the key code constructs.

Essential headers and global variables
#include <stdlib.h>
#include <windows.h> 
#include "struct.h"
#include "dstruct.h" 
static HWND hParent;
static HINSTANCE hThisInstance; 
DLL standard entry code for Visual Studio compiler
BOOL WINAPI DllMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
switch (dwReason) {
if(hDLL == NULL)MessageBox( GetFocus()," NULL instance",NULL, MB_OK);
return TRUE;
Exported function to implement the tool.
BOOL _Xmodeler (HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){
lpEVI=lpevi;  // set pointer  
// Implement the tool

The SimplPlt example

To return to the simplplt example, this section will highlight the main points. For fine detail use the bullet points below to identify features to examine in the code (file simplot.plt.c)

Note the following:

This completes our discussion of the example. You should look at the code for the other tool plugins, find and identify the similarities with this example and follow the logic of the argument in the code.

Go back to the developer page...