CommandSequence CustomObjHandler Classes Table of Contents


Availability  LightWave® 6.0
Component  Modeler
Header  lwcmdseq.h

Command sequence plug-ins issue commands to create and manipulate geometry in Modeler. They also have access to the same mesh editing functions as the MeshDataEdit class.

Activation Function

   XCALL_( int ) MyCmdSeq( int version, GlobalFunc *global,
      LWModCommand *local, void *serverData );

The local argument to a command sequence's activation function is an LWModCommand.

   typedef struct st_LWModCommand {
      void          *data;
      const char    *argument;
      LWCommandCode (*lookup)   (void *, const char *cmdName);
      int           (*execute)  (void *, LWCommandCode cmd, int argc,
                                   const DynaValue *argv,
                                   EltOpSelect, DynaValue *result);
      MeshEditBegin *editBegin;
      int           (*evaluate) (void *, const char *command);
      void          (*undoGroupBegin) (void);
      void          (*undoGroupEnd) (void);

   } LWModCommand;
An opaque pointer to data used internally by Modeler. Pass this as the first argument to the lookup, execute and evaluate functions.

Users and other plug-ins can invoke your plug-in with arguments, which are stored here as a string.

cmdcode = lookup( data, cmdname )
Returns an integer code corresponding to the command name. The command is issued by passing the command code to the execute function. Command codes are constant for a given Modeler session, so this only needs to be called once per command, after which the codes can be cached and then used in any number of calls to execute.

result = execute( data, cmdcode, argc, argv, selection, cmdresult )
Issue the command given by the command code argument. argv is an array of DynaValue arguments. argc is the number of arguments in the argv array. The selection determines which geometry will be affected by the command and can be any one of the EltOpSelect codes except OPSEL_MODIFY. The result of the command is written in cmdresult. The function returns CSERR_NONE (0) if it succeeds or one of the following non-zero error codes.


edit = editBegin( pnt_bufsize, pol_bufsize, opsel )
Begin a mesh edit. The buffer sizes are used to create temporary buffers associated with each point and polygon. Modeler allocates and frees this memory for you, and you can use it for any per-point or per-polygon data you might need during the edit. Points and polygons are flagged as selected according to the code you pass in opsel.

The editBegin function is identical to the function passed as the local data to mesh edit plug-ins. See that page for complete documentation of the MeshEditOp structure it returns. Command sequence plug-ins can perform multiple mesh edits. Each edit begins by calling this function to get a MeshEditOp and ends when the MeshEditOp's done function is called. No commands can be issued during a mesh edit.

result = evaluate( data, cmdstring )
Issue the command with the name and arguments in the command string. This is an alternative to using lookup and execute. The command and its arguments are written to a single string and delimited by spaces.
This allows for multiple actions to be classified under a single undo operation. Call this before the first action.
Call this to complete a series of actions that are part of a single undo group.

See the Commands pages for a complete list of the commands that can be issued in Modeler, as well as a detailed explanation of the formatting of command arguments for both the execute and evaluate methods.


The DNA sample is a CommandSequence plug-in that builds classic Watson-Crick DNA molecules. It uses the ModLib static-link library, which greatly simplifies command execution by translating commands into function calls. The library currently contains about 170 functions that cover Modeler commands, mesh edit functions, and globals.

This ModLib function executes the MAKEBALL command, building the DynaValue argument list and calling the lookup and execute functions. (ModData is a ModLib structure that caches the LWModCommand pointer and the data returned from a number of globals.)

   int csMakeBall( double *radius, int nsides, int nsegments,
      double *center )
      static LWCommandCode ccode;
      ModData *md = getModData();
      DynaValue argv[ 4 ];

      assert( md->edit == NULL );

      argv[ 0 ].type = DY_VFLOAT;
      argv[ 0 ].fvec.val[ 0 ] = radius[ 0 ];
      argv[ 0 ].fvec.val[ 1 ] = radius[ 1 ];
      argv[ 0 ].fvec.val[ 2 ] = radius[ 2 ];

      argv[ 1 ].type = DY_INTEGER;
      argv[ 1 ].intv.value = nsides;

      argv[ 2 ].type = DY_INTEGER;
      argv[ 2 ].intv.value = nsegments;

      if ( center ) {
         argv[ 3 ].type = DY_VFLOAT;
         argv[ 3 ].fvec.val[ 0 ] = center[ 0 ];
         argv[ 3 ].fvec.val[ 1 ] = center[ 1 ];
         argv[ 3 ].fvec.val[ 2 ] = center[ 2 ];
      else argv[ 3 ].type = DY_NULL;

      if ( !ccode )
         ccode = md->local->lookup( md->local->data, "MAKEBALL" );

      md->cmderror = md->local->execute( md->local->data, ccode,
         4, argv, md->opsel, &md->result );

      return md->cmderror == CSERR_NONE;

Using ModLib makes DNA's command processing almost as simple as scripting. Below is a code fragment from the function in the DNA plug-in that creates the cylinders representing atomic bonds.

   csSetLayer( layer2 );
   csSetDefaultSurface( surface_name( snum ));
   csMakeDisc( r, h, 0, "Y", bond_nsides, bond_nsegments, c );
   csRotate( xrot, "X", NULL );
   csRotate( yrot, "Y", NULL );
   csMove( pt );
   rot = 36 * j;
   csRotate( rot, "Y", NULL );
   csSetLayer( layer1 );