Most tools can be divided into two classes: non-interactive tools that simply do their job when clicked and those that need further information from the user. This example demonstrates the former: the tool button simply creates a sphere when clicked.
The plugin demonstrates many of the commonly needed concepts plugins typically need:
How to separate functionality from the user interface via extension methods
How to implement and register new classes into Realsoft 3D
How to support macro system
How to create new geometric objects and insert them into the current project
You can find the source code for this plugin in samples/plugins/toolbutton.
It is always very bad idea to mix user interface code and functionality code with each other. The functionality should always be separated from the user interface. This example plugs the actual functionality code into the geometric layer class as an extension method. This way it can be called by anyone, not only the tool button it was originally implemented for.
Extension method are always of form:
static void *myemth_foo(R3OBJ *obj, void *p1, void *p2, void *p3);
In this example we use the three extension method parameters for passing object name, center and radius for the sphere to be created. The extension method would look as follows:
#include <real/layer/r3prilay.h>
#include <real/objects/r3sphere.h>
static void *mytoolset_sphere(R3OBJ *primlayer, char *name, R3FLOAT *radius, R3VECTOR *center)
{
// create a sphere
R3OBJ *sphere = R3New(R3CLID_SPHERE,
R3T(R3RA_Name, name),
R3T(R3SPHA_Radius, radius),
R3T(R3SPHA_Center, center),
R3TAG_END);
// insert it to the current project
if(sphere)
R3Do(primlayer, R3OLAYM_INSERT, sphere);
return sphere;
}
To register the above extension method to the prim. layer, call:
int R3LibraryInit(R3APP *app)
{
// register the extension method if application has a primlayer
if(R3ClassFind(R3CLID_PRIMLAYER))
R3ClassAddExtensionMethod(R3CLID_PRIMLAYER, "mytoolset_sphere", mytoolset_sphere);
...
If you need to plug in several tools you have two choices: either plug them in into the existing tool groups (see Available Objects window), or create a new tool group and put all your tools in it. In this example we show how to create a new tool group.
To create a new tool group:
#include <real/windows/r3tool.h>
#include <real/widget/r3tbar.h>
// unique class id for the group
#define R3CLID_MYTOOLSET (R3CLID_TESTBASE+33)
// unique label for the toolset
#define MYTOOLSETNAME "My Toolset"
// plug in the new tool group
if(R3ClassFind(R3CLID_TOOLBAR))
if(R3RegisterToolClass(app))
R3DoClassA2(R3CLID_TOOL, R3TOOLCM_INSTALLTOOLGROUP, (void*)R3CLID_MYTOOLSET, MYTOOLSETNAME);
The above code first checks whether there is a tool bar in the application that has loaded the plugin. If it has a tool bar, the plugin registers the tool base class and installs the new tool group to it.
![]() |
Note |
|---|---|
| The example above uses one of the test class ids (R3CLID_TESTBASE+0 ... R3CLID_TESTBASE+99). You can use these for testing purposes. Ask the final class ids from realsoft before releasing your plugins. |
Put the above code to your R3LibraryInit() function, compile and link the code and new tool group will show up in the Available Objects window / Tools tab.
The Customize->Available Objects window consists of several tool groups, such as nurbs tools, sds tools, analytic tools, transformation tools etc.
In order to add new tool into the newly created tool group, you need to implement a tool button class. To do this, just copy the example class from samples/plugins/toolbutton and modify it.
Most of the functionality needed to plug new tool buttons into the program is already implemented by the super classes. Typically you just need to implement two methods namely R3RM_CREATE and R3TOOLM_ACTION. The former constructs your tool button with desired icon and label as well as tells the button to call a method when clicked. And the latter is of course the method to be called.
You should create a nice icon for your tool buttons. Currently built-in icons in Realsoft 3D are implemented in Microsoft .ico format. The 'icons' sub folder contains a simple icon for our tool as well as a makefile which extracts the image from the .ico file into a .h file which we can then include with our source file.
The name of the .ico file is "mytool.ico". To create an icon object:
#include "icons/mytool.h"
static R3OBJ *create_icon()
{
if(!class_icon) {
class_icon = R3New(R3CLID_ICON,
R3T(R3ICONA_Data, mybits),
R3T(R3ICONA_Width, mywidth),
R3T(R3ICONA_Height, myheight),
R3T(R3ICONA_Depth, mydepth),
R3TAG_END);
if (class_icon)
R3DoA(class_icon, R3RM_REF, NULL);
return class_icon;
}
The tool button can then use the icon, as follows:
#include <r3icons/mysphere.h>
static void r3rm_create(R3CLASS *cl, R3OBJ *obj, R3TAG *tags) {
R3IDATA *self = R3CL_IADDR(cl, obj);
if(!(obj = R3DoSuper(cl, obj, R3RM_CREATE,
R3T(R3GA_Icon, create_icon()),
R3T(R3GA_Text, "Sphere"),
R3T(R3GA_ToolTip, "Create a sphere"),
R3TAG_MORE, tags)))
return(NULL);
// ask the button to call R3TOOLM_ACTION method when clicked
R3Do(obj, R3WGM_MAPCHANGES,
R3T(R3WGA_MapToObj, obj),
R3T(R3WGA_MapToMethod, R3TOOLM_ACTION),
R3TAG_END);
return obj;
}
So the created button will call our R3TOOLM_ACTION method when clicked. In this method we could simply call the extension method, as follows:
R3FLOAT radius = ..;
R3VECTOR center = ...;
R3DoE3(primlayer, "mytoolset_sphere", "my nice sphere", &radius, ¢er);
However,we would miss two important issues: first, the primlayer must always be locked due to multi threaded nature of Realsoft 3D. Second, we want to support macro system. For example, the user should be able to create 100 spheres simply by clicking the tool once in macro recording mode and then executing the macro with desired repeat count.
The following code shows how to do all this:
#iclude <real/code/r3maccl.h>
static void *r3toolm_action(R3CLASS *cl, R3OBJ *obj, R3INT event)
{
R3IDATA *self = R3CL_IADDR(cl, obj);
R3OBJ *layer, *primlayer;
R3GetAttrs(obj, R3T(R3TOOLA_Layer, &layer), R3TAG_END);
if (layer) {
R3GetAttrs(layer, R3T(R3LAYA_Prims, &prims), R3TAG_END);
if(prims) {
R3MAC_SNDMSGA(app, "R3CurrentPrims", prims, R3OLAYM_LOCKEXCLUSIVE, NULL, R3MCTP_INT);
R3MAC_SNDEMSGA3(app, "R3CurrentPrims", prims, "mytoolset_sphere",
"my nice sphere", R3MCTP_STRING, // p1
&radius, R3MCTP_FLOAT, // p2
¢er, R3MCTP_VECTOR); // p3
R3MAC_SNDMSGA(app, "R3CurrentPrims", prims, R3OLAYM_RELEASE, NULL, R3MCTP_INT);
}
}
return (void*)TRUE;
}
The tool button class should also create one class specific icon and return it in R3RM_GET method, as follows:
/* r3rm_get */
case R3RA_Icon:
*(R3OBJ **)tag->value = create_icon();
break;
so that the Available Windows can show a nice icon rather than just a text label.
Remember to delete the class icon in R3RCM_FREECACHE method.
Now that we have a decent tool button class, we can plug it in to the Available Objects window by calling:
R3DoClassA2(R3CLID_TOOL, R3TOOLCM_INSTALLTOOLCLASS, (void*)R3CLID_MYTOOLSET, (void*)R3CLID_MYSPHERETOOL);
Put the above call into your R3LibraryInit() function and a new tool will show up into the Available Objects window / Tool / My Toolset frame. Drag & drop the tool into your favourite tool tab and click the tool: a new sphere should show up in the project.