
LightWave Plug-in Architecture -- Stuart Ferguson 5/3/95

1      Plug-In Interface
    1.1    Server Identification
    1.2    Server Activation Function
    1.3    The Global Function
    1.4    Plug-in and Built-in Servers

2      Server Interface
    2.1    Plug-in Initialization and Cleanup
      (1)    Startup usage
      (2)    Shutdown usage
    2.2    Activation Function
      (3)    Activation function args
      (4)    ActivateFunc type
    2.3    Global Function
      (5)    GlobalFunc types
      (6)    GlobalFunc types
    2.4    The Global Server Class
      (7)    Global activation data
    2.5    External Function Entry Points
      (8)    XCALL Definitions
    2.6    Single-Service Plug-ins
      (9)    Activate usage
    2.7    Multiple-Service Plug-ins
      (10)   ServerRecord type

3      Common Globals
    3.1    Host Display Info
      (11)   Host Display Info declaration
    3.2    Monitor Objects
      (12)   Monitor types
      (13)   Monitor declarations

4      Example Plug-in Service
    4.1    String Transform Class
      (14)   Test types
      (15)   Test types
    4.2    String Transform Functions
      (16)   String transform arguments
	4.2.1  Length Operation
	  (17)   Length function body
	4.2.2  Reverse Operation
	  (18)   Reverse function body
	4.2.3  Capitalization Operation
	  (19)   Capitalize function body
	4.2.4  Double Operation
	  (20)   Double function body
    4.3    Implementing Servers
	4.3.1  Single-Service Plug-in -- Reverse
	  (21)   Test Reverse plug-in program
	4.3.2  Multiple-Service Plug-in -- Caps & Double
	  (22)   Test Caps and Double plug-in program
	4.3.3  Built-in Server -- Length
	  (23)   Test host utilities
	4.3.4  Global Test Server
	  (24)   Test Global Server plug-in

5      Creating a Plug-in
    5.1    Amiga -- SAS/C Compiler
      (25)   Makefile examples
    5.2    Amiga -- Manx Compiler
      (26)   Makefile examples
    5.3    Microsoft's Windows
      (27)   Makefile examples
      (28)   Alignment Table
    5.4    SGI Unix
      (29)   Makefile examples
    5.5    Linking with LightWave
      (30)   Config file examples
      (31)   Config file examples


1    Plug-In Interface

There are two parts to the system-generic plug-in interface: the host
side and the server side.  The host is the application program which
wants to load external code modules to perform some generic type of
operation.  Servers are imported routines (which can be loaded
plug-ins or internal built-ins) which implement a specific instance of
a generic type of service.

The host interface provides facilities to create server classes,
register plug-in modules, and perform lazy loading and activation of
registered servers.  There is a fairly elaborate name and type mapping
scheme which allows a great deal of flexibility in how modules are
used, but which still provides a fairly simple interface for those who
do not need the full facility.

The server interface provides an easy method to write programs that
will operate as plug-ins.  Different classes of plug-in services will
require different host interfaces, but the loading and initialization
part of the server interface is standard and works with the host
portion of the system.


1.1    Server Identification

The plug-in interface is designed to allow the host to have any number
of servers loaded to perform as many different functions as the host
wants to define.  The servers in the system are referenced by a
combination of class and name.

A Server Class is a string which determines the type of service which
the server can perform.  This might be strings like "TEXTURE" or
"FileRequester".  Many servers can have the same class, and all
servers of the same class have the same host interface.

A Server Name is a string which refers to a specific server within a
given class.  This might be something like "FractalNoise3D" or
"Default".  The name must be unique among the servers of the same
class.

The names for class and server identification should be byte strings
containing characters only the the ASCII range 33-127.  By convention
these string contain no spaces and no characters outside 7-bit ASCII.
Case is significant in distinguishing different classes and servers
within classes.


1.2    Server Activation Function

Every server has a single `activation' function.  This is the function
which the host calls to access the service provided by the server.
For some servers this one function will perform the whole action and
for others this will only be a prelude to a sequence of actions.
Servers which must remain loaded after they return from their
activation function must be locked by the host while there are actions
pending or they may be unloaded.


1.3    The Global Function

The activation function for every server is called with a `global'
function pointer which provides access to the internal global state of
the host system.  The server calls the function with a string
identifing the global data requested and a flag for how it will be
used.  The host can service this request, or the request can be passed
on to global plug-in servers.


1.4    Plug-in and Built-in Servers

Servers can be either plug-in or built-in.  A plug-in server is
implemented as a file containing code that can be loaded and unloaded
as needed.  A built-in server is implemented as a callback within the
host itself.  Having both allows the host to provide a standard set of
servers which it handles the same way it handles plug-in servers,
without having to unbundle their functionality in a way that can be
replaced or used by other programs.


2    Server Interface

A plug-in server is written like any ordinary C program, but instead
of a single "main()" entry point, a server has a different primary
entry point and several possible additional entry points.  The server
is linked with initializaion code (different from the normal shell or
Workbench init) which places these interfaces where the host can
access them.

There are two main types of plug-in modules: those providing a single
server and those providing multiple servers.  It is simple to have one
server per module, but it can be more efficient and useful to define
many servers with a single code file.

All servers require an activation function, and all plug-ins have the
option of providing initialization and cleanup functions.  The header
for server types is `splug.h'.


2.1    Plug-in Initialization and Cleanup

In both the single and multiple versions of the plug-in module, there
are optional entry points which allow the module to initialize itself
when it is first loaded and to clean itself up before being unloaded.
If the plug-in code does not contain functions with these names, no
attempt will be made to call them.

The Startup function, if present, will be called when the plug-in is
first loaded into the host system.  The return value is global data
for the server which is passed to the Activate and Shutdown entry
points as ` serverData'.  A zero return value (null pointer) indicates
failure, so even a plug-in with no data should return something.

    (1)  Startup usage

		void *
	Startup (void)

If provided, the server's Shutdown function is called just before the
server module is unloaded from the host.  Any allocated server data
should be freed at this point.  Note that even though it is an error,
this function may be called even when the server is locked, so correct
cleanup should be done in this case as well.

    (2)  Shutdown usage

		void
	Shutdown (
		void                    *serverData)


2.2    Activation Function

All servers have a single activation function which is the entry point
for the host to get access to the service provided by the server.  The
activation function gets passed the version number for the service
implementation, the `global' pointer to access global host data,
class-specific `local' data, and private data maintained by the
plug-in.  The version number is application-defined, but typically it
represents the revision of the interface that the host expects the
server to use.  Typically a server will not attempt to operate if the
version number is greater than it expects.  The ` serverData' is
returned by the Startup entry point in a plug-in.  The global function
can be called to get global data from the host enviroment, and the
contents of the `local' pointer are defined by the type of service.

    (3)  Activation function args

	long             version,
	GlobalFunc      *global,
	void            *local,
	void            *serverData

The activation function returns an error code if the attempt to call
failed because of some clash between the server and the host
environment.  If the server was able to process the request, even it
failed to complete it, it should return AFUNC_OK.  If the version
number is not a value which the server can explicitly handle it should
return AFUNC_BADVERSION.  If there is some global data the server
cannot get which it requires it should return AFUNC_BADGLOBAL.  Severe
problems with the contents of the local data, such as some necessary
pointer in the local data being null, may be reported by returning
AFUNC_BADLOCAL.  Any other errors from the server (running out of
memory, bad filenames, user aborts, etc.) must be provided for by the
specific plug-in protocol.

    (4)  ActivateFunc type

	typedef int     ActivateFunc (<Activation function args>);

	#define AFUNC_OK                0
	#define AFUNC_BADVERSION        1
	#define AFUNC_BADGLOBAL         2
	#define AFUNC_BADLOCAL          3


2.3    Global Function

The global function passed by the host to the server is a special
function which returns the pointer to some global data given by a
string ID.  These data blocks will often contain function pointers,
but can be anything.

    (5)  GlobalFunc types

	typedef void *          GlobalFunc (const char *, int);
	. . .

When a server calls the global function, it passes a string which
identifies the global data required and a code for the way the data
will be used.  If the data pointer is not available, null is returned.
The ID's that will be recognized depends on the host, on the available
global plug-ins and perhaps on the server class.

The use code depends on how the result of the call will be used.  If
the returned pointer will only be used for the course of the
activation function itself, the TRANSIENT code should be used.  If the
data will be used after the activation function returns, such as in a
server that requires locking, the ACQUIRE code should be used.  In
this case there must be a matching RELEASE call made when the data
pointer is no longer required.  RELEASE calls need only be made for
ACQUIRE calls which returned a non-null pointer.  The return value
from a release mode global data call is undefined.

    (6)  GlobalFunc types
	. . .
	#define GFUSE_TRANSIENT         0
	#define GFUSE_ACQUIRE           1
	#define GFUSE_RELEASE           2


2.4    The Global Server Class

The server class given by the name "Global" is special in that it
allows multiple plug-in servers to share common data or routines.  In
fact, the members of the Gobal class are extensions to the set of ID
strings that can be passed to the "global" function.

When a server calls the global function with an ID string, the host
can service the request itself or has the option of pass unrecognized
ID's to Global class servers of the same name.  For example, if the ID
is "Mambo Functions," the host may recognize this itself and return a
pointer value.  If it does not recognize it, it may attempt to
activate a server of class "Global" with name "Mambo Functions." If
such a server exists, it may be locked or unlocked, depending on the
use type of the global request, and it will be called to get the value
of the global pointer for the orignal requester.

The activation function of a Global server is called with a
GlobalService structure which will be initialized with the ID string
for the request.  The server must fill in the data pointer with a
value which will be returned to the client, which may be null if the
server wishes to deny the request.  The string is passed as data so
that the same activation function may be used for multiple servers.

    (7)  Global activation data

	typedef struct st_GlobalService {
		const char      *id;
		void            *data;
	} GlobalService;


2.5    External Function Entry Points

Functions in the plug-in get called directly by the host, and this is
a funky thing in some systems since they are different environments.
The XCALL_ and XCALL_INIT macros take care of everything for all
different systems and compilers, so these can be used to make
multi-platform servers from a single source code.

XCALL_ is used on the return type, e.g.  XCALL_(int) for an external
entry point returning an int.  XCALL_INIT is used as the first
statement of the function.  Both must be used for full compatibility,
but XCALL_INIT is only non-null for Manx small-code modules.

    (8)  XCALL Definitions

	<XCALL_ and XCALL_INIT system-specific definition>

The activation function as well as any function pointers returned from
the activation function need the XCALL treatment.  Startup and
Shutdown do not.


2.6    Single-Service Plug-ins

A single-service plug-in is a C program with an entry point for the
activation callback and global symbols for the class and name of the
server.  There are also optional entry points for initialization and
cleanup.

This plug-in must contain a global character string with the name
`ServerClass'.  This string defines the class of this server and the
server will not be loaded if this string does not match the service
type string requested by the host.

It must also contain a global character string called `ServerName'
which holds the name for this specific server.

The activation function must be called Activate, which takes the
arguments as described above.

    (9)  Activate usage

		XCALL_(int)
	Activate (<Activation function args>)


2.7    Multiple-Service Plug-ins

A multiple-service plug-in is a C program which defines multiple
servers through a standard set of global symbols.  In particular, a
multiple server module must contain a global array with the name
`ServerDesc' composed of elements of the ServerRecord type.  The last
record in the array must have a null class name pointer.

    (10)  ServerRecord type

	typedef struct st_ServerRecord {
		const char      *class;
		const char      *name;
		ActivateFunc    *activate;
	} ServerRecord;

The plug-in module may also have Startup and Shutdown entry points,
and all the activate functions in the plug-in will get the same
serverData as returned from the Startup function.  The assumption is
that the servers all share a module for some logical reason, so the
sharing of global data is not unreasonable.


3    Common Globals

There are a few global data types which are so basic that they are the
same across plug-in hosts or are used in a wide range of plug-in
interfaces.


3.1    Host Display Info

A plug-in may need to open windows to get user input, and since they
run in the host's context, they will need to do this using the host's
display information.  This info, which can be normally accessed with
the "Host Display Info" ID string, contains information about the
windows and display context used by the host.  If this ID yeilds a
null pointer, the server is probably running in a batch mode and has
no display context.

The fields of the HostDisplayInfo structure vary from system to
system.  On the Amiga, the screen pointer is provided for custom
screens and is null for Workbench applications.  The window pointer is
the main application window or null if there is none.  On X systems,
the window session handle is passed, as well as the ID of the main
application window, if any.  On Win32 systems, the application
instance and main window are provided.

    (11)  Host Display Info declaration

	typedef struct st_HostDisplayInfo {
	    #ifdef _AMIGA
		struct Screen   *screen;
		struct Window   *window;
	    #endif

	    #ifdef _XGL
		Display         *xsys;
		Window           window;
	    #endif

	    #ifdef _WIN32
		HANDLE           instance;
		HWND             window;
	    #endif
	} HostDisplayInfo;

This structure is defined in the `hdisp.h' header file.


3.2    Monitor Objects

Monitors are simple data structures defining an interface which the
server can use to give feedback to the host on its progress in
performing some task.  They are sometimes passed servers to give
feedback on the progress of the particular operation, and can
sometimes be accessed from within a server that wants to show its
progress on a slow operation using the host's normal feedback display.

A Monitor consists of some generic data and three functions: init,
step and done.  The `init' function is called first with the number of
steps in the process to be monitored, which is computed by the server.
As the task is processed, the `step' function is called with the
number of steps just completed (often one).  These step increments
should eventually add up to the total number and then the `done'
function is called, but `done' may be called early if there was a
problem or the process was aborted.  The `step' function will return
one if the user requested an abort and zero otherwise.

    (12)  Monitor types

	typedef struct st_Monitor {
		void             *data;
		void            (*init) (void *, unsigned int);
		int             (*step) (void *, unsigned int);
		void            (*done) (void *);
	} Monitor;

The server is masked from any errors in the monitor that may occur on
the host side of the interface.  If there is a problem with putting up
a monitor, the functions will still return normally, since the monitor
is for user feedback and is not that critical.

There are some macros provided to call a monitor which will do nothing
if the monitor pointer is null.  MON_INCR is used for step sizes
greater than one and MON_STEP is used for step sizes exactly one.

    (13)  Monitor declarations

	#define MON_INIT(mon,count)     if (mon) (*mon->init) (mon->data,
	   count)
	#define MON_INCR(mon,d)         (mon ? (*mon->step) (mon->data, d) :
	   0)
	#define MON_STEP(mon)           MON_INCR (mon, 1)
	#define MON_DONE(mon)           if (mon) (*mon->done) (mon->data)

These structures and macros are described in the `moni.h' header file.


4    Example Plug-in Service

This describes a hypothetical server class and creates some samples of
plug-in modules using it.  This serves as a testbed for third parties
to create test plug-ins, so it should have some general capability.


4.1    String Transform Class

This server class will perform manipulations on character strings,
like reverse them, capitalize them, etc.  This class will be
"StringXfrm".

A new server class is completely defined by the semantics of the
activation function for the class.  The activation function takes a
pointer argument from the host, `local' which is a reference to data
for the particular service the host needs performed.  It also gets a
`global' function pointer which will return global data as needed by
the server.

The `local' pointer will point to a StringLocal structure which holds
the data for the current operation.  This is a null-terminated string
and the length of the string buffer, plus a temporary scratch buffer
and its length.  The server will overwrite `buf' with the result, and
will set the `overflow' status flag if the buffers were too short.

    (14)  Test types

	typedef struct st_StringLocal {
		char            *buf;
		char            *tmpBuf;
		int              len, tmpLen;
		int              overflow;
	} StringLocal;
	. . .

For the string transform class of server, the global function can
return a `progress' function which can be called by the server to give
the user feedback about its progress.  This is returned using a string
ID of "Progress Function."

    (15)  Test types
	. . .
	typedef void            StringProgress (void);

We'll stick these definitions into the `t_plug.h' header file for test
modules to use.


4.2    String Transform Functions

The functions to do string transformations are all the same.  They all
get the same arguments as defined by the format of the activation
function.  The local pointer is specific to the string transform
class.  There is no ` serverData' for any of the transforms since
there is no Startup function.

    (16)  String transform arguments

	long                     version,
	GlobalFunc              *global,
	StringLocal             *local,
	void                    *serverData

String activation functions may return with an error code if the
version number is wrong or if the global progress function is not
available.

    4.2.1    Length Operation

    The length operation gets the length of the string and prints that
    as a number into the string buffer.

	(17)  Length function body

	    {
		    if (version != 1)
			    return AFUNC_BADVERSION;

		    if (local->len < 10)
			    local->overflow = 1;
		    else
			    sprintf (local->buf, "%ld", strlen (local->buf));

		    return AFUNC_OK;
	    }

    4.2.2    Reverse Operation

    The reverse operation copies the characters from the main buffer
    to the temp buffer in reverse order and then copies them back.
    This could use a swap operation to reverse them in place, but this
    method demonstrates using the temp buffer and returning an
    overflow if the temp buffer is too small.  This also calls the
    progress function as it swaps.

	(18)  Reverse function body

	    {
		    StringProgress          *progress;
		    int                      len, i;

		    if (version != 1)
			    return AFUNC_BADVERSION;

		    progress = (*global) ("Progress Function", GFUSE_TRANSIENT
		       );
		    if (!progress)
			    return AFUNC_BADGLOBAL;

		    len = strlen (local->buf);
		    if (local->tmpLen <= len) {
			    local->overflow = 1;
			    return AFUNC_OK;
		    }

		    for (i = 0; i < len; i++) {
			    local->tmpBuf[i] = local->buf[len - i - 1];
			    (*progress) ();
		    }
		    local->tmpBuf[len] = 0;

		    strcpy (local->buf, local->tmpBuf);
		    return AFUNC_OK;
	    }

    4.2.3    Capitalization Operation

    This just passes through the string and converts each letter to
    uppercase, calling the progress function as it goes.  This will
    also use the global empty string if there are no characters
    passed.

	(19)  Capitalize function body

	    {
		    StringProgress          *progress;
		    const char              *empty;
		    char                    *c;

		    if (version != 1)
			    return AFUNC_BADVERSION;

		    progress = (*global) ("Progress Function", GFUSE_TRANSIENT
		       );
		    empty = (*global) ("EmptyStringText", GFUSE_TRANSIENT);
		    if (!progress || !empty)
			    return AFUNC_BADGLOBAL;

		    if (local->buf[0]) {
			    for (c = local->buf; *c; c++) {
				    (*progress) ();
				    if (*c >= 'a' && *c <= 'z')
					    *c = *c - 'a' + 'A';
			    }
		    } else
			    strncpy (local->buf, empty, local->len - 1);

		    return AFUNC_OK;
	    }

    4.2.4    Double Operation

    This doubles each character in the string by copying the buffer to
    the temp buffer and moving twice as many characters back into the
    buffer from there.  This will fail if the buffers are not big
    enough.

	(20)  Double function body

	    {
		    StringProgress          *progress;
		    int                      len, i;

		    if (version != 1)
			    return AFUNC_BADVERSION;

		    progress = (*global) ("Progress Function", GFUSE_TRANSIENT
		       );
		    if (!progress)
			    return AFUNC_BADGLOBAL;

		    len = strlen (local->buf);
		    if (local->tmpLen < len || local->len - 1 < len * 2) {
			    local->overflow = 1;
			    return AFUNC_OK;
		    }

		    strcpy (local->tmpBuf, local->buf);
		    for (i = 0; i < len; i++) {
			    local->buf[i * 2]     = local->tmpBuf[i];
			    local->buf[i * 2 + 1] = local->tmpBuf[i];
			    (*progress) ();
		    }
		    local->buf[len * 2] = 0;

		    return AFUNC_OK;
	    }


4.3    Implementing Servers

A plug-in module is really a wrapper around the activation function,
and can be implemented several ways.  They can be single-service
plug-ins, multiple-service plug-ins, or built-in.  This test includes
one of each.

    4.3.1    Single-Service Plug-in -- Reverse

    The reverse operation is implemented as a single-service plug-in,
    so there is one global class and server name.  The activation
    function is called `Activate' (which it must be).

    The C program module itself includes the headers for the test
    system and server-side plug-ins.  The source file is `tp_rev.c'.

	(21)  Test Reverse plug-in program

	    #include <splug.h>
	    #include "t_plug.h"
	    #include <string.h>

	    char            ServerClass[] = "StringXfrm";
	    char            ServerName[]  = "REVERSE";

		    XCALL_(int)
	    Activate (<String transform arguments>)
	    {
		    XCALL_INIT;
		    <Reverse function body>
	    }

    4.3.2    Multiple-Service Plug-in -- Caps & Double

    The capitalize and double operations are implemented as one
    multiple-service plug-in with two servers.  The activation
    function entry points can have any name and are not exported
    symbols.  They are associated with their server name in the
    exported array of ServerRecords which has the required name
    `ServerDesc'.  The source file for this is `tp_cpdb.c'.

	(22)  Test Caps and Double plug-in program

	    #include <splug.h>
	    #include "t_plug.h"
	    #include <string.h>

		    static XCALL_(int)
	    Capitalize (<String transform arguments>)
	    {
		    XCALL_INIT;
		    <Capitalize function body>
	    }

		    static XCALL_(int)
	    Double (<String transform arguments>)
	    {
		    XCALL_INIT;
		    <Double function body>
	    }

	    const char              class[] = "StringXfrm";
	    ServerRecord            ServerDesc[] = {
		    { class, "CAPS",        Capitalize },
		    { class, "DOUBLE",      Double },
		    { NULL }
	    };

    4.3.3    Built-in Server -- Length

    The length operation will be implemented as a built-in.  As
    result, all we need is a local function entry point of any name in
    the host program.

	(23)  Test host utilities

		    static int
	    ActLength (<String transform arguments>)
	    {
		    <Length function body>
	    }
	    . . .

    4.3.4    Global Test Server

    This test program includes a global server which just returns a
    string for clients to use when passed an empty string.  This
    global's activation function gets a GlobalService request block
    with the `id' set to the requested string.  In this case, this
    MUST be the same as the server name.  The function returns a
    global pointer in the `data' field.

	(24)  Test Global Server plug-in

	    #include <splug.h>
	    #include <string.h>

	    char            ServerClass[] = "Global";
	    char            ServerName[]  = "EmptyStringText";
	    char            result[] = "** Empty String **";

		    XCALL_(int)
	    Activate (
		    long             version,
		    GlobalFunc      *global,
		    GlobalService   *local,
		    void            *data)
	    {
		    XCALL_INIT;
		    if (strcmp (local->id, ServerName) != 0)
			    return AFUNC_BADLOCAL;

		    local->data = result;
		    return AFUNC_OK;
	    }


