Table of Contents


Formally, handlers are plug-in classes that manage persistent instance data through callbacks identified in the activation function. Handlers don't simply run and exit. They tell LightWave® in their activation functions where they can be reached, and then they hang around, waiting for LightWave® to call them.

Instance Functions

An instance is a block of data you create to describe a specific invocation of your handler plug-in. An ItemMotionHandler, for example, can be invoked for any number of items in the scene, and might even be invoked more than once for a given item, but for each slot it occupies, the plug-in will create and use an instance specifically for that item slot. The instance data is where the plug-in settings for that invocation are stored, and every one of the plug-in's callbacks receives this data as one of its arguments.

The instance callbacks are where your plug-in creates, destroys, copies, loads, saves and describes each instance data block. They're collected together in an LWInstanceFuncs structure which is part of the local data passed to your activation function. Your activation function needs to fill in this structure to tell LightWave® where your instance callbacks are.

   typedef struct st_LWInstanceFuncs {
      void         *priv;
      LWInstance   (*create)  (void *priv, void *context, LWError *);
      void         (*destroy) (LWInstance);
      LWError      (*copy)    (LWInstance, LWInstance from);
      LWError      (*load)    (LWInstance, const LWLoadState *);
      LWError      (*save)    (LWInstance, const LWSaveState *);
      const char * (*descln)  (LWInstance);
   } LWInstanceFuncs;
Passed as the first argument to create. Set this to point to data you'd like your create function to have.

instance = create( priv, context, error )
Create an instance. Called, for example, when the user selects your plug-in on the interface and when Layout loads a scene or an object file that refers to your plug-in. Typically, you'll use malloc to allocate memory for a data structure, fill in some of the structure's fields with default values, and return the pointer to this structure. priv is the same as the priv field of the LWInstanceFuncs structure and contains whatever your activation function put there. The context varies depending on the plug-in class, but this is often an item ID for the item this instance will be associated with. If you can't create an instance, set error to an error message string and return NULL.

destroy( instance )
Destroy an instance. Called, for example, when the user deselects your plug-in and when the scene is cleared. Typically you'll free any memory and resources obtained in create when this instance was created.

copy( dest, source )
Copy the contents of the source instance to dest. If your instance data contains pointers, you may have to allocate memory for the pointer fields in dest.

load( instance, loadstate )
Read instance data from a file. LightWave® provides an LWLoadState containing functions used to read the data. See the File I/O page.

save( instance, savestate )
Write instance data to a file using the LWSaveState functions. See the File I/O page.
The existence of this callback is optional. When not provided, the save callback must set to NULL. Doing so prevent saving the plugin's data. Upon loading, the existence of the plugin will not exist in this sitiation and it will not get instanced. This is useful for Master Class handlers that are meant to be LAYOUT types (they survive a scene clear). Saved scenes would not contain the plugin; and therefore, loading the scene would not create a duplicate instance of it. Another use is for save-disabling a demonstration version of a plugin.

descln( instance )
Provide a human-readable description of the instance data. This is a single string displayed to the user on the LightWave® interface and should be short enough to fit there. It can contain anything, but typically it contains shorthand descriptions of the most important settings. This serves as a reminder to the user, who would otherwise have to open your plug-in's interface to check these settings.

Item Handler Extensions

Handler classes that work on items in the scene provide a pair of callbacks that allow them to manage dependencies on other items.

   typedef struct st_LWItemFuncs {
      const LWItemID *  (*useItems) (LWInstance);
      void              (*changeID) (LWInstance, const LWItemID *);
   } LWItemFuncs;
idlist = useItems( instance )
Returns an array of items this instance depends on. If your plug-in's behavior is based on the parameters of other items (such as the positions of objects), you'll want to be re-evaluated after those parameters change, and you use this function to inform Layout of that. The array is terminated by LWITEM_NULL. The function can return NULL if the instance doesn't use any items. It can also return LWITEM_ALL to indicate that it wants to be evaluated after any change occurs.

changeID( instance, idlist )
Notification about a change in item IDs. This function is called if the IDs of items are going to change for any reason. The null-terminated item array passed to this function is of the form "old-1, new-1, old-2, new-2, ..." where the old ID is the value that is changing and the new ID is its new value. Clients should be careful to renumber each item only once.
The changeID callback may also be called when an item's data, such as the geometry of an object, has changed, and when called for this reason, the old and new item IDs will be the same.

Handlers with an LWItemFuncs in their local data are ordinarily called by Layout, but some handler classes (currently image and pixel filters, shaders and textures) can also be called by Modeler for previewing. When called by Modeler, the LWItemFuncs pointer will be NULL. Handlers must test the value of the LWItemFuncs pointer before attempting to fill in the useItems and changeID fields.

