HandlersFormally, 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;
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;
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;
Example 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; } 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;
Example 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, ICMF_CHOOSE_ALLCOMPRESSORS, NULL, NULL, &cv, "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"), XpEND }; lwxpf = (LWXPanelFuncs*)(*global)( LWXPANELFUNCS_GLOBAL, GFUSE_TRANSIENT ); 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; } 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:
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. |