5    Creating a Plug-in

Methods for creating plug-ins have been developed for each of the
target platforms.  Versions of a plug-in can be created for the
different systems from a single source code with different linking
instructions.  Each case that follows includes an implicit makefile
rule to create a ".p" plug-in module from an object file.  The macro
SLIB stands for the directory where the startup code and server
libraries are located.  SINC is the include directory and OTHER_LIBS
would be any other libraries need by the module.

The final section shows how to add your plug-in to the LightWave host.


5.1    Amiga -- SAS/C Compiler

Linking under SAS/C on the Amiga requires replacing the normal startup
code with plug-in startup code, `serv_s.o'.  This can be done by using
the "startup" option when using "sc link" or by placing `serv_s.o'
first in the "FROM" list when using slink.  Modules must also be
linked with the server library.  Object modules should be built
without stack checking.

    (25)  Makefile examples

	.o.p:
		sc link $(CFLAGS) startup=$(SLIB)serv_s.o $*.o\
		 $(SLIB)server.lib $(OTHER_LIBS) pname=$@
	. . .

The math options to the compiler must be chosen so that doubles are
64-bit IEEE values.  There is currently some difficulty using the
"math=68881" option, however, having to do with the startup code in
serv_s.a.


5.2    Amiga -- Manx Compiler

Linking under the Manx compiler on the Amiga requires using the
plug-in startup code `serv_m.o', which must be placed first in the
list of objects passed to ln.  The linker will warn about ".begin" and
"_geta4" overriding library symbols, which is correct behavior in this
case.  They should also be linked with the "server_m" library to get
the Manx server library.

    (26)  Makefile examples
	. . .
	.o.p:
		ln -o $@ $(SLIB)serv_m.o $*.o -lserver_m $(OTHER_LIBS)
	. . .

Manx modules must use 32-bit ints and IEEE format floating point
values.


5.3    Microsoft's Windows

Plug-in modules under Windows are just DLLs created by linking with
`serv_w.obj' and `server.lib'.  There is no need to create a ".lib" or
".exp" file for the DLL, but the ".def" file should contain an export
statement for the global address `_mod_descrip'.  A usable default def
file is provided as "serv.def" in the main include directory.  There
is no DLL entry point function.

    (27)  Makefile examples
	. . .
	.obj.p:
		link32 -dll -out:$@ -def:$(SINC)serv.def $*.obj\
		 $(SLIB)serv_w.obj server.lib $(OTHER_LIBS)
	. . .

Structure alignment may vary among different compilers and can cause
problems when trying to communicate between the host and a plug-in
DLL.  The LightWave host is compiled using Microsoft alignment rules.
Here's an excerpt on structure alignment from the MS Visual C
documentation:

"Applications should generally align structure members at addresses
that are 'natural' for the data type and the processor involved.  For
example, a 4-byte data member should have an address that is a
multiple of four.

"This principle is especially important when you write code for
porting to multiple processors.  A misaligned 4-byte data member,
which is on an address that is not a multiple of four, causes a
performance penalty with an 80386 processor and a hardware exception
with a MIPS RISC processor.  In the latter case, although the system
handles the exception, the performance penalty is significantly
greater.  The following guidelines ensure proper alignment for
processors targeted by Win32:

    (28)  Alignment Table

	"Type                   Alignment
	 ----                   ---------
	 char                   Align on byte boundaries
	 short (16-bit)         Align on even byte boundaries
	 int and long (32-bit)  Align on 32-bit boundaries
	 float                  Align on 32-bit boundaries
	 double                 Align on 64-bit boundaries
	 structures             Largest alignment requirement of any member
	 unions                 Alignment requirement of the first member

"The compiler automatically aligns data in accordance with these
requirements, inserting padding in structures up to the limit (default
pack size) specified by the /Zp option or #pragma pack.  For example,
/Zp2 permits up to 1 byte of padding, /Zp4 permits up to 3 bytes of
padding, and so on.  The default pack size for Windows 3.x is 2,
whereas the default for Win32 is 8."


5.4    SGI Unix

Plug-in modules under IRIX are shared object modules linked with
`serv_u.o' and `libserver.lib'.  The DSO should export the
"_mod_descrip" symbol and use "serv_u" as startup code.

The link line should include any other libraries that the plug-in
would need as a stand-alone program.  Since most libs on the SGI are
themselves DSOs, this adds very little to the size of the plug-in and
adds no extra runtime overhead.

    (29)  Makefile examples
	. . .
	.o.p:
		ld -shared -exported_symbol _mod_descrip -L$(SLIB)\
		 $(SLIB)serv_u.o $*.o -o $@ -lserver $(OTHER_LIBS)

Normally the plug-in DSO's are loaded in a way that forces resolution
of all symbols.  This allows the host program to report undefined
symbols to the plug-in developer.  If the name of the module includes
the substring "__lazy" (lowercase), however, then the lazy evaluation
mode is used, allowing the module to contain undefined symbols as long
as they are not referenced by any executed code.  This is normally not
needed unless you are using code from an external vendor which
includes undefined but unused symbols, like the HIIP library from
Elastic Reality.


5.5    Linking with LightWave

LightWave and Modeler read the names of servers from their startup
configuration files.  This method is much faster than scanning a
directory path and allows for some user customization of plug-in names
(such as national localization).  It does require that the config file
be accurate, since the host will blindly attempt to use servers that
may not exist.  This is non-fatal but may be disconcerting to the
user.

For Modeler, for example, the config file on the Amiga is
"MOD-config", on the SGI is ".lwmrc" and on Windows is "LWM.CFG".
This file can contain any number of lines of the following form:

    (30)  Config file examples

	Plugin <class> <name> <module> <user name>
	. . .

Each line describes a single server given by Class and Name.  The
module is the plug-in file containing the server and the user name is
the string to display on the interface for describing the server's
function.  Class, name and module are delimited by spaces, and the
user name is the rest of the line.  Here are some examples (lines wrap
for readability -- each statement has to be a single line).

    (31)  Config file examples
	. . .
	Plugin CommandSequence Demo_AllBGLayers layerset.p Include Background
	Plugin CommandSequence Demo_NextEmptyLayer layerset.p Next Empty
	Plugin MeshDataEdit Demo_MakeSpikey z:lw/plugin/spikey.p Spikey
	   Subdivide
	Plugin ImageLoader PDQ_Targa pdq/targa.lwp Truevision Targa Image
 
====================================

LightWave Images -- Stuart Ferguson 1/13/95

1      Introduction
  (1)    Public declarations
  (2)    Public forward definitions

2      Image I/O Server Interface
    2.1    Image Loaders
      (3)    Public types
    2.2    Image Savers
      (4)    Public types
    2.3    Result Value
      (5)    Public declarations
    2.4    Image Transfer Protocols
	2.4.1  Color Protocol
	  (6)    Public types
	2.4.2  Index Protocol
	  (7)    Public types
	2.4.3  Generic Protocol
	  (8)    Public types
	  (9)    Public forward definitions
	2.4.4  Error Handling
	2.4.5  Misc Types
	  (10)   Public declarations
	  (11)   Public declarations

3      Test Server
    3.1    Targa Reader
      (12)   Targa types
      (13)   Targa functions
      (14)   Targa utilities
      (15)   Read targa data
      (16)   Read targa lines
      (17)   Read uncompressed targa line
      (18)   Read compressed targa line
      (19)   Read a targa pixel element into `bgra'
      (20)   Store `bgra' pixel to line buffers
    3.2    Targa Saver
      (21)   Targa types
      (22)   Targa functions
      (23)   Targa utilities
      (24)   Targa utilities
      (25)   Targa utilities
    3.3    Plug-in Module
      (26)   Targa Image server


1    Introduction

This module provides interfaces for dealing with image types commonly
employed by LightWave users.  This allows the loading and saving of
large, deep images in an expandable set of formats, and for accessing
the data in a uniform manner regardless of the underlying data format.
This interface is designed with plug-in image loaders and savers in
mind and it provides some built-in IFF format support.

Image types are given by the following values.  RGB24 is an image with
eight bits each of red, green and blue data for each pixel.  GREY8 is
an image with eight bits of greyscale value at each pixel.  INDEX8 is
an image with up to eight bits of color index at each pixel, mapped
through a 24 bit color table.

    (1)  Public declarations

	#define IMG_RGB24       0
	#define IMG_GREY8       1
	#define IMG_INDEX8      2
	. . .

Image color component, grey or index values are all unsigned chars
scaled from 0 to 255.

    (2)  Public forward definitions

	typedef unsigned char            ImageValue;
	. . .


2    Image I/O Server Interface

The image input and output interfaces are designed to be extended with
plug-in loaders and savers.  As result, each interface really only
defines the local data structure for the activation function.


2.1    Image Loaders

Image loaders are servers that are called sequentially until one is
able to load the image file.  An application will normally have a
standard format in which images are saved, so that will normally be
tried first after which other loaders may be tried in any order the
host can determine.  If loaders are just scanned in the host plug-in
database they will be called in something like alphabetical order.

The activation call for a loader gets passed a pointer to a filename
as well as callbacks for image data transfer.  If the loader cannot
open the file it sets the `result' field to IPSTAT_BADFILE and
returns.  If it does not recognize the file format, it sets the result
to IPSTAT_NOREC.  If it can load the image, it calls the `begin'
callback with type of image protocol it would like.  The loader then
sends the data from the file to the host through the protocol and
calls the `done' callback when complete to allow the source to dispose
of the protocol.  These callbacks are called with the `priv_data'
pointer as the first field.

    (3)  Public types

	typedef struct st_ImLoaderLocal {
		void             *priv_data;
		int               result;
		const char       *filename;
		Monitor          *monitor;
		ImageProtocolID (*begin) (void *, int type);
		void            (*done) (void *, ImageProtocolID);
	} ImLoaderLocal;
	. . .


2.2    Image Savers

Image savers are servers of "ImageSaver" class that write an image out
to a file in a single specific format.  The save format is typically
chosen directly by the user with an interface showing the user names
for the servers, so no scanning or ordering is required.

The activation call for savers gets a filename, a requested protocol
type, and a callback for the host to output its image data to the
saver protocol.  The flag in the `sendData' callback can contain the
IMGF_ALPHA bit if the saver can store alpha data and IMGF_REVERSE bit
if the saver wants the data sent bottom to top rather than top to
bottom.  The saver should create a protocol and set flags most
appropriate for the destination file format.  The `sendData' callback
will return a non-zero error code if anything failed on the sending
end or if the destination reports an error.

    (4)  Public types
	. . .
	typedef struct st_ImSaverLocal {
		void            *priv_data;
		int              result;
		int              type;
		const char      *filename;
		Monitor         *monitor;
		int            (*sendData) (void *, ImageProtocolID, int);
	} ImSaverLocal;
	. . .


2.3    Result Value

The result value indicates the status of the loader or saver upon
completion.  If the load or save was sucessful, the value should be
IPSTAT_OK.  If a loader fails to recognize a file as something it can
load it should set the result to IPSTAT_NOREC.  If the server could
not open the file it should return IPSTAT_BADFILE.  Any other error is
just a generic failure of the loader or saver and so should set the
result to IPSTAT_FAILED.  Other failure modes might be possible if
required in the future.

    (5)  Public declarations
	. . .
	#define IPSTAT_OK                0
	#define IPSTAT_NOREC             1
	#define IPSTAT_BADFILE           2
	#define IPSTAT_ABORT             3
	#define IPSTAT_FAILED           99
	. . .


2.4    Image Transfer Protocols

Images are passed from source to destination using an image protocol.
Typically, the source will select the protocol type and the
destination will create a protocol of that type.  The source will then
send the image data to the source by calling callbacks in the
protocol.  Both ends are then given an opportunity to clean up.  This
is called a pusher protocol since the source "pushes" the data at the
destination rather than the destination pulling it.

There are two protocols for the three types of images: color and index
protocols.  The protocol `type' can have any of the same values as
image type and determines the callbacks in the protocol and what they
do.  Protocols contain a private data pointer which should be passed
as the first argument to all the callbacks.

    2.4.1    Color Protocol

    The color protocol is used for the RGB and grey valued images
    (RGB24 and GREY8 types).  The source starts the output by calling
    the `setSize' function with the width and height of the image and
    flags.  The flags can contain the IMGF_ALPHA bit to indicate that
    the source data contains an alpha channel.  The source then sends
    the data by calling the `sendLine' function with each image row
    number and a pointer to a line of image data and a line of alpha
    data, if any was indicated.  For greyscale images, the image line
    consists of one image value per column in the image (G1 G2 ...
    Gw).  For RGB images, this line data consists of three image
    values per column of the image in RGB order (R1 G1 B1 R2 G2 B2 ...
    Rw Gw Bw).  The alpha data is in greyscale format.

	(6)  Public types
	    . . .
	    typedef struct st_ColorProtocol {
		    int              type;
		    void            *priv_data;
		    void           (*setSize) (void *, int, int, int);
		    int            (*sendLine) (void *, int, const ImageValue
		       *,
						const ImageValue *);
		    int            (*done) (void *, int);
	    } ColorProtocol;
	    . . .

    2.4.2    Index Protocol

    Colormap index images use the index protocol.  The source must
    first call `setSize' and `numColors' with image size, flags and
    number of entries in the colormap.  The source must then set the
    colormap by calling the `setMap' callback for each entry in the
    colormap.  Any entry which is not set is left undefined.  The data
    in the image is then filled in using the `sendLine' function just
    like the greyscale case except that the image values are not grey
    values but colormap indices.  Alpha values are in greyscale data
    format.

	(7)  Public types
	    . . .
	    typedef struct st_IndexProtocol {
		    int              type;
		    void            *priv_data;
		    void           (*setSize) (void *, int, int, int);
		    void           (*numColors) (void *, int);
		    void           (*setMap) (void *, int, const ImageValue
		       [3]);
		    int            (*sendLine) (void *, int, const ImageValue
		       *,
						const ImageValue *);
		    int            (*done) (void *, int);
	    } IndexProtocol;
	    . . .

    2.4.3    Generic Protocol

    The generic protocol is either of these possibilities plus the
    type field for easy type identifcation.

	(8)  Public types
	    . . .
	    typedef union un_ImageProtocol {
		    int              type;
		    ColorProtocol    color;
		    IndexProtocol    index;
	    } ImageProtocol;

	(9)  Public forward definitions
	    . . .
	    typedef union un_ImageProtocol  *ImageProtocolID;

    2.4.4    Error Handling

    There are two specific mechanisms for dealing with errors that
    occur while using image protocols.  The destination can return
    error codes from the `sendLine' and `done' callbacks, and the
    source can pass an error code to the destination's `done'
    callback.

    If an error occurs in the source of a protocol, such as a failure
    partway though reading a file, the source can stop calling
    `sendLine' prematurely.  This will often trigger an error in the
    destination since it will have been keeping track of the amount of
    data sent.  The source should then also pass a non-zero error code
    to the `done' callback which will signal an error to the
    destination.

    If an error occurs in the destination of a protocol, such as a
    failure partway through saving an image, the destination should
    start to return a non-zero error code from `sendLine.' A
    well-written source will stop sending data when this happens, but
    the destination should be prepared to continue to get lines of
    data and to continue to return an error code.  A failed
    destination should also return a non-zero error code from the
    `done' callback.

    2.4.5    Misc Types

    Flags to be passed to `setSize' and `sendData' callbacks.

	(10)  Public declarations
	    . . .
	    #define IMGF_ALPHA               1
	    #define IMGF_REVERSE             2
	    . . .

    There are also some protocol macros defined to get the whole
    calling interface right.

	(11)  Public declarations
	    . . .
	    #define IP_SETSIZE(p,w,h,f)     (*(p)->setSize)
	       ((p)->priv_data,w,h,f)
	    #define IP_NUMCOLORS(p,n)       (*(p)->numColors)
	       ((p)->priv_data,n)
	    #define IP_SETMAP(p,i,val)      (*(p)->setMap)
	       ((p)->priv_data,i,val)
	    #define IP_SENDLINE(p,ln,d,a)   (*(p)->sendLine)
	       ((p)->priv_data,ln,d,a)
	    #define IP_DONE(p,err)          (*(p)->done) ((p)->priv_data,err)


3    Test Server

This is a very simple server designed to test an alternate image
format.  The single plug-in will load and save Targa 32 and 24 bit
formats.


3.1    Targa Reader

