Common Elements

This page discusses the components that are common to all plug-ins. These are the structural components that form the bridge between LightWave and your plug-ins. They have funny names and do possibly unfamiliar things, so we need to introduce some terminology.

The host is the program, Layout or Modeler, for example, that runs your plug-ins.

A plug-in module is a file, usually with a .p extension, that contains one or more LightWave plug-ins. Any number of plug-ins can be compiled together into a single module. It's common for an image loader and an image saver to be together in the same file, for example.

Every plug-in file needs a server description that lists the plug-ins in the file, and every plug-in needs a special entry point function, its activation function. Both of these are defined in the lwserver.h header file. Each plug-in file also contains initialization and cleanup functions called Startup and Shutdown.

Server Description

The server description lists what your plug-in file contains. It's the first thing the host examines when it loads your module. The list appears in your source code as an array of ServerRecords.

   typedef struct st_ServerRecord {
      const char     *className;
      const char     *name;
      ActivateFunc   *activate;
      ServerTagInfo  *tagInfo;
   } ServerRecord;
A string containing the class of the plug-in. The class identifies what kind of plug-in this is. The header files for classes contain #defines for each class name. These are also listed in the documentation for each class.
A string containing the name by which LightWave will uniquely identify your plug-in. This is the name LightWave uses internally and saves in scene and object files. It's also the name displayed to the user if the plug-in doesn't supply at least one user name. The name must be a string of ASCII characters in the range 33 to 127 (note that this excludes spaces). Case is significant.

Although this allows punctuation and other special characters to appear in the name, you're strongly encouraged to limit names to those that would be legal identifiers in the C language. C identifiers contain letters, numbers and the underscore character (ASCII 0x5F). Image saver names, which by convention end with the default filename extension in parentheses, are an exception to this rule.

The use of non-alphanumeric initial characters to force your plug-ins to appear first, or together, in lexicographically sorted lists is discouraged. This practice may interfere with LightWave's internal name processing and may conflict with conventions that evolve in the future.

Each class has its own name space, so plug-ins of different classes can have the same name. Although you'll probably want to avoid giving unrelated plug-ins the same name, you must use the same name for the interface class associated with a handler. This is how the host matches a handler with its interface.

The activation function. See below.
An array of tag strings that describe the plug-in. Among other things, this is where you list the name that will be displayed to your users in LightWave's interface.

Server Tags

The ServerRecord's tagInfo field is an array of ServerTagInfo structures.

   typedef struct st_ServerTagInfo {
      const char   *string;
      unsigned int  tag;
   } ServerTagInfo;

Each tag contains two codes combined using bitwise-or. The high word is the tag type, and the low word is the language ID. Not all of the tags are supported yet. Currently defined tag types include the following.

The name displayed to the user in LightWave's interface. Multiple user names for different locales can be provided by combining this type code with different language IDs. LightWave attempts to select the name that's most appropriate for the locale of the user's machine. Unlike the internal server name, there are no restrictions on what the string may contain.
Japanese strings should be encoded as JIS on Windows and EUC on Unix.
The string that will appear on a button or in a popup list used to invoke your plug-in. This is usually an abbreviated version of your user name.
The LightWave interface organizes commands, including plug-ins, into command groups. The command group you specifiy determines the heading under which users will find your plug-in on menu and key customization dialogs. The command group can be a predefined group, or a new group created simply by listing its name.

In general, the predefined group names are lowercase versions of the group names displayed in the interface. When using one of these groups, the language ID should be 0. Predefined group names are automatically translated to the locale of the user's machine. The following is a partial list of the predefined command groups.

Both Layout Modeler
For plug-ins that can be activated as commands or tools (all Modeler classes, plus generics in Layout), the menu string specifies the location of the plug-in's node in LightWave's menu system. Like command groups, the menu string can refer to predefined or custom nodes. They can also specify a "path" resembling a filename, with optional root menu nodes followed by a colon and other nodes separated by forward slashes, and the nodes can be a mix of predefined and custom. The path