Render Handler Extensions

Certain handlers involved directly in rendering also provide callbacks for the start and end of a render session and the start of a new sampling pass.

   typedef struct st_LWRenderFuncs {
      LWError (*init)    (LWInstance, int);
      void    (*cleanup) (LWInstance);
      LWError (*newTime) (LWInstance, LWFrame, LWTime);
   } LWRenderFuncs;
errormsg = init( instance, mode )
Prepare the instance for a new rendering session. This is called before the first frame of a rendering session is begun. The mode will be either LWINIT_PREVIEW or LWINIT_RENDER. Returns a string containing an error message if an error occurs, otherwise returns NULL.

cleanup( instance )
Called after the last frame of a rendering session is completed.

errormsg = newTime( instance, frame, time )
Called at the start of a new sampling pass. This may be called more than once for the same frame but for slightly different times. Returns an error message string or NULL.


This activation function is for an environment handler. The local data includes both the item and render extensions. All of the names on the right side of the equals sign are functions your plug-in provides.

   XCALL_( static int )
   Handler( int version, GlobalFunc *global,
      LWEnvironmentHandler *local, void *serverData )
      if ( version != LWENVIRONMENT_VERSION )
         return AFUNC_BADVERSION;

      local->inst->create   = Create;
      local->inst->destroy  = Destroy;
      local->inst->copy     = Copy;
      local->inst->load     = Load;
      local->inst->save     = Save;
      local->inst->descln   = Descln;

      if ( local->item ) {
         local->item->useItems = UseItems;
         local->item->changeID = ChangeID;

      local->rend->init     = Init;
      local->rend->cleanup  = Cleanup;
      local->rend->newTime  = NewTime;
      local->evaluate = Evaluate;
      local->flags    = Flags;

      return AFUNC_OK;

The Interface Class

Each handler class has an associated interface class with its own activation function. As mentioned in the server description documentation, LightWave® matches handlers with their interfaces by finding matching name strings in the ServerRecord array for a plug-in file.

The interface activation function receives the instance data as the first field of an LWInterface structure. This is the pointer returned by the handler's create function. The interface activation fills in the other fields of the LWInterface to tell LightWave® how the plug-in wants its interface to be presented to the user.

   typedef struct st_LWInterface {
      LWInstance  inst;
      LWXPanelID  panel;
      LWError    (*options) (LWInstance);
      LWError    (*command) (LWInstance, const char *);
   } LWInterface;
An instance returned by the handler's create function. This is read-only.

An xpanel containing the controls for a user interface. The xpanel is created by calling the functions returned by the XPanels global. If this is NULL, LightWave® will use the options callback instead. Some classes receive real estate on LightWave®'s panels for displaying their non-modal xpanel interfaces, so for those classes, the plug-in's interface is "always on," rather than being explicitly invoked by the user.

error = options( instance )
A callback that typically displays a modal panel. This is equivalent to the way the interface activation function itself worked in versions of LightWave® prior to 6.0. LightWave® calls this whenever the user explicitly opens the interface for the associated handler, often by double-clicking on the handler's name in a list. If options is NULL, LightWave® uses the panel to display the plug-in's interface. (Exactly one of the panel and options fields should be non-NULL.)

error = command( instance, cmdstring )
A callback that processes batch commands. This isn't used in LightWave® 6.0 and can safely be set to NULL.


The avisave sample plug-in uses the options function to display the standard Windows codec selection dialog. This is also the approach to take if you're going to display a classic panels interface.

   XCALL_( int )
   Interface( int version, GlobalFunc *global, LWInterface *local,
      void *serverData )
      if ( version != LWINTERFACE_VERSION )
         return AFUNC_BADVERSION;

      local->panel   = NULL;
      local->options = Options;
      local->command = NULL;

      return AFUNC_OK;

Options uses the Win32 ICCompressorChoose function to display the dialog. The window handle of Layout's main window, obtained from the Host Display Info global, is passed as the parent window for the dialog.

   XCALL_( static LWError )
   Options( SampleAVI *avi )
      result = ICCompressorChoose( hdi->window,
         "SampleAVI Options" );
      return NULL;

The NoisyChan sample creates an LWXP_VIEW xpanel that draws its controls in the lower right corner of Layout's graph editor window.

   XCALL_( static int )
   NoisyChannel_UI( int version, GlobalFunc *global, LWInterface *UI,
      void *serverData )
      if ( version != LWINTERFACE_VERSION )
         return AFUNC_BADVERSION;

      GGlobal = global;

      UI->panel   = NoisyXPanel( global, UI->inst );
      UI->options = NULL;
      UI->command = NULL;

      return AFUNC_OK;

The NoisyXPanel function creates the xpanel.

   LWXPanelID NoisyXPanel( GlobalFunc *global, NoisyData *dat )
      LWXPanelFuncs *lwxpf = NULL;
      LWXPanelID     panID = NULL;
      static LWXPanelHint hint[] = {
         XpLABEL(0,"Noisy Channel"),

      lwxpf = (LWXPanelFuncs*)(*global)( LWXPANELFUNCS_GLOBAL,
      if ( lwxpf ) {
         panID = (*lwxpf->create)( LWXP_VIEW, ctrl_list );
         if ( panID ) {
            (*lwxpf->hint)    ( panID, 0, hint );
            (*lwxpf->describe)( panID, data_descrip, NoiseData_get,
               NoiseData_set );
            (*lwxpf->viewInst)( panID, dat );
            (*lwxpf->setData) ( panID, 0, dat);
      return panID;

The Gizmo Class

Some handler classes in Layout have an associated gizmo class with its own activation function. Gizmos are a means for plugins to draw user interfaces in the viewport with which the user can interact by dragging handles. They act like non-modal Layout Tools.

The gizmo activation function receives the instance data as the first field of an LWGizmo structure. This is the pointer returned by the handler's create function. The gizmo activation fills in the other fields of the LWGizmo to set the functions used to draw in the viewports and process user interaction with the gizmo.

   typedef struct st_LWGizmoFuncs {
      void            (*done)     (LWInstance);
      void            (*draw)     (LWInstance, LWCustomObjAccess *);
      const char *    (*help)     (LWInstance, LWToolEvent *);
      int             (*dirty)    (LWInstance);
      int             (*count)    (LWInstance, LWToolEvent *);
      int             (*handle)   (LWInstance, LWToolEvent *, int i, LWDVector pos);
      int             (*start)    (LWInstance, LWToolEvent *);
      int             (*adjust)   (LWInstance, LWToolEvent *, int i);
      int             (*down)     (LWInstance, LWToolEvent *);
      void            (*move)     (LWInstance, LWToolEvent *);
      void            (*up)       (LWInstance, LWToolEvent *);
      void            (*event)    (LWInstance, int code);
      LWXPanelID      (*panel)    (LWInstance);
   } LWGizmoFuncs;

   typedef struct st_LWGizmo {
      LWInstance       instance;
      LWGizmoFuncs     *gizmo;
      const LWItemID* (*pickItems)(LWInstance, const LWItemID *, const unsigned int *);
   } LWGizmo;

The gizmo functions are the same as the Layout Tool functions. However, the following functions currently have no effect:

Gizmos use the plugin instance data, and are therefore destroyed when the plugin instance is destroyed.
Gizmos are non-modal and can not be dropped or activated independent of the plugin.
Use the plugin interface class instead.
From version 2 of the gizmo interface the drawing done by a gizmo can participate in viewport picking by supplying a pickItems function. In version 3 this was expanded to include an array of part numbers:
items = pickItems( instance, drawitems, drawparts )
The drawitems array contains the item IDs that were set with setCSysItem (see below) for those parts of the gizmo drawing that were picked. This array may be NULL if there were no items set, otherwise the array will be terminated with LWITEM_NULL. The array may contain multiple item IDs (for example if the gizmo draws in multiple coordinate systems and a box selection is done), but no duplicates.

If there are items in the array, then there can be an optional drawparts array of part numbers supplied. If not NULL, each entry in the array corresponds with the matching entry in the drawitems array. The values in the array are derived from the part numbers supplied by the LWCustomObjAccess setPart function. There can be multiple part numbers per item. Each value is a bitfield of 32 bits. Part number 1 is mapped to bit 0 (least significant bit), part 2 to bit 1, and so on up to part 32 and bit 31 (most significant bit).

Return an LWITEM_NULL terminated array of items which should become selected or deselected when the user picks the drawing done by the gizmo. It is acceptable to return NULL, which is equivalent to no items. During the picking tests, the gizmo's draw function will be called with the LWCOFL_PICKING flag set.

A common implementation for gizmos which add drawing to items in their coordinate systems would be to simply return drawitems.

Note that a gizmo is not associated with any specific item in the scene, unlike a Custom Object Handler for example. When drawing using an object-relative coordinate system, use the setCSysItem LWCustomObjAccess function to set which item to draw relative to.

A gizmo is automatically enabled if the plugin is enabled. It is up to the gizmo implementation to decide whether or not to draw based on the state of Layout, for example by examining if a particular item is selected or not.

By combining a Master Handler with a gizmo, a non-modal always-on layout tool can be created.