The targa loader will recognize a targa file by reading the header
into this data struct.  The `type' gives the compression format and
interpretation of image data, `bits' gives the pixel size and
`reverse' indicates if the lines will come bottom to top.

    (12)  Targa types

	typedef struct st_TargaInfo {
		unsigned char    type, bits;
		short            width, height;
		int              reverse;
	} TargaInfo;

	#define CKPT_TGA_BADFILE        991
	#define CKPT_TGA_NOREC          992
	. . .

The main reader just reads the header, and if this can be matched as a
targa image it reads the body.  Errors will be captured by the
exception context and will set the result code.

    (13)  Targa functions

		int
	TargaLoader (
		long                     version,
		GlobalFunc              *global,
		ImLoaderLocal           *local,
		void                    *servData)
	{
		ReadStrmID               strm;
		TargaInfo                tga;
		int                      fail;

		if (version != 1)
			return AFUNC_BADVERSION;

		if (!CkptCapture (fail)) {
			if (fail == CKPT_ABORT)
				local->result = IPSTAT_ABORT;
			else if (fail == CKPT_TGA_BADFILE)
				local->result = IPSTAT_BADFILE;
			else if (fail == CKPT_TGA_NOREC)
				local->result = IPSTAT_NOREC;
			else
				local->result = IPSTAT_FAILED;

			return AFUNC_OK;
		}

		strm = StrmReadOpen (local->filename, NULL);
		if (!strm)
			CkptRecover (CKPT_TGA_BADFILE);
		ARM1 (StrmReadClose, strm);

		if (!ReadTargaHeader (strm, &tga))
			CkptRecover (CKPT_TGA_NOREC);

		<Read targa data>

		StrmReadClose (strm);
		CkptEnd ();

		local->result = IPSTAT_OK;
		return AFUNC_OK;
	}
	. . .

The reader will check just a very few things in the header before it
decides it can load the file.  This might be a problem since targa
files are much less self-identifying than others.  Any values that are
out of range cause this to return 0, indicating failure to recognize.
If it returns 1, the info has been read.

    (14)  Targa utilities

		static int
	ReadTargaHeader (
		ReadStrmID               strm,
		TargaInfo               *tga)
	{
		unsigned char            byte, idLen;

		(*strm->readBytes) (strm, &idLen, 1);
		(*strm->readBytes) (strm, &byte, 1);
		if (byte)
			return 0;

		(*strm->readBytes) (strm, &tga->type, 1);
		if (tga->type != 2 && tga->type != 10)
			return 0;

		(*strm->skipBytes) (strm, 9);
		(*strm->readIWords) (strm, &tga->width, 1);
		(*strm->readIWords) (strm, &tga->height, 1);

		(*strm->readBytes) (strm, &tga->bits, 1);
		if (tga->bits != 24 && tga->bits != 32)
			return 0;

		(*strm->readBytes) (strm, &byte, 1);
		byte &= 0xF0;
		if (byte == 0)
			tga->reverse = 1;
		else if (byte == 0x20)
			tga->reverse = 0;
		else
			return 0;

		(*strm->skipBytes) (strm, idLen);
		return 1;
	}
	. . .

We will always send the data in RGB24 format, since we currently only
recognize targa 32 and 24 bit formats.  Buffers are allocated to
transfer the rgb and alpha data in the right byte-packing order.  The
protocol is started and recovery actions are armed in case we fail
partway through.

    (15)  Read targa data

	{
		ImageProtocolID          ip;
		ColorProtocol           *cp;
		ImageValue              *buf, *abuf;
		int                      bufSize, i, alpha;

		ip = (*local->begin) (local->priv_data, IMG_RGB24);
		if (!ip)
			CkptRecover (CKPT_IO_ERROR);

		alpha = (tga.bits == 32);

		bufSize = tga.width * 4;
		buf = NEW_Z (bufSize);
		ARM_Z (buf, bufSize);
		abuf = (alpha ? buf + 3 * tga.width : NULL);

		cp = &ip->color;
		IP_SETSIZE (cp, tga.width, tga.height, (alpha ? IMGF_ALPHA :
		   0));

		ARM2 (local->done, local->priv_data, cp);

		MON_INIT (local->monitor, tga.height);
		if (local->monitor)
			ARM1 (local->monitor->done, local->monitor->data);

		if (CkptBegin ()) {
			ARM2 ((void*)cp->done, cp->priv_data, -1);
			<Read targa lines>
			CkptEnd ();
		}
		if (IP_DONE (cp, 0))
			CkptRecover (CKPT_IO_ERROR);

		MON_DONE (local->monitor);
		(*local->done) (local->priv_data, ip);
		FREE_Z (buf, bufSize);
	}

Basically we just read all the lines in forward or reverse order.
They may be compressed or not.

    (16)  Read targa lines

	for (i = 0; i < tga.height; i++) {
		int                      ln, x;
		unsigned char            bgra[4];
		ImageValue              *rgbBuf, *alphaBuf;

		rgbBuf = buf;
		alphaBuf = abuf;
		if (tga.type == 2) {
			<Read uncompressed targa line>
		} else {
			<Read compressed targa line>
		}

		ln = (tga.reverse ? tga.height - i - 1: i);
		if (IP_SENDLINE (cp, ln, buf, abuf))
			break;

		if (MON_STEP (local->monitor))
			CkptRecover (CKPT_ABORT);
	}

Uncompressed lines of data are just `width' pixels which we read
sequentially.

    (17)  Read uncompressed targa line

	for (x = 0; x < tga.width; x++) {
		<Read a targa pixel element into `bgra'>
		<Store `bgra' pixel to line buffers>
	}

A compressed line is enough pixels in literals and runs to fill a
scanline.  If the scanline is not exactly filled, this is an error.

    (18)  Read compressed targa line

	x = 0;
	while (x < tga.width) {
		unsigned char            test;
		int                      count, k;

		(*strm->readBytes) (strm, &test, 1);
		count = (test & 0x7F) + 1;
		if (test & 0x80) {
			<Read a targa pixel element into `bgra'>
			for (k = 0; k < count; k++) {
				<Store `bgra' pixel to line buffers>
			}
		} else {
			for (k = 0; k < count; k++) {
				<Read a targa pixel element into `bgra'>
				<Store `bgra' pixel to line buffers>
			}
		}
		x += count;
	}
	if (x != tga.width)
		CkptRecover (CKPT_IO_ERROR);

24 and 32 bit targa pixels are just 3 or 4 bytes in BGR(A) order.  We
read that into an array that will be unpacked into the format we want.

    (19)  Read a targa pixel element into `bgra'

	(*strm->readBytes) (strm, bgra, (alpha ? 4 : 3));

Once we have read a pixel we can store it to the accumulating output
row by sticking the rgb and optional alpha into their buffers.

    (20)  Store `bgra' pixel to line buffers

	*rgbBuf++ = bgra[2];
	*rgbBuf++ = bgra[1];
	*rgbBuf++ = bgra[0];
	if (alpha)
		*alphaBuf++ = bgra[3];


3.2    Targa Saver

    (21)  Targa types
	. . .
	typedef struct st_TargaSave {
		WriteStrmID      strm;
		Monitor         *mon;
		int              width, height;
		int              alpha, result;
	} TargaSave;

The targa saver sets up a protocol of the RGB24 type and requests a
send from the source.  Since the protocol callbacks have to return
result codes, the ckpt mechanism is more of a hinderance here.

    (22)  Targa functions
	. . .
		int
	TargaSaver (
		long                     version,
		GlobalFunc              *global,
		ImSaverLocal            *local,
		void                    *servData)
	{
		ImageProtocol            prot;
		TargaSave                tga;

		if (version != 1)
			return AFUNC_BADVERSION;

		if (local->type != IMG_RGB24) {
			local->result = IPSTAT_FAILED;
			return AFUNC_OK;
		}

		tga.strm = StrmWriteOpen (local->filename);
		if (!tga.strm) {
			local->result = IPSTAT_BADFILE;
			return AFUNC_OK;
		}

		tga.result = IPSTAT_OK;
		tga.mon = local->monitor;

		prot.type = IMG_RGB24;
		prot.color.priv_data = &tga;
		prot.color.setSize = Targa_SetSize;
		prot.color.sendLine = Targa_SendLine;
		prot.color.done = Targa_Done;

		(*local->sendData) (local->priv_data, &prot, IMGF_ALPHA);

		StrmWriteClose (tga.strm);
		local->result = tga.result;
		return AFUNC_OK;
	}

The set size callback will just record the size and alpha status in
the save info and write the header.  The header is mostly zero expcpt
for a few bytes with special values and the size as reversed byte
order words.

    (23)  Targa utilities
	. . .
		XCALL_(static void)
	Targa_SetSize (
		TargaSave               *tga,
		int                      w,
		int                      h,
		int                      flags)
	{
		unsigned char            hdr[12];
		short                    size[2];
		int                      fail;

		if (!CkptCapture (fail)) {
			tga->result = IPSTAT_FAILED;
			return;
		}

		tga->width = w;
		tga->height = h;
		tga->alpha = ((flags & IMGF_ALPHA) != 0);

		memset (hdr, 0, 12);
		hdr[2] = 2;
		(*tga->strm->writeBytes) (tga->strm, hdr, 12);

		size[0] = w;
		size[1] = h;
		(*tga->strm->writeIWords) (tga->strm, size, 2);

		hdr[0] = (tga->alpha ? 32 : 24);
		hdr[1] = 0x20;
		(*tga->strm->writeBytes) (tga->strm, hdr, 2);

		if (tga->mon)
			MON_INIT (tga->mon, tga->height);

		CkptEnd ();
	}
	. . .

Writing a line is really easy.  The pixel loop just unwraps the rgb
and optional alpha data into targa pixel format and writes it.  Write
errors will return an error code, but nothing else.

    (24)  Targa utilities
	. . .
		static int
	Targa_SendLine (
		TargaSave               *tga,
		int                      line,
		const ImageValue        *data,
		const ImageValue        *adata)
	{
		unsigned char            bgra[4];
		int                      i, plen;
		int                      fail;

		if (tga->result != IPSTAT_OK)
			return -1;

		if (!CkptCapture (fail)) {
			if (fail == CKPT_ABORT)
				tga->result = IPSTAT_ABORT;
			else
				tga->result = IPSTAT_FAILED;

			return -1;
		}

		plen = (tga->alpha ? 4 : 3);

		for (i = 0; i < tga->width; i++) {
			bgra[2] = *data++;
			bgra[1] = *data++;
			bgra[0] = *data++;
			if (tga->alpha)
				bgra[3] = *adata++;

			(*tga->strm->writeBytes) (tga->strm, bgra, plen);
		}

		if (tga->mon && MON_STEP (tga->mon))
			CkptRecover (CKPT_ABORT);

		CkptEnd ();
		return 0;
	}
	. . .

The `done' callback completes the monitor transaction and returns the
aggregate error status.

    (25)  Targa utilities
	. . .
		static int
	Targa_Done (
		TargaSave               *tga,
		int                      error)
	{
		if (error)
			tga->result = IPSTAT_FAILED;

		if (tga->mon)
			MON_DONE (tga->mon);

		return (tga->result != IPSTAT_OK);
	}


3.3    Plug-in Module

    (26)  Targa Image server

	#include <image.h>
	#include <strmu.h>
	#include <splug.h>
	#include <std.h>

	<Targa types>
	<Targa utilities>
	<Targa functions>

	ServerRecord            ServerDesc[] = {
		{ "ImageSaver",   "Targa",      TargaSaver },
		{ "ImageLoader",  "Targa",      TargaLoader },
		{ NULL }
	};
 
====================================

File Requester Plug-ins -- Stuart Ferguson 1/20/95

1      Introduction

2      Server Interface
    2.1    Process
    2.2    Activation Parameters
      (1)    Public types
    2.3    File Type Conversion
      (2)    Public types


1    Introduction

File requesters are in the tools library as part of the system-generic
interface components.  File requesters will work the same way on all
systems, with the default mode being to use the local standard file
requester provided by the host system.  In addition, the file
requester interface here is defined as a plug-in server class, so in
the future more and different types of file requesters may be
provided.


2    Server Interface

The file requester server class is "FileRequester" and the version is
1.


2.1    Process

The activation function for a file requester server performs the
entire operation at once.  The host passes a local structure defining
the request, the server opens a requester and gets a reply from the
user and returns that result back to the calling host.

A file requester should respect the current directory of the caller
when processing the request and should leave it unchanged.  It should
also the user to specify relative path names as well as fully
qualified ones.  (Both of these issues have to be specially coded when
using the Windows common file dialogue.)


2.2    Activation Parameters

The host sets up the local data with the type of request and the
initial filename and path, if any.  The `reqType' request type is one
of the FREQ_* values defined below.  GENERIC might be either a load or
a save.  A possible title for this request is passed in `title'.  The
`fileType' string is set by the host as a hint about the type of file
being requested.  Some possible values might be "Scenes," "Objects,"
"Images," etc.  A null pointer indicates no particular file type.  The
initial path is set in the `path' string and the initial filename is
set in `baseName', either of which may be empty strings.  All three
character pointers must point to buffers at least `bufLen' characters
long, a value the host must also set.

When the activation function returns, the user has made a choice.  If
they canceled the request, `result' will be false.  If not, the full
file name is in `fullName' and path and base names have been updated
to reflect the full name.

    (1)  Public types

	typedef struct {
		int              reqType, result;
		const char      *title;
		const char      *fileType;
		char            *path;
		char            *baseName;
		char            *fullName;
		int              bufLen;
	} FileReq_Local;

	#define FREQ_GENERIC     0
	#define FREQ_LOAD        1
	#define FREQ_SAVE        2
	. . .


2.3    File Type Conversion

The host should provide a global function to get filename patterns
from file type strings, returned by ID "File Type Pattern".  This
function takes a file type string and returns a pattern used to match
files of the given type.  If the type is unknown, or the string is
null, a generic wildcard is returned to match all files on the system
which will varry depending on the host filesystem.

    (2)  Public types
	. . .
	typedef const char      *FileTypeFunc (const char *);
 
====================================

LightWave 3D Animation and Modeling Plug-ins -- Stuart Ferguson
6/28/95

1      Introduction
    1.1    Pre-Release Compatibility
    1.2    Final 4.0 Compatibility

2      Common Server Classes
    2.1    Utility Servers
    2.2    Object Import
      (1)    Common Server Classes
	2.2.1  Sending Mesh Data
	  (2)    Common Server Classes
	2.2.2  Result Codes
	  (3)    Common Server Classes

3      Common Globals
    3.1    Utility Globals
    3.2    File Requester
      (4)    Common Globals
    3.3    User Messages
      (5)    Common Globals

4      Modeling Datatypes
    4.1    Dynamic Types
      (6)    Modeling Base Types
      (7)    Modeling Types
      (8)    Modeling Types
      (9)    Modeling Types
      (10)   Modeling Types
      (11)   Modeling Types
      (12)   Modeling Types
      (13)   Modeling Types
      (14)   Modeling Types
    4.2    Element Operation Filters
	4.2.1  Layer Filters
	  (15)   Modeling Base Types
	4.2.2  Element Filters
	  (16)   Modeling Base Types

5      Modeling Server Classes
    5.1    Mesh Editing
      (17)   Modeling Base Types
	5.1.1  Local Data
	  (18)   Modeling Servers
	5.1.2  Getting Element Information
	  (19)   Modeling Types
	5.1.3  PointInfo
	  (20)   Modeling Base Types
	5.1.4  PolygonInfo
	  (21)   Modeling Base Types
	  (22)   Modeling Types
	5.1.5  Main Data Struct
	  (23)   Modeling Types
	  (24)   Modeling Types
	5.1.6  Error Codes
	  (25)   Modeling Base Types
	5.1.7  Query Functions
	  (26)   Mesh Edit Count functions
	  (27)   Modeling Types
	  (28)   Mesh Edit Query functions
	5.1.8  Element Traversal
	  (29)   Modeling Base Types
	  (30)   Mesh Edit Enumeration functions
	5.1.9  Creating New Elements
	  (31)   Modeling Base Types
	  (32)   Mesh Edit Create functions
	5.1.10 Modifying Existing Elements
	  (33)   Mesh Edit Modify functions
    5.2    Command Sequencing
      (34)   Modeling Types
	5.2.1  Command Activation
	  (35)   Modeling Servers
	5.2.2  Commands
	5.2.3  External Activation on Windows
	  (36)   Trigger code

6      Modeling Globals
    6.1    Dynamic Conversion
      (37)   Modeling Globals
      (38)   Modeling Types
      (39)   Modeling Types
    6.2    Dynamic Requester
      (40)   Modeling Globals
	6.2.1  Requester Usage
	  (41)   Modeling Types
	6.2.2  Control Descriptors
	  (42)   Modeling Types
	  (43)   Modeling Types
	  (44)   Modeling Types
	  (45)   Modeling Types
    6.3    Dynamic Monitor
      (46)   Modeling Globals
    6.4    Custom Commands
      (47)   Modeling Globals
    6.5    Modeler Internal State
      (48)   Modeling Globals
    6.6    Surfaces List
      (49)   Modeling Globals
    6.7    Outline Font List
      (50)   Modeling Globals

7      Animation Datatypes
    7.1    Coordinate and Range Scales
      (51)   Animation Types
    7.2    Items and Properties
      (52)   Animation Types
      (53)   Animation Types
      (54)   Animation Types
    7.3    Time
      (55)   Animation Types
    7.4    Errors
      (56)   Animation Types
    7.5    Instances and Handlers
      (57)   Animation Types
	7.5.1  Instance Persistence
	  (58)   Animation Types
	  (59)   Animation Types
	7.5.2  Handler Functions
	  (60)   Animation Types
	7.5.3  Interface Server

8      Animation Server Classes
    8.1    Utilities
    8.2    Image Post Processing
	8.2.1  Input Buffers
	  (61)   Animation Servers
	8.2.2  Filter Access
	  (62)   Animation Servers
	8.2.3  Handler
	  (63)   Animation Servers
    8.3    Procedural Texture
	8.3.1  Shader Access
	  (64)   Animation Servers
	8.3.2  Geometric Parameters
	  (65)   Read-only shader parameters
	8.3.3  Modifiable Parameters
	  (66)   Modifiable shader parameters
	8.3.4  Shading Functions
	  (67)   Shader functions
	8.3.5  Instance
	  (68)   Animation Servers
	  (69)   Animation Servers
    8.4    Procedural Displacement Map
	8.4.1  Displacement Access
	  (70)   Animation Servers
	8.4.2  Handler
	  (71)   Animation Servers
    8.5    Procedural Item Animation
	8.5.1  Item Motion Access
	  (72)   Animation Servers
	8.5.2  Handler
	  (73)   Animation Servers
    8.6    Procedural Object Replacement
	8.6.1  Object Replacement Access
	  (74)   Animation Servers
	  (75)   Animation Servers
	8.6.2  Handler
	  (76)   Animation Servers
    8.7    Frame Buffers
      (77)   Animation Servers
    8.8    Animation Output
      (78)   Animation Servers
    8.9    Scene Conversion
      (79)   Animation Servers
    8.10   General Function

9      Animation Globals
    9.1    Item Information
      (80)   Animation Types
      (81)   Animation Globals
    9.2    Object Information
      (82)   Animation Types
      (83)   Animation Globals
    9.3    Bone Information
      (84)   Animation Types
      (85)   Animation Globals
    9.4    Light Information
      (86)   Animation Types
      (87)   Animation Types
      (88)   Animation Globals
    9.5    Camera Information
      (89)   Animation Globals
    9.6    Scene Information
      (90)   Animation Types
      (91)   Animation Globals
      (92)   Animation Globals
    9.7    Image List Information
      (93)   Animation Types
      (94)   Animation Globals
    9.8    Compositing Information
      (95)   Animation Globals
    9.9    Global Rendering Memory Pool
      (96)   Animation Types
      (97)   Animation Globals

10     Files
  (98)   Common LightWave Header
  (99)   LightWave Modeler Plug-in Header
  (100)  LightWave Rendering and Animation Plug-in Header


1    Introduction

This document describes the plug-in interfaces defined for the
LightWave 3D animation and modeling programs.  The two programs which
make up the LightWave 3D suite each have different plug-in interfaces
to allow access to their internal state and functions, as well as some
common interfaces which are shared between the two.  These common
interfaces are the subject of the first portion of this document.
After the common interfaces, the plug-in interfaces specific to
modeling and animation are described.

The reader should be familiar with the basic concepts of the LightWave
plug-in design, such as server classes, local data, and global data.
These are described in the document entitled "LightWave Plug-in
Architecture," and should be considered a prerequsite to this
document.  In addition, some of the common server classes are defined
in other documents which will be referenced.

The LightWave animation program will be called 'Layout' and the
modeling program will be called 'Modeler' throughout this document.


1.1    Pre-Release Compatibility

LightWave 4.0 was released commercially in "pre-release" form in April
95.  The pre-release Modeler fully supported the plug-in interface as
it was defined at that time.  The pre-release Layout only supported a
small fraction of the interface defined for it:

             The ImageFilterHandler class was enabled, but with no
	     instance saving or loading and RGBA buffers only.

             The ShaderHandler class was enabled, but with no instance
	     saving or loading and no rayTrace or illuminate
	     functions.

             The SceneInfo global was fully available.

             The ImageList global was available but without load or
	     spot functions.

Since then development has continued both on the programs and on the
plug-in interface.  While most of the changes are backward compatible
with the pre-release, a few are not.  If you are using the
pre-release, you will have to define the LW_PRERELEASE symbol to
remove anything from this header that is incompatible with the
pre-release versions of Layout and Modeler.


1.2    Final 4.0 Compatibility

This SDK goes with the LightWave 4.0 release.  Modeler 4.0 implements
all the features of the interface described in this document.  While
the interface for Layout 4.0 is described by this document, it varies
slightly from the design given in beta versions of the specification.

             The item paramters W_RIGHT, W_UP and W_FORWARD have been
	     removed.  These can be calculated by inverting the matrix
	     given by the values for RIGHT, UP and FORWARD.

             The global Envelope Handler has been removed.

             The ObjReplacementAccess field curType is always set to
	     OBJREP_NONE and the fields curFrame, curTime and
	     curFilename are not set.

             The Item Motion callback 'getParam' only returns values
	     for the directly keyframable values POSITION, ROTATION
	     and SCALING.  Other parameter values may be read using
	     the global item info callbacks.


2    Common Server Classes

These are the common server classes defined for both programs in the
LightWave 3D suite.  There are interfaces for these server classes
present in Layout and Modeler and any plug-in of one of these classes
may be shared by both programs.


2.1    Utility Servers

The "FileRequester" and "ImageLoader" utility server classes are used
by both LightWave and Modeler.  The interfaces for these server
classes are defined in the "File Requester Plug-ins" and "LightWave
Images" documents.


2.2    Object Import

When Layout or Modeler encounters a foreign object file which it
cannot parse, it will call an "ObjectLoader" class server to import
it.  All the loaders defined for the host will be activated in
sequence, and the first one to recognize the file will load it.  The
order in which loaders are called is not defined, although it may be
alphabetical by server name.

At activate, an ObjectImport structure is passed to a plug-in object
loader as its local data, and the loader should attempt to parse the
input file given by the filename field.  If it cannot open or
recognize the file the loader should set the `result' field to the
appropriate code and return.