for example, would create a (custom) "Quadrics" popup on the (predefined) "Tools" tab, while


would create a "Metaballs" group. In general, the menu tag path has the form


and the menu info tag can contain many of these strings separated by commas. The string

   "multiply/replicate,LMB:Ultra Studio"

would place the command or tool into the standard location in the main menu and into a custom group in the left mouse button popup. It's even possible to place commands into the bottom command bar in Modeler, but this isn't recommended, since the screen real estate there is limited.

The predefined menu hierarchy hadn't been finalized at the time this document was last updated.

A line of text describing the plug-in. This might be displayed in the interface as hint text or as a description next to the user name in customization dialogs.
A string defining the conditions under which the plug-in should be active. This is currently used for Modeler tools and commands to determine the enable state of the plug-in's button. Possible values include

"pnt" - active points
"pol" - active polygons
"spnt" - directly selected points
"spol" - directly selected polygons

Compound conditions, which would combine these into boolean expressions, aren't supported yet but may be in the future.

The language ID is a code indicating the language for the name string. The language IDs are identical to those defined in the Microsoft Win32 API and exposed in the Microsoft Visual C++ winnt.h header file. Bits 7 - 0 define the language group and bits 15 - 8 define the sublanguage. lwserver.h contains symbols for some of the more common language IDs.


Activation Function

The activation function is the entry point for the service provided by your plug-in. For some plug-in classes, this may be the only function the host calls in your plug-in (other than the startup and shutdown functions). For others, the activation function is where the host finds out about the plug-in's callback functions.

   XCALL_( int )
   MyActivate( long version, GlobalFunc *global, void *local,
      void *serverData );
A class-specific version number. As development of LightWave continues, the interaction between the host and a given plug-in class is sometimes redefined. This number tells you, among other things, what version of the local data the host has passed. See the compatibility discussion for more information on using this value. In most cases, though, you'll test this value against the version number defined in the header file for your plug-in's class and return AFUNC_BADVERSION if they don't match.
A function that gives your plug-in access to services provided by the host and by Global class plug-ins. See the pages about the global function and Global plug-ins for more information.
Class-specific data. Each plug-in class receives different data through this argument. The documentation for each class, in fact, is primarily concerned with describing the class's local argument. For handler classes, this points to a structure that the plug-in needs to fill. The host gets pointers to other functions in your plug-in this way.
The data pointer returned by the startup function. Unless you replaced the default startup function, you should ignore this argument. In particular, don't try to dereference the pointer, since on most systems it contains an invalid (although non-NULL) address.

The activation function returns a code that tells the host whether the plug-in was activated successfully.

The version argument differs from what your plug-in supports. In some cases the host will try again with a lower version number.
A call to the global function failed.
Your plug-in doesn't like something in the local data.
The host is a program you don't support.
Return this when none of the other values is appropriate.

Startup and Shutdown

These two optional entry points allow the module to initialize itself when it is first loaded and to clean itself up before being unloaded.

   void *Startup( void );
   void Shutdown( void *serverData );

Most plug-in files don't require module-level initialization and cleanup. They use the empty startup and shutdown functions supplied by the SDK linker library.

The startup function is called when the plug-in is first loaded by the host. The return value is the data passed to the activation and shutdown functions as the serverData argument. Returning NULL from the startup function indicates failure, so even if a module has no real server data, it should still return something. The module's shutdown function is called just before the host unloads the module. Any allocated server data should be freed at this point.

Calling Convention

Functions in the plug-in are called directly by LightWave, and this is a potentially funky thing in some systems since they may be different environments. The lwserver.h header file defines an XCALL_ macro that establishes the calling convention for each platform and compiler. XCALL_ is applied to anything that preceeds the function name in definitions.

   XCALL_( static const char * ) DescLn( LWInstance instance )
   { ...

All functions in your plug-in that can be called by LightWave need the XCALL_ treatment, with the exception of the startup and shutdown functions.