If it recognizes the file type it should send the mesh and surface
data to the host by calling the callbacks.  The `data' field is an
opaque pointer to some internal state for the host and should be the
first argument to every callback.  The `monitor' field will contain a
pointer to a monitor which can be used to track the progress of
loading.  The monitor should not be used unless the object format is
recognized.

    (1)  Common Server Classes

	typedef struct st_ObjectImport {
		int               result;
		const char       *filename;
		Monitor          *monitor;
		char             *failedBuf;
		int               failedLen;

		void             *data;
		void            (*begin) (void *, void *);
		void            (*done) (void *);
		void            (*numPoints) (void *, int total);
		void            (*points) (void *, int numPts,
					   const float *xyz);
		int             (*surfIndex) (void *, const char *name,
					      int *firstTime);
		void            (*polygon) (void *, int numPts, int surf,
					    int flags,
					    const unsigned short *);
		void            (*surfData) (void *, const char *name,
					     int size, void *data);
	} ObjectImport;
	. . .

    2.2.1    Sending Mesh Data

    Sending mesh data to the host involves calling the functions
    provided in the ObjectImport structure in a semi-sequential order.
    The basics are to start the data transfer, send the points, define
    surface names, send the polygons, assign surface parameters to
    names, and complete the transfer.

     Begin       Callback `begin' is called to mark the start of new
		 mesh data.  The second argument is for special
		 information and should normally be null.  (It might
		 be possible to call this more than once, although
		 `done' would have to be called before calling `begin'
		 a second time.)

     Points      Callback `numPoints' is called with the total number
		 of points.  Then `points' is called with 1 or more
		 point coordinates until the total number of points is
		 reached.  Points are numbered from zero in the order
		 added, and that implicit index is used to create
		 polygons.  All points must be added before any
		 polygons may be created.

     Surfaces    The callback `surfIndex' is called with a surface
		 name to get a surface ID number for that surface.
		 This ID number is used to create polygons.  The
		 function may optionally return a boolean flag to
		 indicate if this is the first time this surface name
		 has been given an ID.

     Polygons    For each polygon, the `polygon' function is called
		 with a list of point indices for the polygon, the
		 number of points, mode flags and a surface index.
		 The mode flags word is a collection of bits.  If the
		 CURVE bit is set, this is a curve rather than a face.
		 If the DETAIL bit is set, then this polygon is a
		 detail of the last top-level polygon.  If the STARTCC
		 or ENDCC bits are set, then this curve has start
		 and/or end points which are continuity control
		 points.

	(2)  Common Server Classes
	    . . .
	    #define OBJPOLF_FACE      0
	    #define OBJPOLF_CURVE    (1<<0)
	    #define OBJPOLF_DETAIL   (1<<1)
	    #define OBJPOLF_STARTCC  (1<<2)
	    #define OBJPOLF_ENDCC    (1<<3)
	    . . .

     Surface Data
		 A block of raw surface parameters may be assigned to
		 a name at any time by calling the `surfData' call
		 with the surface name and byte block.

     Done        Callback `done' is called when data transfer is
		 complete.

    If a failure occurs partway through loading a file, the loader can
    set the result field and return without having to do any other
    cleanup.

    2.2.2    Result Codes

    The loader must set the `result' field to one of these following
    values before it returns.  OK indicates successful parsing of the
    object file.  BADFILE indicates that the loader could not open the
    file.  NOREC indicates that the loader could not recognize the
    format, and ABORTED indicates the that the user manually aborted
    the load.  Any other failure is indicated by the generic FAILED
    value.  In this case, the loader may also place a human-readable
    error message into the buffer pointed to by `failedBuf,' provided
    that `failedLen' is non-zero.

	(3)  Common Server Classes
	    . . .
	    #define OBJSTAT_OK       0
	    #define OBJSTAT_NOREC    1
	    #define OBJSTAT_BADFILE  2
	    #define OBJSTAT_ABORTED  3
	    #define OBJSTAT_FAILED   99


3    Common Globals

This section contains descriptions of the data pointers which can be
accessed by passing specific global ID strings to the global functions
of both Modeler and Layout.  Common servers can access these globals
regardless of which program they are running under.


3.1    Utility Globals

The global ID "Host Display Info" returns a HostDisplayInfo structure
initialized for the host application's main window.  This structure is
described in the "LightWave Plug-in Architecture" document and defined
in the `hdisp.h' header file.

The global ID "File Type Pattern" returns a file type function used to
get filename filters for different file types.  This is used by the
file requester class primarily and is described in the "File Requester
Plug-ins" document.


3.2    File Requester

The global ID "File Request" returns a `FileReqFunc' pointer.  Servers
can use this function to request filenames from users with the same
file requester used by the host.  The `hail' string is the title of
the request and the `name' & `path' buffers should be filled in with
the starting base name and path for the request.  These buffers will
be modified and the `fullName' buffer filled with the final complete
name for the user-selected file.  `bufLen' is the length of all the
passed buffers.  The function returns 0 if the user elected to cancel,
1 if they hit Ok, and negative values for any errors.

    (4)  Common Globals

	typedef int             FileReqFunc (const char *hail, char *name,
					     char *path, char *fullName,
					     int buflen);
	. . .


3.3    User Messages

The global ID "Info Messages" returns a pointer to a MessageFunc
structure which provides simple functions for displaying messages to
the user.  The functions will display different types of messages,
each with one or two lines of text.  The second string argument can be
null for one-line messages.

    (5)  Common Globals
	. . .
	typedef struct st_MessageFuncs {
		void            (*info)    (const char *, const char *);
		void            (*error)   (const char *, const char *);
		void            (*warning) (const char *, const char *);
	} MessageFuncs;


4    Modeling Datatypes

The servers and globals for Modeler share a set of type and value
definitions.  These are basic to an understanding of the Modeler
servers and globals.


4.1    Dynamic Types

Dynamic Values are values of variable type.  Unlike normal C types
which have a fixed interpretation, dynamic values have a type which
can vary according to what is needed.  The possible types for a
dymamic value are given by the following definitions.

    (6)  Modeling Base Types

	typedef int             DynaType;
	#define DY_NULL         0
	#define DY_STRING       1
	#define DY_INTEGER      2
	#define DY_FLOAT        3
	#define DY_DISTANCE     4
	#define DY_VINT         5
	#define DY_VFLOAT       6
	#define DY_VDIST        7
	#define DY_BOOLEAN      8
	#define DY_CHOICE       9
	#define DY_SURFACE      10
	#define DY_FONT         11
	#define DY_TEXT         12
	#define DY_LAYERS       13
	#define DY_CUSTOM       14
	#define DY__LAST        DY_CUSTOM
	. . .

A dynamic value datatype is a structure whose first field is a
DynaType code for the type of the value, followed by varient fields
which hold the value in a form appropriate to the given type.  The
different varient forms of value encoding are listed here.

DY_STRING and DY_SURFACE type values contain a pointer to a string
buffer and a buffer size.  If the buffer size is zero, the buffer is
read-only.

    (7)  Modeling Types

	typedef struct st_DyValString {
		DynaType         type;
		char            *buf;
		int              bufLen;
	} DyValString;
	. . .

Integer values are used for types DY_INTEGER, DY_BOOLEAN (zero or
non-zero), DY_CHOICE (0 - n-1), DY_FONT (font number 0 to n-1) and
DY_LAYERS (bit mask for layer set).  The default value is only used in
requesters as the reset value.

    (8)  Modeling Types
	. . .
	typedef struct st_DyValInt {
		DynaType         type;
		int              value;
		int              defVal;
	} DyValInt;
	. . .

Floating point values are used for types DY_FLOAT and DY_DISTANCE
(distance measure in meters).  The default value is again used when
resetting a requester.

    (9)  Modeling Types
	. . .
	typedef struct st_DyValFloat {
		DynaType         type;
		double           value;
		double           defVal;
	} DyValFloat;
	. . .

The DY_VINT type is an integer vector with three components.  The
single default value resets all three components of the vector when
used in a requester.

    (10)  Modeling Types
	. . .
	typedef struct st_DyValIVector {
		DynaType         type;
		int              val[3];
		int              defVal;
	} DyValIVector;
	. . .

Floating point three-component vectors are used for the types
DY_VFLOAT and DY_VDIST, with the latter being distances encoded in
meters.

    (11)  Modeling Types
	. . .
	typedef struct st_DyValFVector {
		DynaType         type;
		double           val[3];
		double           defVal;
	} DyValFVector;
	. . .

The custom dynamic type, DY_CUSTOM, is used to encode values which do
not fit one of the standard types.  The meaning of the fields
following the type for a custom value are defined by agreement between
the sender and receiver and are usually a set of 4-byte numbers and
pointers, although they can be anything.  Usually anywhere a custom
value is required, an alternate string form can also be accepted.

    (12)  Modeling Types
	. . .
	typedef struct st_DyValCustom {
		DynaType         type;
		int              val[4];
	} DyValCustom;
	. . .

A DynaValue type is the union of all possible value type varients plus
the type code itself which is the only field set for DY_NONE and
DY_TEXT types.

    (13)  Modeling Types
	. . .
	typedef union un_DynaValue {
		DynaType         type;
		DyValString      str;
		DyValInt         intv;
		DyValFloat       flt;
		DyValIVector     ivec;
		DyValFVector     fvec;
		DyValCustom      cust;
	} DynaValue;
	. . .

Error codes returned from the dynamic data type functions.

    (14)  Modeling Types
	. . .
	#define DYERR_NONE                0
	#define DYERR_MEMORY            (-1)
	#define DYERR_BADTYPE           (-2)
	#define DYERR_BADSEQ            (-3)
	#define DYERR_BADCTRLID         (-4)
	#define DYERR_TOOMANYCTRL       (-5)
	#define DYERR_INTERNAL          (-6)
	. . .


4.2    Element Operation Filters

At any given moment Modeler holds some set of layers, each containing
a potentially large collection of point and polygon elements.  The
user selects which subset of elements are to be affected by an
operation by picking layers as active and inactive, and selecting
elements in those layers with the element selection tools.  Plug-in
operations can select what elements to operate on as a function of the
user's selections.

    4.2.1    Layer Filters

    EltOpLayer codes are used to select which layers will be affected
    by an operation.

     PRIMARY     The primary layer is the single active layer that is
		 affected by mesh edits.

     FG          The foreground layers are those which are active and
		 displayed.

     BG          The background layers are those which are inactive
		 but still displayed.

     SELECT      Select layers are all displayed layers, foreground
		 and background.

     ALL         All layers are all layers in the modeler system
		 whether they contain data or not.

     EMPTY       Empty layers are those with no data elements in them.

     NONEMPTY    Non-empty layers are any layers which contain some
		 data.

     Individual Layers
		 In addition to the defined values, codes from 101 to
		 110 can be used to select the individual layers 1
		 through 10.

	(15)  Modeling Base Types
	    . . .
	    typedef int              EltOpLayer;
	    #define OPLYR_PRIMARY    0
	    #define OPLYR_FG         1
	    #define OPLYR_BG         2
	    #define OPLYR_SELECT     3
	    #define OPLYR_ALL        4
	    #define OPLYR_EMPTY      5
	    #define OPLYR_NONEMPTY   6
	    . . .

    4.2.2    Element Filters

    EltOpSelect is a selection mode to pick elements from the selected
    layers for operations.

     GLOBAL      All elements, whether selected or unselected, will be
		 affected by the operation.

     USER        Only those elements selected by the user will be
		 affected.  This includes the implicit selection of
		 all elements when nothing is explicitly selected, and
		 selections by volume.

     DIRECT      Elements selected directly with the point or polygon
		 selection tools will be affected.  This is the case
		 for both points and polygons regardless of the
		 current select mode.

	(16)  Modeling Base Types
	    . . .
	    typedef int              EltOpSelect;
	    #define OPSEL_GLOBAL     0
	    #define OPSEL_USER       1
	    #define OPSEL_DIRECT     2
	    . . .


5    Modeling Server Classes

There are two types of servers defined for Modeler which can perform
modeling operations.  Mesh Edit servers can perform a single mesh data
editing operation by affecting the data elements at a fairly low
level.  Command Sequence servers can execute a sequence of editing
operations, including most of those accessable to the user as well as
low-level mesh edits.


5.1    Mesh Editing

The "MeshDataEdit" class provides the capability of editing existing
layer data though low-level point and polygon operations.  The
available MeshDataEdit servers in a Modeler session are presented to
the user in the "Custom" popup in the "Tools" menu.  Editing is done
through functions which operate on elements represented by opaque
pointers.  The editing state itself is also maintained as an opaque
pointer and is the first argument to most of the calls.

    (17)  Modeling Base Types
	. . .
	typedef struct st_Vertex        *PntID;
	typedef struct st_Polygon       *PolID;
	typedef struct st_EditState     *EditStateRef;
	. . .

A mesh edit operation is a single undoable modification to layer data.
The server starts the operation and is given an EditStateRef pointer
to refer to the ongoing state of the edit operation.  The server may
then add new elements and modify or delete existing elements.  As the
server requests changes, those are logged by the host but will not be
applied until the operation is complete.  At any time the server may
abort the operation and the pending changes will be discarded, or it
can accept the changes and they will be applied as the last step
before the server exits.

    5.1.1    Local Data

    Upon activation, a mesh edit server gets a `MeshEditBegin'
    function pointer as its local data.  To initiate the mesh editing
    operation, the server calls this function and gets back a
    `MeshEditOp' which contains the data for the edit as well as
    pointers to all the editing functions.  This can be called only
    once for each activation.

	(18)  Modeling Servers

	    typedef MeshEditOp *    MeshEditBegin (int pntBuf, int polBuf,
						    EltOpSelect);
	    . . .

    The first two arguments to the function are the client data sizes
    (in bytes) for points and polygons, respectively.  If non-zero,
    the host will allocate a block of memory for each and every point
    and polygon for the exclusive use of this edit operation.  These
    client data buffers can be used to associate any information with
    specific points and polygons for the course of the edit operation,
    and will be freed when the operation completes.  The third
    argument is the selection option and determines what elements are
    initially selected.

    5.1.2    Getting Element Information

    Servers can get information about existing elements by reading
    them out into special information structures.  The PointInfo and
    PolygonInfo structures are used to hold information about points
    and polygons, respectively.  Every element has an ID, a userData
    pointer, a layer number and flags.

     PntID or PolID
		 This uniquely identifies each element and is the
		 reference used for manipulating them.

     userData    This is a pointer to a memory block which has been
		 allocated for the client specifically for this
		 element according to the requested size in the call
		 to MeshEditBegin.  This is an area where the client
		 can store computed values for points and polygon
		 while it operates on them.

     layer       This is just the number of the layer where the
		 element is located (0-9 currently).

     flags       All elements have flags bits for selection and
		 deletion.  The PPDF_SELECT bit is set if the element
		 matched the selection criterion from the start of the
		 edit, and the PPDF_DELETE bit is set if the element
		 has been deleted in this session.

	(19)  Modeling Types
	    . . .
	    #define PPDF_SELECT     (1<<0)
	    #define PPDF_DELETE     (1<<1)
	    . . .

    Except for the memory pointed to by the userData pointer, the
    contents of info structures or the data they reference are
    read-only and cannot be modified.  Any attempts to do so will
    either be futile or catastrophic.

    5.1.3    PointInfo

    In addition to the common parts, a PointInfo struct also includes
    the point position as a triple of floating point numbers for the
    X, Y and Z coordinates.

	(20)  Modeling Base Types
	    . . .
	    typedef struct st_PointInfo {
		    PntID            pnt;
		    void            *userData;
		    int              layer;
		    int              flags;
		    double           position[3];
	    } PointInfo;
	    . . .

    5.1.4    PolygonInfo

    In addition to the common parts of the info structure, a
    PolygonInfo struct encodes the polygon shape as the number of
    points and an array of their IDs.  The surface assigned to the
    polygon is given by a name string.

	(21)  Modeling Base Types
	    . . .
	    typedef struct st_PolygonInfo {
		    PolID            pol;
		    void            *userData;
		    int              layer;
		    int              flags;
		    int              numPnts;
		    const PntID     *points;
		    const char      *surface;
	    } PolygonInfo;
	    . . .

    Polygons also have some additional flag bits.  CCEND and CCSTART
    are set if the polygon has continuity points at either end.  CURVE
    is set if this is a curve (it is a face if this is clear).  DETAIL
    is set if the polygon is a detail.

	(22)  Modeling Types
	    . . .
	    #define PPDF_CCEND      (1<<2)
	    #define PPDF_CCSTART    (1<<3)
	    #define PPDF_CURVE      (1<<4)
	    #define PPDF_DETAIL     (1<<5)
	    . . .

    5.1.5    Main Data Struct

    When the `MeshEditBegin' function starts an edit operation, it
    returns a MeshEditOp structure which the client uses to execute
    the edit.  This structure contains a few data fields and a large
    set of function fields.

	(23)  Modeling Types
	    . . .
	    typedef struct st_MeshEditOp {
		    EditStateRef      state;
		    int               layerNum;
		    void            (*done) (EditStateRef, EDError, int selm);

		    <Mesh Edit Count functions>
		    <Mesh Edit Enumeration functions>
		    <Mesh Edit Query functions>
		    <Mesh Edit Create functions>
		    <Mesh Edit Modify functions>
	    } MeshEditOp;
	    . . .

     state       The internal state of the edit is maintained in the
		 private `state' field which is the first argument to
		 every function.

     layerNum    Points and polygons may only be modified if they
		 belong to the primary active layer which is given by
		 this layer number.  The primary layer is the lowest
		 numbered foreground layer.  All new data will be
		 added to this layer and changes attempted on data in
		 other layers will fail.

     done        The `done' function completes the edit.  If the error
		 code is EDERR_NONE, the edit operation will complete
		 and the cumulative edits will be applied to the data.
		 If an actual error code is passed, the edit will
		 abort and any changes made will be discarded.  The
		 `selm' argument is bit flags which provide info on
		 how to alter the selection based on editing changes.
		 A value of zero leaves all directly selected elements
		 selected after the edit.  The CLEARCURRENT hint bit
		 set will clear the current selected elements, and the
		 SELECTNEW hint bit set will cause any newly created
		 elements to become selected.  Hints will not override
		 selection settings made by the user, and only when
		 elements are explicitly selected will new selections
		 be made.  The force bits will always force direct
		 selection of the points and/or polygons created by
		 this operation regardless of current user selections.

	(24)  Modeling Types
	    . . .
	    #define EDSELM_CLEARCURRENT     (1<<0)
	    #define EDSELM_SELECTNEW        (1<<1)
	    #ifndef LW_PRERELEASE
	     #define EDSELM_FORCEVRTS       (1<<2)
	     #define EDSELM_FORCEPOLS       (1<<3)
	    #endif
	    . . .

     Other functions
		 The remaining functions allow for examining the state
		 of the mesh data and modifying it.  All changes for a
		 given edit operation must be made through these
		 functions.  No data structures may be modified
		 directly.

    As changes are made they are buffered through the undo mechanism,
    so they are not reflected in the data until the operation is
    complete.  For example, if a MeshDataEdit client reads the
    coordinates of a point and changes them (correctly using the
    `pntMove' function) and reads the coordinates again, they will be
    the same as the first time.  The coordinates will not change until
    the edits are sucessfully applied using the `done' function.

    5.1.6    Error Codes

    Errors are integer codes returned from functions and passed to the
    `done' function.  The exceptions are functions which create new
    elements in which case an error is signaled by a null return
    value.  The BADLAYER error will be returned for an attempt to
    operate on data not in the primary edit layer.  BADSURF will be
    returned for an illegal surface name.  BADARGS is the catch-all
    for other invalid arguments.

	(25)  Modeling Base Types
	    . . .
	    typedef int             EDError;
	    #define EDERR_NONE      0
	    #define EDERR_NOMEMORY  1
	    #define EDERR_BADLAYER  2
	    #define EDERR_BADSURF   3
	    #define EDERR_USERABORT 4
	    #define EDERR_BADARGS   5
	    . . .

    5.1.7    Query Functions

    Clients can get a count of the number of points or polygons in
    specific layers.  The `mode' argument to the count functions
    specify all the elements, only the selected elements or only the
    elements deleted in this edit session.

	(26)  Mesh Edit Count functions

	    int             (*pointCount) (EditStateRef, EltOpLayer, int
	       mode);
	    int             (*polyCount)  (EditStateRef, EltOpLayer, int
	       mode);

	(27)  Modeling Types
	    . . .
	    #define EDCOUNT_ALL              0
	    #define EDCOUNT_SELECT           1
	    #define EDCOUNT_DELETE           2
	    . . .

    Given a point or polygon ID, the client can get info for that
    element.  The returned info pointer is only valid until the next
    call to an info function (including enumeration).  The normal
    vector for a polygon may also be found given its ID.  The
    `polyNormal' function returns zero if the polygon has fewer than 3
    vertices, or the normal is degenerate for some reason.  If it
    returns 1, then the normal has been written to the caller's
    vector.

	(28)  Mesh Edit Query functions

	    PointInfo *     (*pointInfo)  (EditStateRef, PntID);
	    PolygonInfo *   (*polyInfo)   (EditStateRef, PolID);
	    int             (*polyNormal) (EditStateRef, PolID, double[3]);

    There is only one of each of the PointInfo and PolygonInfo structs
    for every usage.  The same pointer is returned from each query
    call and passed to the enumeration functions, so the client must
    copy any information needed before calling the query function
    again.

    5.1.8    Element Traversal

    The client can traverse all the elements in a layer or combination
    of layers by passing a callback to be called for each element.
    These enumeration functions (given by the prototypes below) take
    as arguments a client data pointer which can be arbitrary, and the
    info structure for the current element.  If the client returns an
    error code (or any non-zero value for that matter) from this
    function, the scan will be aborted and that code will be returned.

	(29)  Modeling Base Types
	    . . .
	    typedef EDError         PointScanFunc (void *, const PointInfo *);
	    typedef EDError         PolyScanFunc (void *, const PolygonInfo
	       *);
	    . . .

    The following functions initiate a scan of points or polygons in
    layer data.  The client provides an enumeration callback and
    client data pointer as well as specifying which layers to include
    in the scan.  The function will be called for each point and
    polygon in order.  If the selection mode used to begin this edit
    was DIRECT, the order of the selected elements is the same as the
    order that the user selected them.  In other select modes, the
    order is the creation order for points and undefined for polygons.
    The return value is EDERR_NONE (0) if the scan completed, and the
    non-zero error code returned by the enumeration callback if the
    scan was aborted.

	(30)  Mesh Edit Enumeration functions

	    EDError         (*pointScan) (EditStateRef, PointScanFunc *,
					  void *, EltOpLayer);
	    EDError         (*polyScan)  (EditStateRef, PolyScanFunc *,
					  void *, EltOpLayer);

    5.1.9    Creating New Elements

    A new data element is added by calling the appropriate function,
    which creates the new element but does not add it to the layer
    until the edit is completed.  Polygons are created from lists of
    PntIDs which can be the IDs of pre-existing points or of points
    created in this session, as long as the existing ones are in the
    primary layer.

     addPoint    New points are created by passing a vector of X, Y
		 and Z coordinates to this function.

     addPoly     Polygons are created from a surface name (or null for
		 default), number of points and point list.  The
		 first, second and last points are used to compute the
		 polygon normal.

     addCurve    Curves are created the same way as polygons except
		 that they have an additional flag value which may
		 have PPDF_CCSTART and/or END set.  Closed curves must
		 have both of these bits set and have the first and
		 last two points overlapping.

     addQuad and addTri
		 These two functions create quadrangles and triangles
		 using the default surface and obeying the user's new
		 data options with respect to two-sided and triangles
		 only.  These are used by operations which create new
		 objects from scratch, like the sphere or box tools in
		 Modeler.

     addPatch    This will add a set of polygons to create a polygonal
		 patch from bounding curves obeying the user's new
		 data options.  It takes the number of divisions in
		 the C and R directions, the length/knot flags in the
		 C and R directions, and three or four boundary curve
		 descriptions.  Each boundary curve is a curve-type
		 polygon and the indices of the start and end knots of
		 the curve to be used for patching.

	(31)  Modeling Base Types
	    . . .
	    typedef struct st_PBoundCv {
		    PolID            curve;
		    int              start, end;
	    } PBoundCv;

	(32)  Mesh Edit Create functions

	    PntID           (*addPoint) (EditStateRef, double *xyz);
	    PolID           (*addPoly)  (EditStateRef, const char *surf,
					 int numPnt, const PntID *);
	    PolID           (*addCurve) (EditStateRef, const char *surf,
					 int numPnt, const PntID *, int
					    flags);
	    EDError         (*addQuad)  (EditStateRef, PntID, PntID,
					 PntID, PntID);
	    EDError         (*addTri)   (EditStateRef, PntID, PntID, PntID);
	    EDError         (*addPatch) (EditStateRef, int nr, int nc, int lr,
					 int lc, PBoundCv *r0, PBoundCv *r1,
					 PBoundCv *c0, PBoundCv *c1);

    5.1.10    Modifying Existing Elements

    These functions are used to alter existing data.  If called with
    elements created in this edit session they will return BADLAYER.

     remPoint, remPoly
		 Remove existing data elements.  These will remove
		 points and polygons from the current data set.  The
		 PPDF_DELETE flag bit will be set for these elements
		 after this function is called.

     pntMove     Move a point.  The point will be moved to the new
		 coordinates.

     polSurf     Change polygon surface.  The polygon will be altered
		 to use the new named surface.

     polPnts     Change point list.  The polygon will be changed to
		 have a new set of points given by the list of IDs.
		 The PntIDs may be for existing points or points
		 created this session, but should not refer to points
		 that will be deleted.

     polFlags    Change polygon attributes.  The first mask is the set
		 of attributes to change and the second is their new
		 values.  Only PPDF_CCEND and PPDF_CCSTART may
		 currently be modified.

	(33)  Mesh Edit Modify functions

	    EDError         (*remPoint) (EditStateRef, PntID);
	    EDError         (*remPoly)  (EditStateRef, PolID);
	    EDError         (*pntMove) (EditStateRef, PntID, const double *);
	    EDError         (*polSurf) (EditStateRef, PolID, const char *);
	    EDError         (*polPnts) (EditStateRef, PolID, int, const PntID
	       *);
	    EDError         (*polFlag) (EditStateRef, PolID, int mask, int
	       value);


5.2    Command Sequencing

The "CommandSequence" class servers can execute a sequence of Modeler
commands and/or mesh edits.  CommandSequence servers are presented to
the user in the "Custom" popup in the "Objects" menu, and the user has
the ability to configure the server to take different string
arguments.  The argument string selected by the user is pass to the
server at activation.

Modeling commands are identified by unique case-insensitive names and
by unique integer codes.  Codes may be looked up given the command
string.

    (34)  Modeling Types
	. . .
	typedef int             CommandCode;
	. . .

Commands are executed by passing the command code and a list of
arguments in the form of DynaValues.  The values can have any type
which is can be converted to the required type of each positional
argument.  A command sequence server can execute any sequence of
commands and may combine them with mesh edit operations as well.

    5.2.1    Command Activation

    A CommandSequence server gets a ModCommand structure passed to its
    activation function.  The activation function performs the
    sequence of commands and mesh edits and returns when complete.

     data        Internal host data passed as the first argument to
		 the `lookup' and `execute' functions.

     argument    String argument to this command as set in the custom
		 command list.

     lookup      Function which converts a command name to a command
		 code for use with the `execute' function.  This is a
		 separate step so that the string lookup does not have
		 to be done on every command invocation.  Case is not
		 significant.  Since the codes are fixed for a
		 session, they can be looked up the first time the
		 server is used and cached after that.

     execute     Function which performs the modeling function.  Takes
		 a command code as found by `lookup' and an array of
		 DynaValue arguments.  Which elements to be affected
		 by the command can be selected using the EltOpSelect
		 mode.  If non-null, the result pointer will be
		 written with the return value of the command.
		 Commands with no result will write DY_NULL on this
		 value.  The return value is zero for success and an
		 error code for failure.  Some possible codes are: 1 =
		 out of memory, 2 = I/O error, 4 = user abort, 2901 =
		 wrong number of arguments, 2902 = wrong argument
		 type, 2903 = bad argument value.

     editBegin   This function can be used as described in the secion
		 on mesh editing to start a mesh edit operation from a
		 command sequence server.  Any edit operation must be
		 complete before more commands are executed.

	(35)  Modeling Servers
	    . . .
	    typedef struct st_ModCommand {
		    void             *data;
		    const char       *argument;
		    CommandCode     (*lookup)  (void *, const char *cmdName);
		    int             (*execute) (void *, CommandCode cmd,
						int argc, const DynaValue
						   *argv,
						EltOpSelect, DynaValue
						   *result);
		    MeshEditBegin    *editBegin;
	    } ModCommand;

    5.2.2    Commands

    Here follows a complete list of the commands supported by the
    command mode interface and their arguments.  Optional arguments
    are listed in square brackets.  A more complete description of
    each command may be found in the Modeler ARexx documentation.

     NEW, UNDO   

     DELETE, CUT, COPY, PASTE
		 

     LOAD, SAVE  filename<string>

     SETLAYER, SETBLAYER
		 mask<layers>

     SURFACE     name<string>

     FIXEDFLEX   axis<X|Y|Z>, start<dist>, end<dist>, [ease<i;o>]

     AUTOFLEX    axis<X|Y|Z>, direction<+|->, [ease<i;o>]

     DEFORMREGION
		 radius<vector>, [center<vector>, axis<X|Y|Z>]

     MOVE, SHEAR, MAGNET
		 offset<vector>

     ROTATE, TWIST, VORTEX
		 angle<float>, axis<X|Y|Z>, [center<vector>]

     SCALE, TAPER, POLE
		 factor<vector>, [center<vector>]

     BEND        angle<float>, direction<float>, [center<vector>]

     JITTER      radius<vector>,
		 [type<GAUSSIAN|UNIFORM|NORMAL|RADIAL>,
		 center<vector>]

     SMOOTH      [iterations<int>, strength<float>]

     QUANTIZE    size<vector>

     MERGEPOINTS [mindist<dist>]

     MAKEBOX     lowcorner<vector>, highcorner<vector>,
		 [nsegments<vector>]

     MAKEBALL    radius<vector>, nsides<int>, nsegments<int>,
		 [center<vector>]

     MAKETESBALL radius<vector>, level<int>, [center<vector>]

     MAKEDISC, MAKECONE
		 radius<vector>, top<dist>, bottom<dist>, axis<X|Y|Z>,
		 nsides<int>, [nsegments<int>, center<vector>]

     MAKETEXT    text<string>, index<number>,
		 [cornertype<SHARP|BUFFERED>, spacing<number>,
		 scale<number>, axis<X|Y|Z>, pos<vector>]

     LATHE       axis<X|Y|Z>, nsides<int>, [center<vector>,
		 endangle<float>, startangle<float>, offset<dist>]

     EXTRUDE     axis<X|Y|Z>, extent<dist>, [nsegments<int>]

     MIRROR      axis<X|Y|Z>, plane<dist>

     PATHCLONE, PATHEXTRUDE
		 filename<string>, [step<float>, start<float>,
		 end<float>]

     RAILCLONE, RAILEXTRUDE
		 segments<int>, [divs<KNOTS|LENGTHS>, flags<o;s>,
		 strength<float>]

     AXISDRILL   operation<CORE|TUNNEL|SLICE|STENCIL>, axis<X|Y|Z>,
		 [surface<string>]

     SOLIDDRILL  operation<CORE|TUNNEL|SLICE|STENCIL>,
		 [surface<string>]

     BOOLEAN     operation<UNION|SUBTRACT|INTERSECT|ADD>

     BEVEL       inset<dist>, shift<dist>

     SHAPEBEVEL  pattern<custom>

                 The patten for a shapebevel is either a string
		 containing pairs of inset / shift values, or a custom
		 dynavalue with the val[0] field set to the number of
		 pairs, and the val[1] field cast to a pointer to an
		 array of doubles holding the pairs.

     SMOOTHSHIFT offset<dist>, [maxangle<float>]

     FLIP, TRIPLE, FREEZECURVES
		 

     ALIGNPOLS, REMOVEPOLS, UNIFYPOLS
		 

     CHANGESURFACE
		 surface<string>

     SUBDIVIDE   mode<FLAT|SMOOTH|METAFORM>, [maxangle<float>]

     FRACSUBDIVIDE
		 mode<FLAT|SMOOTH|METAFORM>, fractal<float>,
		 [maxangle<float>])

     SEL_POINT   action<SET|CLEAR>

                 action, VOLUME, lo<vector>, hi<vector>

                 action, CONNECT

                 action, NPEQ, npol<int>

                 action, NPLT, npol<int>

                 action, NPGT, npol<int>

     SEL_POLYGON action<SET|CLEAR>

                 action, VOLEXCL, lo<vector>, hi<vector>

                 action, VOLINCL, lo<vector>, hi<vector>

                 action, CONNECT

                 action, NVEQ, nvert<int>

                 action, NVLT, nvert<int>

                 action, NVGT, nvert<int>

                 action, SURFACE, surface<string>

                 action, FACE

                 action, CURVE

                 action, NONPLANAR, [limit<float>]

     SEL_INVERT  

     SEL_HIDE    state<SELECTED|UNSELECTED>

     SEL_UNHIDE  

     CMDSEQ      name<string>, [arg<string>]

     PLUGIN      module<string>, [class<string>, name<string>,
		 username<string>]

    5.2.3    External Activation on Windows

    When Modeler is running under Windows, CommandSequence class
    servers in the program can be triggered by other Windows programs.
    The Modeler main window looks for messages with a code created by
    the function RegisterWindowMessage() with the string "LWM CmdSeq
    Trigger".  This message code is unique throughout the Windows
    session and the arguments of this message describe the server to
    activate.  The first argument (wp) should be null, and the second
    argument (lp) should be two global atoms containing the
    CommandSequence server name and argument string, combined with the
    MAKELONG() macro.

    The following Windows function triggers a server in Modeler given
    the handle to Modeler's main window.  Atoms are created to pass
    the server name and argument (if any) and the message is posted to
    Modeler's window.  If the PostMessage fails, this function frees
    the atoms, otherwise Modeler will free them when it processes the
    message.  The message code could be looked up only one time if
    multiple messages are to be sent, and SendMessage could be used
    for synchronous triggering.

	(36)  Trigger code

		    static void
	    TriggerModeler (
		    HWND                     wnd,
		    const char              *server,
		    const char              *argument)
	    {
		    UINT                     msg;
		    ATOM                     name, arg;

		    msg = RegisterWindowMessage ("LWM CmdSeq Trigger");

		    name = GlobalAddAtom (server);
		    if (argument && argument[0])
			    arg = GlobalAddAtom (argument);
		    else
			    arg = 0;

		    if (!PostMessage (wnd, msg, NULL, MAKELONG (name, arg))) {
			    GlobalDeleteAtom (name);
			    if (arg)
				    GlobalDeleteAtom (arg);
		    }
	    }


6    Modeling Globals

This section contains descriptions of the global data pointers which
can be accessed from Modeler's global function.


6.1    Dynamic Conversion

The global ID "LWM: Dynamic Conversion" returns a DynaConvertFunc
which can be used to translate a dynamic type element to another type.
An error may be returned if the conversion cannot be performed, and
hints may be provided when converting strings to integer bitfield or
choice values.

    (37)  Modeling Globals

	typedef int             DynaConvertFunc (const DynaValue *,
						 DynaValue *,
						 const DynaStringHint *);
	. . .

String hints are choice hints and/or bitfield hints.  The choice hint
is list of strings and values used when converting between DY_STRING
and DY_CHOICE types.  The pairs indicate a mapping between choice
values and strings.  The list is terminated with a null item string.
The bitfield hint is a list of character codes and bit values used
when converting between DY_STRING and DY_INTEGER types.  If the
character (upper or lower case) is present in the string, the bit
value will be ORed into the result, and visa-versa.  The list is
terminated with a zero bitval.

    (38)  Modeling Types
	. . .
	typedef struct st_DyChoiceHint {
		const char      *item;
		int              value;
	} DyChoiceHint;

	typedef struct st_DyBitfieldHint {
		char             code;
		int              bitval;
	} DyBitfieldHint;
	. . .

Either field in the string hint structure may be null.

    (39)  Modeling Types
	. . .
	typedef struct st_DynaStringHint {
		DyChoiceHint    *chc;
		DyBitfieldHint  *bits;
	} DynaStringHint;
	. . .


6.2    Dynamic Requester

The global ID "LWM: Dynamic Request" returns a set of functions for
creating and displaying a simple requester.  The requesters that can
be created with this interface are like simple forms.  There is a
title and a series of lines each with a label and a control for a
single value.  The controls are described by DynaValues, with the
DynaType determining the type of control and the value determining its
setting.  The user can change the value of the controls while the
requester is displayed.

    (40)  Modeling Globals
	. . .
	typedef struct st_DynaReqFuncs {
		DynaRequestID   (*create)   (const char *);
		int             (*addCtrl)  (DynaRequestID, const char *,
					     DyReqControlDesc *);
		DynaType        (*ctrlType) (DynaRequestID, int);
		int             (*valueSet) (DynaRequestID, int, DynaValue *);
		int             (*valueGet) (DynaRequestID, int, DynaValue *);
		int             (*post)     (DynaRequestID);
		void            (*destroy)  (DynaRequestID);
	} DynaReqFuncs;
	. . .

    6.2.1    Requester Usage

    The basic idea is to create a requester, set up its controls, set
    their values, post the requester, read out the modified values and
    destroy the requester.  The set/post/get cycle may be done any
    number of times once the requester is created.

     create      Create is used to allocate an instance of a dynamic
		 requester with a given title string.  Multiple
		 requesters can be allocated at the same time,
		 although only one may be displayed at once.  The
		 create function returns an ID which is used
		 throughout the rest of the interface.

	(41)  Modeling Types
	    . . .
	    typedef struct st_DynaRequest   *DynaRequestID;
	    . . .

     addCtrl     Controls are added to the requester starting from the
		 top.  The function takes a label and a description
		 (below) and returns an index number for the new
		 control which is used to set and get its value.  The
		 description contains the control type and other
		 information necessary for its display.

     ctrlType    This function just returns the type of a control
		 given its index.

     valueSet    Calling this function with a control index and a
		 DynaValue sets the given control to that value.  The
		 type of the value does not have to be the same as the
		 control as long as the one can be converted to the
		 other.  Note that any "default" fields in the
		 DynaValue will be used to reset the control if the
		 user selects "Reset."

     valueGet    This function is the opposite of the above, reading
		 out the value of the control into the provided
		 DynaValue.

     post        Once the requester is created and the proper values
		 are set, this function displays the requester and
		 allows the user to change the values.  It returns
		 zero if the user presses "Cancel" to dismiss the
		 requester and one if the user presses "Ok."

     destroy     When all interaction is done, a call to destroy frees
		 all resources and completes the process.

    6.2.2    Control Descriptors

    Controls in a dynamic requester are determined primarily by a
    DynaType for the type of data being edited, however for some types
    additional settings may be required for correct display of the
    value.

    Controls of type DY_STRING have a width, in characters, of the
    input field.  This is an average width on systems with variable
    pitch fonts.

	(42)  Modeling Types
	    . . .
	    typedef struct st_DyReqStringDesc {
		    DynaType         type;
		    int              width;
	    } DyReqStringDesc;
	    . . .

    Controls of type DY_CHOICE present a set of labeled buttons for
    the user to select between.  The descriptor contains a pointer to
    an array of strings (terminated with a null pointer) for the
    labels of the choice items.  If the vertical flag is true, the
    choices will be set in a vertical layout, otherwise they will be
    horizontal.

	(43)  Modeling Types
	    . . .
	    typedef struct st_DyReqChoiceDesc {
		    DynaType         type;
		    const char     **items;
		    int              vertical;
	    } DyReqChoiceDesc;
	    . . .

    The DY_TEXT control type is a constant control for displaying
    lines of text.  The text lines are contained in an array of
    strings (terminated with a null pointer).

	(44)  Modeling Types
	    . . .
	    typedef struct st_DyReqTextDesc {
		    DynaType         type;
		    const char     **text;
	    } DyReqTextDesc;
	    . . .

    The control descriptor is the union of all these varient records
    plus the DynaType alone.  If there is no special descriptive data
    for a type, then only the type code is needed to create a control
    of that type.

	(45)  Modeling Types
	    . . .
	    typedef union un_DyReqControlDesc {
		    DynaType         type;
		    DyReqStringDesc  string;
		    DyReqChoiceDesc  choice;
		    DyReqTextDesc    text;
	    } DyReqControlDesc;


6.3    Dynamic Monitor

The global ID "LWM: Dynamic Monitor" returns a structure holding
functions which can be used to create a monitor for providing feedback
on the progress of an operation and allow user to abort it.  Monitors
are described in the "LightWave Plug-in Architecture" document and are
declared in the `moni.h' header file.

 create      Clients create a monitor instance with header and
	     optional footer text.  Once created, the monitor object
	     can be used as described in the above referenced
	     document.  The create func may return null if the Modeler
	     bar graph is already in use, since there can be only one.

 destroy     When done, the monitor must be destroyed by calling this
	     function.  This must be called whether the operation was
	     completed or not.

    (46)  Modeling Globals
	. . .
	typedef struct st_DynaMonitorFuncs {
		Monitor *       (*create) (const char *, const char *);
		void            (*destroy) (Monitor *);
	} DynaMonitorFuncs;
	. . .


6.4    Custom Commands

The global ID "LWM: Custom Commands" returns a set of functions for
manipulating the custom commands and function key mappings.  These may
be changed by a server, but there should be some provision for setting
them back to the user's defaults when complete.

 listAdd     Adds an new custom command to the list.  The name will be
	     the string that the user sees in the custom popup, the
	     server is the internal server name of the CommandSequence
	     plug-in to activate, and the arg string is the agrument
	     that will be passed to that plug-in.  This returns false
	     if the new item could not be added.

 listRem     Removes a entry from the custom list given its name.

 funGet      Gets the server and argument strings for the current
	     association with function key N.  The bufLen is the
	     length of the string buffers.  This returns false if the
	     key is not assigned.

 funSet      Sets the server to activate and the argument to pass when
	     the given function key is pressed.

    (47)  Modeling Globals
	. . .
	typedef struct st_CustomCommandFuncs {
		int             (*listAdd) (const char *name,
					    const char *server,
					    const char *arg);
		void            (*listRem) (const char *name);
		int             (*funGet) (int n, char *server,
					   char *arg, int bufLen);
		void            (*funSet) (int n, const char *server,
					   const char *arg);
	} CustomCommandFuncs;
	. . .

For ARexx scripts on the Amiga Modeler, the server name is "$REXX" and
the argument is the script name.


6.5    Modeler Internal State

The global ID "LWM: State Query" returns a set of functions for
querying Modeler's global state.  It can be queried at any time
although it may only be altered at specific times.

 numLayers   This returns total number of data layers in Modeler.

 layerMask   This returns bits describing the set of layers included
	     in each of the possible EltOpLayer selections.  If the
	     set includes layer 1 then bit 0 is set, if it includes
	     layer 2 bit 1 is set, and so forth.

 surface     This returns the name of the default surface.

 bbox        This returns the number of points in the given layer, and
	     if minmax is a non-null pointer, it is treated as an
	     array of 6 doubles and is filled with the bounding box
	     information for the layer (x0, x1, y0, y1, z0, z1).

    (48)  Modeling Globals
	. . .
	typedef struct st_StateQueryFuncs {
		int             (*numLayers) (void);
		unsigned int    (*layerMask) (EltOpLayer);
		const char *    (*surface) (void);
		unsigned int    (*bbox) (EltOpLayer, double *minmax);
	} StateQueryFuncs;
	. . .


6.6    Surfaces List

The global ID "LWM: Surface List" returns a set of functions which can
be used to read and modify Modeler's surface list.  Clients may add,
rename and modify the contents of surfaces at any time, but there is
no capability to remove them.  Note that adding surfaces or renaming
them will alter the relative order of surfaces in the list.

 next        This returns the name of the surface after the given one.
	     If the argument is null, it returns the first surface.
	     If the argument is the last surface in the list, it
	     returns null.

 create      This creates a surface of the given name with no data.

 rename      This changes the name of a surface, reordering it in the
	     list.

 getData     This returns the size and contents of the surface data
	     parameters for the named surface.

 setData     This resets the data parameter block to the given size
	     and contents.

    (49)  Modeling Globals
	. . .
	typedef struct st_SurfaceListFuncs {
		const char *    (*next)    (const char *name);
		void            (*create)  (const char *name);
		void            (*rename)  (const char *name,
					    const char *newName);
		void *          (*getData) (const char *name, int *size);
		void            (*setData) (const char *name, int size,
					    void *data);
	} SurfaceListFuncs;
	. . .


6.7    Outline Font List

The global ID "LWM: Font List" returns a set of functions for reading
and modifying Modeler's font list.  The list may be modified at any
time, but keep in mind that altering the list may affect stored font
choices in your requesters, if any.

 count       This returns the total number of fonts in the list.

 index       This returns the list index for a named font, -1 if not
	     found.

 name        This returns the name of a font given its list index,
	     null if out of range.

 load        This loads the given file as a Type-1 font and returns
	     the new list index.  The fonts at this old index and
	     above are all shifted up.  It returns -1 for errors.

 clear       This removes the font at the given index from the list,
	     shifting all the others down.

    (50)  Modeling Globals
	. . .
	typedef struct st_FontListFuncs {
		int             (*count) (void);
		int             (*index) (const char *name);
		const char *    (*name)  (int index);
		int             (*load)  (const char *filename);
		void            (*clear) (int index);
	} FontListFuncs;


7    Animation Datatypes

The servers and globals for Layout share a set of type and value
definitions which are basic to understanding concepts dehind the
Layout servers and globals.


7.1    Coordinate and Range Scales

There are several conventions used to interpret different types of
values within LightWave and throughout this external interface.

 positions   Positions are always given as an array of three doubles
	     which are the X, Y and Z coordinates (respectively) of a
	     position with respect to some known coordinate system.
	     This system is always listed along with the vector
	     (usually object or world).

 directions  Direction vectors, such as normals, are also an X Y Z
	     array of doubles, but are normalized to be unit vectors.
	     The coordinate system for these is also always listed.

 rotations   Rotations are arrays of three doubles representing the
	     Euler angles (heading, pitch and bank, respectively) of
	     an item in some coordinate system.  Angles are
	     represented in radians.

 colors      Colors are given as an array of three doubles giving the
	     intensities of the red, green and blue componenets of the
	     color, respectively.  The values are scaled so that 0.0
	     is the minimum intensity and 1.0 is the maximum, although
	     out-of-range values are allowed.

 percentages Values which are represented on the LightWave user
	     interface as percentages are represented internally as
	     doubles scaled from 0.0 to 1.0.  A luminosity of 65.7%,
	     for example, would be held internally as the floating
	     point value 0.657.

Floating point values with a nominal range of 0.0 to 1.0 will
sometimes be converted to single-byte values for storing in image
buffers.  Colors and alphas are converted this way for final image
output and other values are used this way internally.  The floating
point value is clipped to be strictly within the 0.0 to 1.0 range and
is then scaled and converted to a BufferValue type so that 0.0 is 0
and 1.0 is 255.

    (51)  Animation Types

	typedef unsigned char     BufferValue;
	. . .


7.2    Items and Properties

A LightWave item is anthing which can be keyframed in the layout
interface.  All objects, lights, bones and cameras in LightWave are
items and have a unique LWItemID value.

    (52)  Animation Types
	. . .
	typedef void *           LWItemID;
	#define LWITEM_NULL      ((LWItemID) 0)
	. . .

Types of items are given by LWItemType codes.

    (53)  Animation Types
	. . .
	typedef int              LWItemType;
	#define LWI_OBJECT       0
	#define LWI_LIGHT        1
	#define LWI_CAMERA       2
	#define LWI_BONE         3
	. . .

All items have a set of vector parameters which servers can read (and
sometimes write) using property codes.

 POSITION    item location in its parent's coordinates.

 ROTATION    item rotation in its parent's coordinates.

 SCALING     item X, Y and Z scaling factors relative to its parent.

 RIGHT, UP, FORWARD
	     +X, +Y and +Z direction vectors, respectively, for the
	     item in world coordinates.  These three concatenated
	     together are the transformation matrix for the item.

 PIVOT       item pivot point in its own coordinates.

 W_POSITION  item location in world coordinates.

    (54)  Animation Types
	. . .
	typedef int              LWItemParam;
	#define LWIP_POSITION    1
	#define LWIP_RIGHT       2
	#define LWIP_UP          3
	#define LWIP_FORWARD     4
	#define LWIP_ROTATION    5
	#define LWIP_SCALING     6
	#define LWIP_PIVOT       7
	#define LWIP_W_POSITION  8
	. . .


7.3    Time

Time values in LightWave are given in two ways.  A frame number is the
index of a single image (typically the current image) in the output
sequence of still images that make up the animation.  A time value is
the precise instant of an event in seconds.  Assuming a scene rendered
at 30 frames per second and without motion blur (or with a blur length
of zero), frame N is a snapshot of the animation at a time in seconds
of N/30.  If there is motion blur, then some events in frame N will be
from times slightly before N/30 seconds, and if the motion blur length
is greater than 100%, then some events may even overlap with the times
of events in previous frames.

    (55)  Animation Types
	. . .
	typedef int              LWFrame;
	typedef double           LWTime;
	. . .


7.4    Errors

Server functions return errors to LightWave by returning a string
pointer.  A null string pointer indicates no error, and a non-null
pointer points to an error string.  The string will be displayed for
the user and, except where otherwise indicated, the user will have the
option to ignore the error and continue with the operation.

    (56)  Animation Types
	. . .
	typedef const char *     LWError;
	. . .


7.5    Instances and Handlers

Most LightWave plug-ins are "handlers" which manage "instances." An
instance is a specific collection of user settings for a texture,
image filter, etc., which persist across sessions by being stored in
scene and object files.  A `LWInstance' is any longword value which
identifies a specific instance for a specific server, usually a
pointer to allocated memory.

    (57)  Animation Types
	. . .
	typedef void *           LWInstance;
	. . .

    7.5.1    Instance Persistence

    Instances have to load and save their data to and from ASCII scene
    files and binary object files, and sometimes both, so the data
    read/write mechanism provides servers with functions to read and
    write data in both these formats.  The `read' function reads bytes
    from the source and returns the number of bytes read.  The `write'
    function writes bytes to the output and tracks any errors
    internally.  The format of the file is given by `ioMode' code,
    either OBJECT or SCENE.

	(58)  Animation Types
	    . . .
	    #define LWIO_OBJECT      0
	    #define LWIO_SCENE       1
	    . . .

    If the mode is OBJECT, the format is binary and no scene-specific
    information should be stored.  The read and write functions deal
    in raw bytes which can have any value from 0 to 255.  They read or
    write the number of bytes requested using the passed buffer.

    If the mode is SCENE, the format is ASCII and bytes stored must be
    in the extended ASCII range of 32 to 255.  Values outside this
    range are ignored or undefined.  The read and write functions in
    this case deal with lines.  The write function writes a line at a
    time and looks for a null terminator in the input rather than the
    length.  The read function can read partial lines if a length less
    then or equal to the total line length is requested.  If the
    length is greater than the remaining line length, the length is
    returned and the buffer is null-terminated.  The read function
    returns -1 for the actual end of input, since a read length of
    zero is valid for a blank line.

	(59)  Animation Types
	    . . .
	    typedef struct st_LWLoadState {
		    int               ioMode;
		    void             *readData;
		    int             (*read) (void *readData, char *buf,
					     int len);
	    } LWLoadState;

	    typedef struct st_LWSaveState {
		    int               ioMode;
		    void             *writeData;
		    void            (*write) (void *writeData, char *buf,
					      int len);
	    } LWSaveState;
	    . . .

    Plug-in clients which write instance data must do their own
    versioning so they can read old forms of their own data, and their
    own bit twiddling to read and write binary data on machines with
    different byte order and floating point formats.  Clients must
    also make sure they do not read past the end of their own data.
    This last restriction may be lifted in future versions.

    7.5.2    Handler Functions

    A server manages its instances by providing LightWave with
    functions to create, destroy, load and save them.  The server
    activation function gets a handler structure which it initializes
    with the standard instance handler functions listed here, plus
    whatever else is required by the specific class of plug-in.

     create      create a default instance.  Any failure should return
		 a null pointer and optionally set the error value.

     destroy     dispose of an instance.

     copy        copy the contents of the "from" instance to the "to"
		 instance.

     load        read an instance description from a file into an
		 already created instance.

     save        write an instance description to a file.

    The create function should create a default instance which can
    then be modified by the interface function.  The load and copy
    functions will overwrite existing instances with new values read
    from a file or a source instance.

	(60)  Animation Types
	    . . .
	    typedef struct LWInstHandler {
		    LWInstance      (*create) (LWError *);
		    void            (*destroy) (LWInstance);
		    LWError         (*copy) (LWInstance from, LWInstance to);
		    LWError         (*load) (LWInstance, const LWLoadState *);
		    LWError         (*save) (LWInstance, const LWSaveState *);
	    } LWInstHandler;
	    . . .

    7.5.3    Interface Server

    There is often another server associated with a handler and that
    is the "Interface" server.  The activation function for the
    interface server is called with a LWInstance as its local data.
    The server will then allow the user to edit the instance
    description and return.  The interface server is just another
    function that operates on instances of a specific type, but it is
    separate from the other instance handler functions for two
    reasons.  The first is that the user interface code is frequently
    the largest and least often used part of a handler, so it makes
    sense to allow it to be loaded separately only when needed.  The
    second is to permit plug-in authors to easily make "render-only"
    versions of their plug-in servers for rendering accelerators or
    packaging bundles.

    For example, if the plug-in type was "XXX", there would be two
    classes of server, "XXXHandler" and "XXXInterface".  Then for a
    specific server of the XXX type, called "MyXXX", there would be a
    MyXXX defined for the XXXHandler class which would provide all the
    normal handler functions, and there would also be a MyXXX server
    of the XXXInterface class which would perform the user interface.


8    Animation Server Classes

The many server classes for Layout provide a wide range of
capabilities and extentions to basic LightWave rendering and
animation.  Since there are so many servers there may be multiple ways
to accomplish the same effect, some better than others.


8.1    Utilities

The "ImageSaver" class, described in the "LightWave Images" document
is used by Layout to save output images in different formats.


8.2    Image Post Processing

The "ImageFilterHandler" (and "ImageFilterInterface") class is used to
apply image post processing (filtering) effects to the final rendered
image.  Each filter is applied after all the antialiasing and motion
blur passes are complete, and the server modifying the red, green,
blue and alpha values of the final image.

    8.2.1    Input Buffers

    In addition to looking at the RGBA of the image, the server can
    compute its effects based on a potentially large set of full-image
    buffers, given by the LWBUF codes below.  Each of these is a
    full-screen array of 0-255 BufferValues indicating the presence or
    absence of that particular attribte for each pixel in the final
    image.

     RED, GREEN, BLUE and ALPHA
		 These buffers are the outputs of the rendering pass
		 and are the base which should be modified by the
		 server.  These are always provided to every image
		 filter.

     SPECIAL     This value is assigned by the user on a surface by
		 surface basis which is used only for this filter.
		 This is designed to be used to activate the post
		 processing effect for specific surfaces, and
		 user-assigned percentages show up here as 0-255
		 values in the buffer.

     LUMINOUS..RAW_BLUE
		 These eight buffers are the raw values of the surface
		 parameters before shading.

     SHADING     This buffer is a picture of the diffuse shading
		 applied to the raw shapes in the image.

     SHADOW      This indicates where shadows are falling in the final
		 image.  It may also be thought of as an illuminations
		 map, showing what parts of the image are visible to
		 the lights in the scene.

     GEOMETRY    The value in this buffer is computed from the
		 dot-product of the surface normal with the eye
		 vector.  It reveals something about the underlying
		 shape of the objects in the image.  Where this buffer
		 is 255 (or 1.0) the surface is facing directly toward
		 the camera, and where this buffer is 0, the surface
		 is edge-on to the camera.

     DEPTH       The depth buffer is a map of the distance of each
		 pixel from the camera plane.  This buffer is
		 different from all the others because it is floating
		 point, and because it is not anti-aliased or
		 motion-blured.

	(61)  Animation Servers

	    #define LWBUF_SPECIAL    0

	    #define LWBUF_LUMINOUS   1
	    #define LWBUF_DIFFUSE    2
	    #define LWBUF_SPECULAR   3
	    #define LWBUF_MIRROR     4
	    #define LWBUF_TRANS      5
	    #define LWBUF_RAW_RED    6
	    #define LWBUF_RAW_GREEN  7
	    #define LWBUF_RAW_BLUE   8

	    #define LWBUF_SHADING    9
	    #define LWBUF_SHADOW     10
	    #define LWBUF_GEOMETRY   11
	    #define LWBUF_DEPTH      12

	    #define LWBUF_RED        32
	    #define LWBUF_GREEN      33
	    #define LWBUF_BLUE       34
	    #define LWBUF_ALPHA      35
	    . . .

    8.2.2    Filter Access

    At each frame that the filter is active, the server will get the
    image to process.  It reads the contents of the image buffers and
    writes new RGB and Alpha data to the output buffer and exits when
    it has processed the entire frame.  This processing is done using
    a `FilterAccess' structure which contains data fields and
    functions.

     width, height
		 This is the total size of the input and output image
		 buffers.  Filters cannot change the image size and
		 all buffers are the same size.

     frame       This is the frame number of this final image.

     start, end  These two times are the start and end times for the
		 frame.  The times are the same unless the frame has
		 motion-blur, in which case the difference between
		 them is the "exposure time" for the frame.

     bufLine, fltLine
		 The functions allow access to the input buffers and
		 return pointers to a line of the buffer of the given
		 type.  For y=0, the top line of the buffer is
		 returned; for y=1 the second to the top line, etc.
		 `bufLine' returns lines from byte-encoded buffers and
		 `fltLine' returns lines from float-encoded buffers
		 (currently only LWBUF_DEPTH).  Invalid type codes
		 return null pointers.

     setRGB, setAlpha
		 The output buffers must be set using these functions
		 which set the final value at a pixel location.  The
		 input RGBA buffers do not change as the output
		 buffers are modified.  A filter must set every pixel
		 in the output image even if it does not alter the
		 value, but it can set them in any order.

     monitor     This monitor can be used by the server to update the
		 host about its progress through the frame.  As with
		 all monitors, the number of steps should be kept
		 fairly low since checking for abort can have
		 significant overhead on some systems.  Every line or
		 every other line should be about right.

	(62)  Animation Servers
	    . . .
	    typedef struct st_FilterAccess {
		    int               width, height;
		    LWFrame           frame;
		    LWTime            start, end;
		    BufferValue *   (*bufLine) (int type, int y);
		    float *         (*fltLine) (int type, int y);
		    void            (*setRGB)   (int x, int y, BufferValue
		       [3]);
		    void            (*setAlpha) (int x, int y, BufferValue);
		#ifndef LW_PRERELEASE
		    Monitor          *monitor;
		#endif
	    } FilterAccess;
	    . . .

    8.2.3    Handler

    The activation function for an image filter gets passed a blank
    handler structure as its local data which the server must fill in.
    In addition to the normal instance functions, it must also provide
    a `process' function and `flags' function.

     process     This is the function which filters a single frame
		 given an instance and the access structure.

     flags       This returns a set of bits representing the buffers
		 this instance wants at processing time, where the bit
		 numbers are the LWBUF values above.  Only buffers
		 0-12 need to be specified this way since the R, G, B
		 and Alpha buffers are always provided.  Undefined
		 bits should be clear by default.

	(63)  Animation Servers
	    . . .
	    typedef struct st_ImageFilterHandler {
		    LWInstHandler     inst;
		    void            (*process) (LWInstance, const FilterAccess
		       *);
		    unsigned int    (*flags) (LWInstance);
	    } ImageFilterHandler;
	    . . .


8.3    Procedural Texture

The "ShaderHandler" (and "ShaderInterface") class is for modifying the
attributes of a pixel as it is being rendered.  These are sometimes
called "procedural textures," but in the LightWave implementation they
are quite a bit more powerful than that.  Since it is called on a
per-pixel basis, this interface is designed for speed.

As LightWave goes through the process of converting abstract 3D
surfaces into imagery, it breaks surfaces down into tiny patches which
each get a uniform color.  Computing the color of these tiny spots is
done by starting from a set of basic surface parameters which are
approximately constant over the patch: base color, surface normal,
luminosity, diffuse reflection, specular reflection, reflectivity,
transparency, refractive index and roughness (or glossiness).  From
these values LightWave's illumination calculation computes the color
and intensity of reflected light and transmitted light and determines
the color of the spot as seen from the given viewpoint.  Plug-in
shaders can either alter the base parameters and let LightWave do the
rendering calculation, or they can perform the illumination themselves
and compute the preceived color directly.

    8.3.1    Shader Access

    The spot evaluation function is called for every visible spot on a
    surface with a `ShaderAccess' structure describing the spot to be
    shaded.  The access structure for contains some values which are
    read-only and some which are meant to be modified.  The read-only
    values describe the geometry of the pixel being shaded.  The
    read-write values describe the current parameters of this pixel
    and should be modified in place to affect the final look of the
    spot.  Since shaders may be layered, these properties may be
    altered many more times before final rendering.  The access
    structure also contains special functions usable only while
    rendering.

	(64)  Animation Servers
	    . . .
	    typedef struct st_ShaderAccess {
		    <Read-only shader parameters>
		    <Modifiable shader parameters>
		    <Shader functions>
	    } ShaderAccess;
	    . . .

    8.3.2    Geometric Parameters

    The spot parameters are read-only and describe the local geometry
    of the spot being shaded.

     sx, sy      Spot location in the final image in pixel coordinates
		 with (0,0) at the upper-left.

     oPos, wPos  Spot position in object coordinates and world
		 coordinates.

     gNorm       Geometric normal in world coordinates.  This is the
		 raw polygonal normal at the spot, unperturbed by
		 smoothing or bump mapping.

     spotSize    Approximate spot diameter.  This is a very
		 approximate value since spots on a surface viewed on
		 edge are long and thin.  This can be used to compute
		 texture antialiasing.

     raySource   Origin of the incoming viewing ray in world
		 coordinates.  Often this will be the camera but it
		 does not have to be.

     rayLength   The distance the viewing ray traveled in free space
		 to reach this spot.

     cosine      This is the cosine of the angle between the viewing
		 ray and the surface normal at this spot.  It
		 indicates how glancing the view is and gives a
		 measure of how approximate the spot size is.

     oXfrm, wXfrm
		 Object to world and world to object transformation
		 matrices.  This can be computed other ways, but are
		 included here for speed and are intended to be used
		 primarily for directional vectors.

     objID       The object being shaded.  A single shader instance
		 can be shared between multiple objects, so this may
		 be different for each evaluation.  For sample sphere
		 rendering the ID will refer to an object not in the
		 current scene.

     polNum      The polygon number of the object being shaded.  While
		 this will be the polygon number for normal mesh
		 objects, it may represent other sub-object
		 information in non-mesh objects.

	(65)  Read-only shader parameters

		int              sx, sy;
		double           oPos[3], wPos[3];
		double           gNorm[3];
		double           spotSize;
		double           raySource[3];
		double           rayLength;
		double           cosine;
		double           oXfrm[9],  wXfrm[9];
		LWItemID         objID;
	    #ifndef LW_PRERELEASE
		int              polNum;
	    #endif

    8.3.3    Modifiable Parameters

    These parameters are used by the renderer to compute the perceived
    color at the spot and may be modified by the shader.  The shader
    must return the correct flags for any value it will modify or the
    change will not take effect (see below).

     wNorm       Surface normal in world coordinates.  Modifying this
		 makes the surface look bumpy without altering the
		 geometry (bump mapping).  The shader needs to
		 renormalize the vector after perturbation.

     color       Base color of the spot.

     luminous    Percentage luminosity.

     diffuse     Percentage diffuse reflection.

     specular    Percentage specular reflection.

     mirror      Percentage reflectivity.

     transparency
		 Percentage transparency.

     eta         Index of refraction.

     roughness   Surface roughness, often expressed as the inverse of
		 glossiness.

	(66)  Modifiable shader parameters

	    double           wNorm[3];
	    double           color[3];
	    double           luminous;
	    double           diffuse;
	    double           specular;
	    double           mirror;
	    double           transparency;
	    double           eta;
	    double           roughness;

    To set the perceived color directly a shader can set all the
    parameters to zero except for luminous which is 1.0 and color
    which is the output color of the spot.

    8.3.4    Shading Functions

    Special functions are provided to shaders which are not available
    in any other context.

     illuminate  This function returns the light ray (color and
		 direction) hitting the given position from the given
		 light at the current instant.  The return value is
		 zero if the light does not illuminate the given world
		 coordinate position at all.  The color includes
		 effects from shadows (if any), falloff, spotlight
		 cones and transparent objects between the light and
		 the point.

     rayTrace    This function may be called to trace a ray from the a
		 given location in a given direction (in world
		 coordinates).  The return value is the length of the
		 ray (or -1.0 if infinite) and the color coming from
		 that direction.  The direction used is the outgoing
		 direction and must be normalized to be a unit vector.

	(67)  Shader functions

	    int            (*illuminate) (LWItemID light,
					  const double position[3],
					  double direction[3],
					  double color[3]);
	    double         (*rayTrace) (const double position[3],
					const double direction[3],
					double color[3]);

    8.3.5    Instance

    A shader instance may store its data in an object (in the case of
    a surface texture) or in a scene (in the case of a clip map) so
    the save/load functions should be prepared to deal with both
    cases.

     init        Called at the start of rendering a sequence of
		 frames.

     cleanup     Called when current sequence is complete.

     newTime     Called at the start of each new time within the
		 current sequence.

     evaluate    Called to compute the shading of each affected pixel
		 within the current time.

     flags       Returns a word containing status bits for the
		 instance.  Undefined flag bits should be clear by
		 default.  The first nine LWSHF bits should be set
		 only if the shader instance is going to modify that
		 particular attribute.  RAYTRACE must be set if the
		 shader intends to use the `rayTrace' function.

	(68)  Animation Servers
	    . . .
	    #define LWSHF_NORMAL    (1<<0)
	    #define LWSHF_COLOR     (1<<1)
	    #define LWSHF_LUMINOUS  (1<<2)
	    #define LWSHF_DIFFUSE   (1<<3)
	    #define LWSHF_SPECULAR  (1<<4)
	    #define LWSHF_MIRROR    (1<<5)
	    #define LWSHF_TRANSP    (1<<6)
	    #define LWSHF_ETA       (1<<7)
	    #define LWSHF_ROUGH     (1<<8)
	    #define LWSHF_RAYTRACE  (1<<10)
	    . . .

	(69)  Animation Servers
	    . . .
	    typedef struct st_ShaderHandler {
		    LWInstHandler     inst;
		    LWError         (*init) (LWInstance);
		    void            (*cleanup) (LWInstance);
		    LWError         (*newTime) (LWInstance, LWFrame, LWTime);
		    void            (*evaluate) (LWInstance, ShaderAccess *);
		    unsigned int    (*flags) (LWInstance);
	    } ShaderHandler;
	    . . .


8.4    Procedural Displacement Map

The "DisplacementHandler" (and "DisplacementInterface") class is
called upon before rendering to modify the geometry of an object.
This is done not only during rendering but also during interactive
previewing in the Layout window.  This means that a server should
always be prepared to process a displacement instance at any time.

    8.4.1    Displacement Access

    At its core a displacement handler takes point coordinates and
    moves them for each timestep.  The access structure for a
    displacement map gets the position of the point to displace in two
    ways.

     oPos        This is the point location in object coordinates and
		 is read-only.  The server may use this in
		 computations, but moving it has no effect.

     source      This is the location to be transformed in place by
		 the displacement.  If this is not a world-coordinate
		 displacement, then the source coordinates are the in
		 the object coordinate system but have been already
		 displaced by any morphing or boning applied to the
		 object, and may differ from the object coordinates.
		 If the displacment is in world coordinates (see
		 `flags' below), then the source coordinates are
		 morphed, boned and transformed by object motion (i.e.
		 they are world coordinates).

	(70)  Animation Servers
	    . . .
	    typedef struct st_DisplacementAccess {
		    double           oPos[3];
		    double           source[3];
	    } DisplacementAccess;
	    . . .

    8.4.2    Handler

    The handler functions for a displacement map are the same as a
    shader except for the lack of `init' and `cleanup' functions.  The
    `newTime' function also has a parameter for the ID of the object
    being affected by the displacement.  The LWDMF_WORLD bit should be
    set in the `flags' return value if the displacement will take
    place in world coordinates.

	(71)  Animation Servers
	    . . .
	    typedef struct st_DisplacementHandler {
		    LWInstHandler     inst;
		    LWError         (*newTime) (LWInstance, LWItemID,
						LWFrame, LWTime);
		    void            (*evaluate) (LWInstance,
						 DisplacementAccess *);
		    unsigned int    (*flags) (LWInstance);
	    } DisplacementHandler;

	    #define LWDMF_WORLD     (1<<0)
	    . . .


8.5    Procedural Item Animation

The "ItemMotionHandler" (and "ItemMotionInterface") class is used to
apply animation behavior to any item in a scene which can be
keyframed.  After the keyframe position of the item is computed, the
item motion server can alter the keyframed motion or replace it with a
completely different one.  Motions will be evaluated both during
rendering and while interactively laying out a scene.

    8.5.1    Item Motion Access

    At each time instant and for each affected item, the motion
    evaluation function will be called with an access structure
    holding the ID of the item and the time instant for which the
    motion should be computed.  The server can query keyframe
    parameters for the item and sets it own values for the current
    time.

     item        This is set to the ID for the item to be affected by
		 the procedural motion.

     frame, time This is set to the current instant for which the
		 motion should be evaluated.

     getParam    Returns the keyframed motion set by the user for the
		 item at any given time.  Only the POSITION, ROTATION
		 and SCALING parameters may be queried.

     setParam    Used by the evaluation function to set the computed
		 motion of the item at the current time.  Only the
		 POSITION, ROTATION and SCALING parameters may be set.

	(72)  Animation Servers
	    . . .
	    typedef struct st_ItemMotionAccess {
		    LWItemID          item;
		    LWFrame           frame;
		    LWTime            time;
		    void            (*getParam) (LWItemParam, LWTime,
						 double vector[3]);
		    void            (*setParam) (LWItemParam,
						 const double vector[3]);
	    } ItemMotionAccess;
	    . . .

    Procedural motions are not currently allowed to interact.  If a
    motion evaluation function attempts to read out the position of
    another object which is affected by a procedural motion, only the
    values of the keyframed motion will be returned.

    8.5.2    Handler

    The handler for item motions adds only the `evaluate' function to
    the standard set of handler functions.  This computes the motion
    for an item at a given timestep, and may be called at any time.

	(73)  Animation Servers
	    . . .
	    typedef struct st_ItemMotionHandler {
		    LWInstHandler     inst;
		    void            (*evaluate) (LWInstance,
						 const ItemMotionAccess *);
	    } ItemMotionHandler;
	    . . .


8.6    Procedural Object Replacement

The "ObjReplacementHandler" (and "ObjReplacementInterface") class
allows another type of animation which can replace the entire object
geometry at every single step.  Replacement is done by object name, so
the server evaluation function can provide a new object name to load
for each subframe timestep, or it can only load a new object
periodically, allowing the same geometry to persist for a length of
time.

Filenames are used instead of direct mesh replacement for generality.
An object replacement server could use a series of prebuilt objects,
like character heads for example, to do expressions or lip-syncing by
providing the name of the correct head at each step.  Some animation
could be done very efficiently using a combination of object
replacement and object import servers.  The replacement server could
write a brief description file for the parameters of a timestep
(positions and sizes of metaballs, for example) which the object
import server could then convert into a complete mesh while loading.
A simple form of this server could be used to replace objects with
nulls when they are not visible in the scene.

    8.6.1    Object Replacement Access

    The access structure passed to the evaluation function contains
    information about the currently loaded object and the next
    timestep.  The server compares the current settings and the next
    step and provides a new filename if a different object should be
    loaded for the next timestep to be evaluated.  If the currently
    loaded geometry can be used for the new frame and time, then the
    new filename can be set to null.

     objectID    Item ID for the object whose geometry may be replaced
		 by this server.

     curFrame, curTime, newFrame, newTime
		 The frame and time values for the currently loaded
		 geometry and the next step.  New geometry should be
		 loaded if the object needs to look different at the
		 two different times.  The times may not be
		 sequential, since network rendering can cause the
		 renderer to jump around between non-sequential times.

     curType, newType
		 The type of the geometry currently loaded and needed
		 for the next timestep.  The server can provide
		 different geometry for interactive previewing and
		 actual rendering by examining this value.
		 OBJREP_NONE is only used when there is no geometry
		 loaded at all for the current time.

	(74)  Animation Servers
	    . . .
	    #define OBJREP_NONE      0
	    #define OBJREP_PREVIEW   1
	    #define OBJREP_RENDER    2
	    . . .

     curFilename This is set to the object geometry file currently
		 loaded, and may be null if there is no geometry
		 loaded.

     newFilename This is the filename of a new object file to be
		 loaded as the geometry for this item at the new
		 timestep, and is the only field set by the server.
		 It should only be set if the new geometry differs
		 from that currently loaded, since loading new
		 geometry incurs significant overhead.

	(75)  Animation Servers
	    . . .
	    typedef struct st_ObjReplacementAccess {
		    LWItemID         objectID;
		    LWFrame          curFrame, newFrame;
		    LWTime           curTime,  newTime;
		    int              curType,  newType;
		    const char      *curFilename;
		    const char      *newFilename;
	    } ObjReplacementAccess;
	    . . .

    In Layout 4.0, curType is always set to OBJREP_NONE and curFrame,
    curTime and curFilename are not set.  4.0 treats every frame as if
    no model were loaded.

    8.6.2    Handler

    In addition to the normal handler functions, the server provids an
    `evaluate' function which is called for each affected object at
    each timestep to get new geometry.  This function can be called at
    any time while rendering or setting up animations.

	(76)  Animation Servers
	    . . .
	    typedef struct st_ObjReplacementHandler {
		    LWInstHandler     inst;
		    void            (*evaluate) (LWInstance,
						 ObjReplacementAccess *);
	    } ObjReplacementHandler;
	    . . .


8.7    Frame Buffers

The "FrameBufferHandler" (and "FrameBufferInterface") class is used to
display the output of rendering as each frame is completed.  This is
for the user to view, so the frame buffer should also be able to pause
waiting for user input.

A frame buffer is an instance, but it may be very limited.  The built-
in frame buffers have no UI and no stored state.

 open        Open display at the given size.

 close       Close display and end display transations.

 begin       Start a new frame.

 write       Write a new line of RGB and alpha data to the
	     framebuffer.  Lines always come from top to bottom and
	     there are always enough to fill the width and height of
	     the requested display.

 pause       Display the buffer to the user and wait for their signal
	     to continue before returning.

The sequence of calls for rendering to the frame buffer can be
visualized as a regular expression:

open, (begin, (write)H, pause?)*, close

Any number of frames may be displayed in a session (even zero).  Write
will always be called for all the lines in the image and pause is
optional.

    (77)  Animation Servers
	. . .
	typedef struct st_FrameBufferHandler {
		LWInstHandler     inst;
		LWError         (*open) (LWInstance, int w, int h);
		void            (*close) (LWInstance);
		LWError         (*begin) (LWInstance);
		LWError         (*write) (LWInstance,
					  const BufferValue *R,
					  const BufferValue *G,
					  const BufferValue *B,
					  const BufferValue *alpha);
		void            (*pause) (LWInstance);
	} FrameBufferHandler;
	. . .


8.8    Animation Output

The "AnimSaverHandler" (and "AnimSaverInterface") class is used to
write out animations.  The scheme is nearly identical to framebuffers,
except that there is no `pause' function and in addition to the image
size, LightWave will also pass a filename for the animation file.

    (78)  Animation Servers
	. . .
	typedef struct st_AnimSaverHandler {
		LWInstHandler     inst;
		LWError         (*open) (LWInstance, int w, int h,
					 const char *filename);
		void            (*close) (LWInstance);
		LWError         (*begin) (LWInstance);
		LWError         (*write) (LWInstance,
					  const BufferValue *R,
					  const BufferValue *G,
					  const BufferValue *B,
					  const BufferValue *alpha);
	} AnimSaverHandler;
	. . .


8.9    Scene Conversion

The "SceneConverter" class is used in import foreign scene formats.
When the user selects a file to load as a scene, LightWave first
attempts to load it directly as an LWSC format file.  It it cannot, it
will pass the filename to each scene converter in sequence.  The scene
converter will attempt to read the file and rewrite it as an LWSC
file.  After successful translation the server will pass the name of
the new scene back to LightWave.  The file will be loaded and the
server will be called back again to delete the translated scene file.

 filename    Filename of foreign scene file.  This is set by the host
	     before activating the server.  This is the file to try to
	     parse.

 readFailure If the server can recognize the format but cannot parse
	     the file for some reason, it should set this error return
	     value.

 tmpScene    If the server sucessfully parses the foreign scene file,
	     it should write a translation of that scene as a LWSC
	     format file and return the name of this translation scene
	     in this field.

 deleteTmp   After reading the temporary scene file set above, the
	     host will call back this delete function to dispose of
	     the file and any other temporary state.  The `tmpScene'
	     and `deleteTmp' fields should be set as a pair before the
	     server returns.

    (79)  Animation Servers
	. . .
	typedef struct st_SceneConverter {
		const char       *filename;
		LWError           readFailure;
		const char       *tmpScene;
		void            (*deleteTmp) (const char *tmpScene);
	} SceneConverter;

When the server is called, only `filename' will be set.  It then must
set the other three fields to one of the following configurations:

 readFailure and tmpScene both null
	     This indicates that the server was unable to recognize
	     the file format and no translation was done.  LightWave
	     will simply try the next translator.

 readFailure set, tmpScene null
	     This indicates that the file format was recognized, but
	     that a failure of some kind occured during translation.
	     LightWave will display this error and will stop
	     attempting to translate the file.

 readFailure null, tmpScene set
	     This indicates successful translation.  LightWave will
	     read `tmpScene' as an LWSC file and then will call the
	     `deleteTmp' function to dispose of it.  Note that if
	     tmpScene is set, deleteTmp must be set as well.


8.10    General Function

The "LayoutGeneric" class is provided for general layout functionality
which does not fit into any of the previous server or handler
categories.  Servers of this class can be activated by the user from
the Layout interface to perform non-rendering functions, such as
configuring external devices, performing calculations, etc.

Normal global information is available to this class of server, but
the local pointer is unused.


9    Animation Globals

This section contains descriptions of the global data pointers which
can be accessed from LightWave's global function.  The ID string for
each global is given in quotes.


9.1    Item Information

The global ID "LW Item Info" returns functions for traversing the
entire set of items in the scene and getting information about all of
them.  This information is common to all items.  Any information
specific to certain item types is given by separate global functions.

 first       Returns the ID of the first item of a given type.  If
	     type is LWI_BONE, the second argument is the ID of the
	     boned object.  If there are no items of this type this
	     returns LWITEM_NULL.

 next        Returns the next item of the same type as the argument.
	     If there are no more, this returns LWITEM_NULL.

 firstChild  Returns the first child item of the parent item.  It
	     returns LWITEM_NULL if none.

 nextChild   Returns the next child item given a parent item and the
	     previous child.  It returns LWITEM_NULL if that was the
	     last one.

 parent      Returns the item's parent, if any, and LWITEM_NULL if
	     none.

 target      Returns the item's target, if any, and LWITEM_NULL if
	     none.

 goal        Returns the item's goal, if any, and LWITEM_NULL if none.

 type        Returns the type of an arbitrary item.

 name        Returns the name of the item as it appears to the user.

 param       Returns vector parameters from an item using a
	     LWItemParam code to identify the parameter desired.  The
	     value is written to the vector array for the given time.

 limits      Returns upper and lower bounds on vector parameters.
	     These may be limits set by the user on joint angles or
	     ranges of movement.  LWVECF flag bits are returned to
	     indicate which of the three vector indicies contain
	     limits.  Any bits unset are unbounded.

    (80)  Animation Types
	. . .
	#define LWVECF_0        (1<<0)
	#define LWVECF_1        (1<<1)
	#define LWVECF_2        (1<<2)
	. . .

    (81)  Animation Globals

	typedef struct st_LWItemInfo {
		LWItemID        (*first)  (LWItemType, LWItemID);
		LWItemID        (*next)   (LWItemID);
		LWItemID        (*firstChild) (LWItemID parent);
		LWItemID        (*nextChild) (LWItemID parent, LWItemID
		   prevChild);
		LWItemID        (*parent) (LWItemID);
		LWItemID        (*target) (LWItemID);
		LWItemID        (*goal)   (LWItemID);
		LWItemType      (*type)   (LWItemID);
		const char *    (*name)   (LWItemID);
		void            (*param)  (LWItemID, LWItemParam, LWTime,
					   double vector[3]);
		unsigned int    (*limits) (LWItemID, LWItemParam,
					   double min[3], double max[3]);
	} LWItemInfo;
	. . .


9.2    Object Information

The global ID "LW Object Info" returns functions for object-specific
information.

 filename    Returns the filename for the object file.

 numPoints, numPolygons
	     Returns the number of points and polygons in the object
	     mesh.

 shadowOpts  Returns bits for shadow options, as below.

    (82)  Animation Types
	. . .
	#define LWOSHAD_SELF     (1<<0)
	#define LWOSHAD_CAST     (1<<1)
	#define LWOSHAD_RECEIVE  (1<<2)
	. . .

 dissolve    Returns the object dissolve percentage as a function of
	     time.

    (83)  Animation Globals
	. . .
	typedef struct st_LWObjectInfo {
		const char *    (*filename) (LWItemID);
		int             (*numPoints) (LWItemID);
		int             (*numPolygons) (LWItemID);
		unsigned int    (*shadowOpts) (LWItemID);
		double          (*dissolve) (LWItemID, LWTime);
	} LWObjectInfo;
	. . .


9.3    Bone Information

The global ID "LW Bone Info" returns functions for getting
bone-specific information.

 flags       Returns a set of flag bits for the given bone, as
	     follows.

    (84)  Animation Types
	. . .
	#define LWBONEF_ACTIVE          (1<<0)
	#define LWBONEF_LIMITEDRANGE    (1<<1)
	. . .

 restParam   This gets vector parameters for the rest position of a
	     given bone.  Parameters of the animated bone can be read
	     from the normal item info functions.

 restLength  This gets the special rest length parameter of the given
	     bone.

 limits      For limited range bones, this gets the inner and outer
	     limit radii for the bone.  Influence areas are in the
	     shape of a cylinder with hemispherical ends centered at
	     the tips of the bone.

    (85)  Animation Globals
	. . .
	typedef struct st_LWBoneInfo {
		unsigned int    (*flags) (LWItemID);
		void            (*restParam) (LWItemID, LWItemParam,
					      double vector[3]);
		double          (*restLength) (LWItemID);
		void            (*limits) (LWItemID, double *inner,
					   double *outer);
	} LWBoneInfo;
	. . .


9.4    Light Information

The global ID "LW Light Info" returns functions for getting
light-specific information.

 ambient     Returns the ambient light color (with intensity factored
	     in) at the given time.  There is no light ID needed since
	     this is global to the scene.

 type        Returns the type of the given light as one of the
	     following values.

    (86)  Animation Types
	. . .
	#define LWLIGHT_DISTANT  0
	#define LWLIGHT_POINT    1
	#define LWLIGHT_SPOT     2
	. . .

 color       Returns the light color (with intensity factored in) at
	     the given time.

 shadowType  Returns the shadow type for the given light as one of the
	     following values.

    (87)  Animation Types
	. . .
	#define LWLSHAD_OFF      0
	#define LWLSHAD_RAYTRACE 1
	#define LWLSHAD_MAP      2
	. . .

 coneAngles  Returns the cone angles for spotlights.  Radius is half
	     the total light code angle and edge is the angular width
	     of the soft edge.

    (88)  Animation Globals
	. . .
	typedef struct st_LWLightInfo {
		void            (*ambient) (LWTime, double color[3]);
		int             (*type) (LWItemID);
		void            (*color) (LWItemID, LWTime, double color[3]);
		int             (*shadowType) (LWItemID);
		void            (*coneAngles) (LWItemID, double *radius,
					       double *edge);
	} LWLightInfo;
	. . .


9.5    Camera Information

The global ID "LW Camera Info" returns functions for accessing
information specific to the camera.  A camera has an ID which must be
passed to these functions in anticipation of multiple cameras per
scene.

 zoomFactor  Returns the zoom factor for the camera at the given time.

 focalLength Returns the focal length of the camera lens at the given
	     time.  Focal length is expressed in millimeters.

 focalDistance
	     Returns the distance to the focal plane of the camera at
	     the given time.

 fStop       Returns the F-Stop number at the given time.

 blurLength  Returns the blur length as a fraction of the frame time
	     for the given time.

 fovAngles   Returns the camera field of view angles at the given
	     time.  These are angles in radians centered around the
	     camera direction.

    (89)  Animation Globals
	. . .
	typedef struct st_LWCameraInfo {
		double          (*zoomFactor) (LWItemID, LWTime);
		double          (*focalLength) (LWItemID, LWTime);
		double          (*focalDistance) (LWItemID, LWTime);
		double          (*fStop) (LWItemID, LWTime);
		double          (*blurLength) (LWItemID, LWTime);
		void            (*fovAngles) (LWItemID, LWTime,
					      double *horizontal,
					      double *vertical);
	} LWCameraInfo;
	. . .


9.6    Scene Information

The global ID "LW Scene Info" returns a block of information about the
scene itself.  This is all strictly read-only.

 name        User's name for the scene.

 filename    Filename of the scene file.

 numPoints, numPolygons
	     Total number of points and polygons for all the objects
	     in the scene.

 renderType  This can be one of the following values.

    (90)  Animation Types
	. . .
	#define LWRTYPE_WIRE            0
	#define LWRTYPE_QUICK           1
	#define LWRTYPE_REALISTIC       2
	. . .

 renderOpts  This is a combination of bits for different rendering
	     options.  EVENFIELDS is set only if field rendering is on
	     and the first line of the output image is from the field
	     that comes first in time.

    (91)  Animation Globals
	. . .
	#define LWROPT_SHADOWTRACE      (1<<0)
	#define LWROPT_REFLECTTRACE     (1<<1)
	#define LWROPT_REFRACTTRACE     (1<<2)
	#define LWROPT_FIELDS           (1<<3)
	#define LWROPT_EVENFIELDS       (1<<4)
	#define LWROPT_MOTIONBLUR       (1<<5)
	#define LWROPT_DEPTHOFFIELD     (1<<6)
	#define LWROPT_LIMITEDREGION    (1<<7)
	. . .

 frameStart, frameEnd, frameStep
	     The range of frames defined for the scene.

 framesPerSecond
	     Number of frames per real-time second.  This will be 30
	     for video (even field rendered), and 24 for film.

 frameWidth, frameHeight
	     Final output image size in pixels.

 pixelAspect Pixel aspect ratio as pixel-width / pixel-height.  Values
	     greater than one mean short wide pixels and values less
	     than one mean tall thin pixels.

 minSamplesPerPixel, maxSamplesPerPixel
	     Limits on number of samples per pixel in the final image.
	     Because of different rendering techniques and adaptive
	     sampling it is impossible to compute a precise number of
	     antialiasing samples at any pixel, but this gives a range
	     for the current rendering options.

 limitedRegion
	     The location of the limited region area, given as x0, y0,
	     x1, y1.

    (92)  Animation Globals
	. . .
	typedef struct st_LWSceneInfo {
		const char      *name;
		const char      *filename;
		int              numPoints;
		int              numPolygons;
		int              renderType;
		int              renderOpts;
		LWFrame          frameStart;
		LWFrame          frameEnd;
		LWFrame          frameStep;
		double           framesPerSecond;
		int              frameWidth;
		int              frameHeight;
		double           pixelAspect;
		int              minSamplesPerPixel;
		int              maxSamplesPerPixel;
		int              limitedRegion[4];      /* x0, y0, x1, y1 */
	} LWSceneInfo;
	. . .


9.7    Image List Information

The global ID "LW Image List" returns functions for traversing
LightWave's image list and accessing values in the image.  Images are
identified by an abstract data type.

    (93)  Animation Types
	. . .
	typedef void *           LWImageID;
	. . .

 first       Returns the first image in the list, null if none.

 next        Returns the next image after the given one, null if none.

 load        Loads a file as an image, adds it to the list and returns
	     it.

 name        Returns the user's name for an image.

 filename    Returns the filename for the loaded image.  This is the
	     value that should be stored for later retrieval of the
	     image using `load.' If the ID refers to an image
	     sequence, the frame number will be used to construct the
	     appropriate image filename.

 isColor     Returns true if the image has color data or false if only
	     greyscale.

 needAA      This needs to be called by shaders that want to use the
	     "spot" functions to access values in the image in the
	     course of their shading calculations.  This function can
	     only be called from a shader's `init' function.

 size        Returns the width and height of the image in pixels.

 luma        Returns the greyscale value of the image from 0-255.  If
	     this is a color source image the value returned is the
	     NTSC luminence.

 RGB         Returns the RGB color of the image from 0-255 at the
	     given pixel.

 lumaSpot, RGBSpot
	     Returns the floating point greyscale or color value of
	     the image for a spot of the given diameter at the given
	     center in the image.  These functions can only be called
	     during the spot evaluation function of a shader, and
	     `needAA' must have been called during the shader's
	     initialization.  If the spot size is small and `blend' is
	     true, the color value will be interpolated from between
	     image pixels.

 clear       Removes the image from the scene, clearing all
	     references.

    (94)  Animation Globals
	. . .
	typedef struct st_LWImageList {
		LWImageID       (*first) (void);
		LWImageID       (*next) (LWImageID);
		LWImageID       (*load) (const char *);
		const char *    (*name) (LWImageID);
	    #ifndef LW_PRERELEASE
		const char *    (*filename) (LWImageID, LWFrame);
	    #else
		const char *    (*filename) (LWImageID);
	    #endif
		int             (*isColor) (LWImageID);
		void            (*needAA) (LWImageID);
		void            (*size) (LWImageID, int *w, int *h);
		BufferValue     (*luma) (LWImageID, int x, int y);
		void            (*RGB)  (LWImageID, int x, int y,
					 BufferValue[3]);
		double          (*lumaSpot) (LWImageID, double x, double y,
					     double spotSize, int blend);
		void            (*RGBSpot)  (LWImageID, double x, double y,
					     double spotSize, int blend,
					     double[3]);
	    #ifndef LW_PRERELEASE
		void            (*clear) (LWImageID);
	    #endif
	} LWImageList;
	. . .


9.8    Compositing Information

The global ID "LW Compositing Info" returns a structure describing the
state of the built-in compositing function.  The three ImageID's are
the background image, the foreground image and the foreground alpha
image.

    (95)  Animation Globals
	. . .
	#ifndef LW_PRERELEASE
	typedef struct st_LWCompInfo {
		LWImageID        bg;
		LWImageID        fg;
		LWImageID        fgAlpha;
	} LWCompInfo;
	#endif
	. . .


9.9    Global Rendering Memory Pool

The global ID "Global Render Memory" returns functions for accessing
the Global Rendering Pool.  This is shared memory that can be used
while rendering.  This has two main uses: The first is for read-only
tables, like trig or random noise lookup tables which can be shared by
textures.  The second is for communication areas for textures that
wish to cooperate in terms of sharing computed values on a per-pixel
basis.  LightWave does nothing to manage this shared pool expect to
clear it out after rendering.

The memory chunks are pointers to blocks of memory of different sizes.
They are identified by arbitrary null-terminated character strings.

    (96)  Animation Types
	. . .
	typedef void *          MemChunk;

 first, next These functions allow traversal of the memory chunks in
	     the list (pool).  Clients can use these functions if they
	     need to search for more complex critera than just ID.

 ID, size    These return the ID string and size of a memory chunk
	     given a pointer to the memory.

 find        This returns a pointer to a memory chunk which matches
	     the given ID.  Multiple chunks may be created with the
	     same ID, so this returns the first one.

 create      This creates a memory chunk with the given size and ID
	     and returns a pointer to the memory.  For chunks to be
	     unique it is best to try to find the ID before calling
	     this function.

    (97)  Animation Globals
	. . .
	typedef struct st_GlobalPool {
		MemChunk        (*first) (void);
		MemChunk        (*next) (MemChunk);
		const char *    (*ID)   (MemChunk);
		int             (*size) (MemChunk);
		MemChunk        (*find)   (const char *ID);
		MemChunk        (*create) (const char *ID, int size);
	} GlobalPool;


10    Files

Three header files describe the whole set of LightWave servers and
globals.  `lwbase.h' is for the declarations common to both Layout and
Modeler, `lwmod.h' is for Modeler only and `lwran.h' is for Layout
only (Rendering and ANimation).

    (98)  Common LightWave Header

	/*
	 * LWSDK Header File
	 * Copyright 1995  NewTek, Inc.
	 */
	#ifndef LW_BASE_H
	#define LW_BASE_H

	#include <moni.h>
	#include <plug.h>

	<Common Server Classes>
	<Common Globals>

	#endif

    (99)  LightWave Modeler Plug-in Header

	/*
	 * LWSDK Header File
	 * Copyright 1995  NewTek, Inc.
	 */
	#ifndef LW_MOD_H
	#define LW_MOD_H

	#include <lwbase.h>

	<Modeling Base Types>
	<Modeling Types>
	<Modeling Servers>
	<Modeling Globals>

	#endif

    (100)  LightWave Rendering and Animation Plug-in Header

	/*
	 * LWSDK Header File
	 * Copyright 1995  NewTek, Inc.
	 */
	#ifndef LW_RAN_H
	#define LW_RAN_H

	#include <lwbase.h>

	<Animation Types>
	<Animation Servers>
	<Animation Globals>

	#endif
