Contents
Introduction To Picture Driver Development 1
Development Environment 1
Development Kit Files 1
Overview of Picture Driver Processing 1
Reading Image Files 1
Writing Image Files 2
Implementation Details 1
Basic Data Types 1
Setting up the REX Interface 1
Runtime Library Support 2
Automatic Initialization and Cleanup 2
Coding the Pdr (rexlib_header) Structure 2
Providing Output Options 4
Extending the Image_file Structure 5
Reading Single-frame Images 6
open_image_file() 6
close_image_file() 7
read_first_frame() 7
Reading Multi-frame Images 8
read_delta_next() 9
Reading RGB Images 9
rgb_seekstart() 10
rgb_readline() 11
Writing Single-frame Images 11
create_image_file() 11
spec_best_fit() 12
save_frames() 13
Writing Multi-frame Images 13
GFXLIB - Graphics Library Functions 14
pj_rcel_copy 14
pj_put_dot 14
pj_get_dot 15
pj_put_hseg 15
pj_get_hseg 15
pj_put_vseg 16
pj_get_vseg 16
pj_put_rectpix 16
pj_get_rectpix 17
pj_set_hline 17
pj_set_vline 17
pj_set_rect 18
pj_set_rast 18
pj_xor_rect 18
pj_mask1blit 18
pj_mask2blit 19
pj_blitrect 20
pj_tblitrect 20
pj_swaprect 21
pj_xor_rast 21
pj_zoomblit 21
pj_unbrun_rect 22
pj_unss2_rect 23
pj_unlccomp_rect 23
pj_set_colors 24
pj_wait_rast_vsync 24
pj_uncc256 25
pj_uncc64 25
SYSLIB - String, Memory, and Unbuffered I/O Functions 26
free 26
malloc 26
memcmp 26
memcpy 26
memset 26
strcmp 26
strcpy 26
strlen 26
zalloc 26
pj_open 26
pj_create 26
pj_close 27
pj_read 27
pj_write 27
pj_seek 27
pj_tell 28
pj_delete 28
pj_rename 28
pj_exists 28
pj_ioerr 28
pj_get_load_path 29
pj_get_path_name 29
pj_get_path_suffix 29
STDIOLIB - Standard C Stream I/O Functions 30
clearerr 30
fclose 30
feof 30
ferror 30
fflush 30
fgetc 30
fgets 30
fopen 30
fprintf 30
fputc 30
fputs 30
fread 30
fseek 30
ftell 30
fwrite 30
printf 30
rewind 30
sprintf 30
ungetc 30
pj_errno_errcode 30
Introduction To Picture Driver Development
Autodesk Animator Pro has built in support for several image file formats. Loadable picture driver (PDR) modules support other picture and animation file formats. This document describes the techniques used to develop a loadable picture driver module.
Development Environment
You can develop a picture driver with any tools which support the Watcom -3s function calling convention and the Phar Lap DOS extender. The kit is currently oriented primarily towards C (possibly with some assembler code) as the development language. Tools which may be used to develop a PDR module include (but are not necessarily limited to)
-Watcom C/386 (v8.0 or higher)
-MetaWare High C
Other languages and compilers may also be compatible.
A picture driver module is compiled into a Phar Lap REX module. Animator Pro dynamically loads the REX module at runtime, when needed.
Development Kit Files
The PDR development kit contains support libraries, a set of C-language header files, and source code for several example driver modules.
The following diagram shows the structure of the development kit, and provides a brief overview of the directories:
\PICDRIVE
├─ \INC- Header files.
├─ \LIB- Support libraries.
├─ \SKELETON- Skeleton code to clone from.
├─ \TARGA- Reads RGB image files.
├─ \RIF- Reads multiframe files.
└─ \FLILO - Writes multiframe files.
Within the makefiles and linker response files of the example source code, all path references are relative to the current directory; there are no hard-coded path references. The PICDRIVE directory and its children can be installed at any location in your directory structure, including at the root, or with PICDRIVE as the child of another directory.
Overview of Picture Driver Processing
A picture driver can support any combination of the following features:
-Read a single-frame or multi-frame image with a pixel depth of 1 thru 8 bits.
-Read a single-frame image with a pixel depth of greater than 8 bits (ie, an RGB or Truecolor image).
-Write more or more frames of a flic into a single output file. The output file can be any pixel depth supported by the picture driver.
-Provide a set of text strings which are used to build a menu of output options used to write an image file.
It is unlikely that a single picture driver module will implement all these features. Most popular file formats require only a subset of these actions to fully support the format.
A picture driver is loaded and used by a host program. Two host programs currently exist, ANIPRO and ANICONV. ANIPRO is Autodesk Animator Pro itself. ANICONV is an image conversion utility supplied with Animator Pro. There are several small differences in the way these programs use a picture driver module, as follows:
-When a file format supports a variety of output options, such as differing data compression types, the ANICONV host can conduct options dialogs with the user before calling the driver's file creation function.
-ANIPRO does not support the output options dialogs. When the ANIPRO host uses a picture driver to create a file, the driver must apply reasonable defaults if multiple options exist.
-The ANICONV host can process RGB input data directly, converting it to a 256-color image using algorithms built in to ANICONV.
-The ANIPRO host cannot process RGB input data, and will thus never call the RGB-oriented input functions the driver provides.
These differences require specific actions on the part of your driver (assuming reasonable defaults and informing the host when RGB data is present).
Reading Image Files
Picture drivers provide to the host a set of functions to read image files. The functions include open and
close file, read first frame, read next frame, and read RGB line.
For non-RGB images, the host will call the open function, and if it succeeds the read first function is called to load the image into a raster provided by the host. If the picture driver indicates that multiple frames exist in the input file, the host will call the read next function repeatedly, until all the images in the file have been loaded. After the file has been processed, the host calls the driver's close function.
Processing is slightly different for RGB images. If the open function indicated a pixel depth greater than 8 bits, the RGB-aware host will call the read rgb line function to obtain each line of input from the file. A host which cannot handle RGB data may attempt to call the normal read first function to process the image. In this case, the picture driver's read first routine must return Err_rgb_convert to signal that the data can't be converted by the picture driver. (Of course, it is possible to write a picture driver which can perform an internal conversion of RGB to mapped pixels. In this case, the read first function would perform the conversion, and the host would be unaware that the data was originally in RGB format.)
For a non-RGB image, the picture driver processes the entire image, and draws it to the raster using the GFX library functions described later in this document. For an RGB image, the picture driver returns the RGB data a line at a time into a buffer, and the host draws the data to the screen, after translating it to color mapped pixels.
Writing Image Files
Picture drivers provide to the host a set of functions to write images files. These include create file, close file, and save frames. The driver can also provide a set of strings used to prompt the user for output options.
To create an image file, the host calls the create file function (after processing any options dialogs specified by the driver). If the file creation suceeds, the host then calls the save frames function, passing a frame count, a pointer to a raster containing the image, and a pointer to a function to load the next frame into that raster when there are multiple output frames to save.
The picture driver's save frames function obtains the pixels from the raster using functions from the GFX host library described later in this document. It performs any data compression or formatting required by the output file format, and saves the data into the file using normal C I/O functions from the STDIOLIB host library.
Implementation Details
To create a PDR module, you need to code several data structures which establish the interface between the host and your module. You also need to code several functions which the host will call to process image files. This chapter provides details on coding these items.
The SKELETON directory contains a do-nothing PDR module which you can copy and modify as needed to create a new PDR.
Basic Data Types
The STDTYPES.H file defines several standard macros and data types which are used in PDR development. The macros are common C items, and have #ifdef/#endif protective wrappers around them; they are defined only if you haven't already defined them. The items defined in STDTYPES.H and the assumptions made concerning integral C data types are listed below.
Data Type/MacroDescription
charAssumed to be signed or unsigned 8-bit
shortAssumed to be signed 16-bit
intAssumed to be signed 32-bit
longAssumed to be signed 32-bit
BYTE Typedef, signed char
UBYTE Typedef, unsigned char
SHORT Typedef, signed short
USHORT Typedef, unsigned short
LONG Typedef, signed long
ULONG Typedef, unsigned long
PixelTypedef, unsigned char
UcoorTypedef, unsigned long
CoorTypedef, long
BooleanTypedef, int
ErrcodeTypedef, int
NULL Macro, defined as ((void *)0)
TRUE Macro, defined as 1
FALSE Macro, defined as 0
SuccessMacro, defined as 0
Setting up the REX Interface
The REX interface is a subsystem within Animator that loads and unloads PDR modules, and supplies the runtime service libraries (standard I/O, Poco builtin functions, etc). It is also calls the optional initialization and cleanup routines as it loads and unloads the PDR module.
A data structure named rexlib_header provides the primary interface between the REX subsystem and your PDR module. Data in this structure informs the host of which support services you need (standard I/O library, etc), and also provides the host with the pointers to your implementation routines.
Runtime Library Support
PDR modules cannot be linked with a standard C runtime library, because runtime libraries are generally not compatible with the Phar Lap REX module format. The host provides several libraries of functions that fill the basic needs provided by a runtime library.
Each of these host libraries has an associated C header file which you must #include in the PDR source code when you use the library's functions. Some of the libraries also have an associated LIB file, required at link time. Each library has a formal name which helps keep the REX interface layer "behind the scenes" and simplifies setting up PDR modules. The following table describes the host libraries available and the associated support files:
NameHeaderLink LIBFunctionality
AA_SYSLIBSYSLIB.HAASYSLIB.LIBMemory and string utils.
AA_STDIOLIBSTDIOLIB.HSTDIOLIB.LIBStandard C I/O.
AA_GFXLIBGFX.HGFXLIB.LIBGraphics.
Automatic Initialization and Cleanup
A PDR module may contain initialization and cleanup routines which are automatically executed by the host when the module is loaded and unloaded. The init routine will be executed immediately after the PDR module is loaded, before the any PDR functions are called by the host. The cleanup routine is executed just before the PDR module is unloaded.
The init and cleanup routines may use host-provided library functions from any of the libraries listed above.
Coding the Pdr (rexlib_header) Structure
The Pdr structure makes the primary connection between your PDR code and the host. The Pdr structure must be declared and pre-initialized as a global data item in
your driver, and it must be named rexlib_header. The Pdr structure is defined in PICDRIVE.H, as follows:
typedef struct pdr {
Rexlib hdr;
char *title_info;
char *long_info;
char default_suffi[16];
ULONG max_write_frames;
ULONG max_read_frames;
Boolean (*spec_best_fit)();
Errcode (*create_image_file)()
Errcode (*open_image_file)()
void (*close_image_file)()
Errcode (*read_first_frame)()
Errcode (*read_delta_next)()
Errcode (*save_frames)()
Pdroptions *poptions;
Errcode (*rgb_seekstart)()
Errcode (*rgb_readline)()
long reserved[4];
} Pdr;
The hdr field contains information for the REX loader within the host program. You initialize this field with pointers to your auto-init and auto-cleanup functions, and some standard values, as follows:
{REX_PICDRIVER,PDR_VERSION,init,cleanup,HLIB_LIST}
If you don't have an init or cleanup function, code the constant NOFUNC for thoses entries.
The title_info field is a pointer to a 1-line description of your driver which is displayed on the host's driver selection menu. Only the first 34 characters of the string are displayed.
The long_info field contains a full description of your driver. There is no limit on the length of the text. The text is word-wrapped as needed by the host; a newline character will force a displayed newline.
The default_suffi field holds file suffi which are displayed in the file selector dialog buttons. If more than one suffix is given, they should be separated with semicolons (".PI1;.PI2;.PI3"). A maximum of 3 suffi may be given.
The max_write_frames field indicates the maximum number of frames that can be written to a single file in your format. A value of 1 indicates a still-image file format. A value of 0 indicates that your driver reads files but does not write them.
The max_read_frames field indicates the maximum number of frames that can be read from a single file in your format. A value of 1 indicates a still-image file format. A value of 0 indicates that your driver writes files but does not read them.
The poptions field is a pointer to a Pdroptions structure which describes the output options your
driver supports. This field is optional, and must be set to NULL if your driver doesn't support output options. The Pdroptions structure is discussed in detail below.
The reserved field is reserved for future expansion. You must initialize this field to zeros. (In C, this can be done by failing to provide any initialization values in the declaration, as usual.)
The remaining fields are pointers to the functions that provide the read/write functionality for your file format. These are discussed in detail below. For any function you don't implement in your driver, supply a value of NOFUNC in the Pdr structure.
Providing Output Options
Some image file formats provide several ways to store the picture data within the file. The host program can conduct dialogs for you, to ask the user for selections among the various options.
Up to four separate categories of options may be specified. Within each category, there may be as many as eight selections to choose from. The host conducts one dialog for each category. The dialog presents the selections to the user; the user can select any one of the items in each category.
Not all hosts support the options interface to a picture driver. Your driver must assume reasonable defaults for the options, so that it will work correctly with any host. Currently, Animator Pro itself does not conduct options dialogs, but the image conversion utility delivered with Animator Pro does. It is also possible to write a Poco program that runs from within Animator and accesses a PDR directly. That Poco program may conduct the options dialogs (this requires PDRACCES.POE from the Animator Pro Bonus Pack).
The Pdroptions structure is used to pass text strings describing the options to the host program, and to return the requested options to your driver. It is defined in PICDRIVE.H as follows:
typedef struct pdr_options {
char *choicelst1;
char *choicelst2;
char *choicelst3;
char *choicelst4;
UBYTE options_valid;
UBYTE option1;
UBYTE option2;
UBYTE option3;
UBYTE option4;
} Pdroptions;
The choicelst fields are pointers to string that contain the items for the options dialogs. Within
each string are a series of items delimited by newline characters. The first substring is the title placed in the dialog box. The remaining substrings are the option choices. The last substring should always be Cancel. If the user picks the last option (regardless of the actual string text) the host aborts the Save Picture or Save Flic operation in progress without ever calling the PDR create file function.
The options_valid field indicates to the driver whether the host conducted options dialogs or not. If zero, no dialogs were conducted, and the driver must use its default options. If non-zero, the values in the option fields are valid.
The option fields contain the numeric index of the option selections made by the user. This value ranges from zero to the number of selections you provided minus 1.
In some of the example programs, the title string for each option category is defined using the RL_KEYTEXT() macro. We use this macro to make connections to Animator Pro's menu (AA.MU) file. You should not use this macro when setting up options strings in your driver, because the AA.MU file will not contain entries for your driver, and runtime errors will result.
The SKELETON example program contains an example of setting up options data in a picture driver.
Extending the Image_file Structure
Your driver open or create functions return to the host a pointer to an Image_file structure. The host passes this pointer back to your driver's read and write functions. You can extend this structure, or embed it within a larger structure of your own, so that in effect the host passes your I/O functions a pointer to your major control data structure. Some of the example drivers use this technique. If you embed the Image_file structure within your own larger structure, the Image_file structure must appear first.
The Image_file structure is defined in PICDRIVE.H, as follows:
typedef struct image_file {
struct pdr *pd;
UBYTE write_mode;
UBYTE needs_work_cel;
} Image_file;
The pd field is a pointer to your Pdr structure, defined in your code as rexlib_header. This is set by the host; do not change it.
The write_mode field is set to zero when the file is opened for reading, or non-zero if the file is opened
for writing. (IE, it indicates whether the file was opened via a call to your open_ifile or create_ifile. This is set by the host; do not change it.
The needs_work_cel field indicates whether your driver needs a work raster in addition to the main raster to create an image file. This field is set by your driver. When your create_ifile function sets this field to non-zero, the host allocates a work raster for you, and passes the raster pointer to your output function. This is used primarily by animation file formats which generate image data based on the deltas between the prior and current frames. The work raster can be used to hold a copy of the prior frame.
Reading Single-frame Images
The picture driver provides three major functions to the host for reading non-RGB single-frame images:
-open_image_file()
-close_image_file()
-read_first_frame()
The following sections contain details on coding each of these functions.
open_image_file()
Prototype:
Errcode open_image_file(Pdr *pd, char *path,
Image_file **pif, Anim_info *ainfo);
The open_image_file() function serves both as a 'detect' function, and as a prelude to actually loading an image file. When the user requests a Load Picture operation, the host will first try the PDR module selected by the user. If the open_image_file() function in that PDR responds with Success, the host uses that PDR to process the image.
When the pre-selected PDR's open_image_file() function returns an error status, the host then tries every PDR available, calling the open_image_file() function in each. The first PDR which responds with Success, is used to load the image.
Because of the logic used by the host to find an available PDR to cope with any given file, your PDR's open_image_file() function must return Success only if it recognizes the data in the file and is capable of processing it. Do not rely solely on the filename or filetype, open the file and read enough of it to verify that it contains data in the format you expected. Never code a PDR module which always returns Success from the open_image_file() function!
Doing so effectively disables other picture drivers in the system.
The open_image_file() should do only the work needed to determine that it can handle a given file. Keeping this to a minimum helps overall performance of the host program, since the host tries every PDR until one is found that can handle a given file. In general, attempt to reject a file as quickly as possible when it's not a format your driver understands.
Because the host uses open_image_file() both as a detector function and as a prelude to actually reading the file, the sequence of calls to load a picture is:
-Load PDR, call its init() if there is one.
-Call open_image_file(), which returns Success.
-Call close_image_file().
-Call open_image_file() again.
-Call read_first_frame().
-Call close_image_file().
-Call PDR's cleanup() if there is one, then unload the module.
In other words, any number of open/close or open/read/close sequences may occur while the PDR is loaded. The host will never open more than one file at a time using the same instance of a PDR. (IE, the PDR must be serially reusable, but need not be reentrant.)
close_image_file()
Prototype:
Errcode close_image_file(Image_file **pif);
The host calls close_image_file() when it's done processing the file. Any resources (file handles, memory, etc) aquired at open_image_file() time should be freed during the close_image_file() processing.
The host calls this function for image files opened with either open_image_file() or create_image_file(). You can use the write_mode flag in the Image_file structure to determine how the file was opened, if necessary.
read_first_frame()
Prototype:
Errcode read_first_frame(Image_file *ifile,
Rcel *screen);
The read_first_frame() function is used to load the image into the raster provided by the host. This host
calls this function only after open_image_file() has returned Success.
The processing steps generally taken by a driver's read_first_frame() function are:
-Clear the raster using pj_set_rast().
-If the file format includes color palette information, process it into Cmap format (as defined in CMAP.H), and use pj_cmap_load() to load the colors into the raster's color map.
-Read the pixels from the file, decompressing or otherwise processing as necessary to get them into a byte-per-pixel format. Write the pixels into the raster.
-Return to the host caller after the entire image has been loaded.
If necessary, the color palette can be loaded after the pixel data, if required by the data format in the file.
Any of the GFX library output routines can be used to render the pixels on the destination raster. We recommend that you avoid using pj_put_dot() for performance reasons. The most useful GFX functions will be probably be pj_pug_hseg() to write a line at a time to the raster, or pj_put_rectpix() to write several lines at a time. Other functions, such as pj_mask1blit(), might also be useful if you are loading a 1-bit-per-pixel image, for example.
The host handles all issues involving clipping and/or centering the image when it doesn't match the physical screen dimensions. You can just assume that the raster you are drawing to is the exact same size as the image width and height values your open_image_file() function loaded into the host's Anim_info structure. (Indeed, it is mandatory that you make this assumption for the convert utilty's scaling operations to function correctly.)
Reading Multi-frame Images
A driver that supports multiple-frame image file formats (ie, animation files) indicates this fact to the host by setting the max_read_frames field of the Pdr structure to a value greater than 1. In this case, the driver provides an additional input function, read_delta_next(), described below.
When your driver supports multi-frame input, and your open_image_file() sets the num_frames field in the host's Anim_info structure to a value greater than 1, the host makes the following sequence of calls to load the frames:
-Load PDR, call its init() if there is one.
-Call open_image_file(), which returns Success.
-Call close_image_file().
-Call open_image_file() again.
-Call read_first_frame().
-Call read_delta_next() repeatedly to get the rest of the frames.
-Call close_image_file().
-Call PDR's cleanup() if there is one, then unload the module.
The host calls read_delta_next() repeatedly until num_frames have been loaded.
read_delta_next()
Prototype:
Errcode read_delta_next(Image_file *ifile,
Rcel *screen);
This function will only be called after the file has been opened, and the first frame has been loaded using read_first_frame(). Upon entry, the raster provided by the host holds a copy of the prior frame. Your read_delta_next() routine manipulates this image in whatever way is necessary to generate the next frame. (This may involve applying deltas to the image already in the raster based on the next chunk of data in an animation file, or it may involve simply clearing the raster and loading the next image from the input file.) The manipulation may include changes to the pixels and/or color palette.
Reading RGB Images
RGB images (as opposed to color-mapped images) are handled differently in the host <-> driver interface. Some host programs include logic to directly read RGB pixels and convert the image into a color-mapped representation. Other host programs do not contain the conversion code. There is no way for the driver to determine whether the host can handle RGB input. Only single-frame images are handled by the RGB interface to a PDR.
When the driver's open_image_file() function detects a file containing RGB data, it must set the pdepth field of the host's Anim_info structure to a value greater than 8.
A host that can handle RGB input will use the driver's rgb_seekstart() and rgb_readline() routines to process the data, instead of calling read_first_frame(). A host which cannot handle direct RGB input will call the driver's read_first_frame() function. This allows the option of writing a driver that has its own RGB to color mapped conversion code. If your driver doesn't contain such conversion logic, your read_first_frame() routine should return Err_rgb_convert to indicate that it can't perform the conversion internally. The user will then be prompted to use the Animator Pro image conversion utility to process the picture.
When the host cannot handle RGB input directly, it makes the following sequence of calls:
-Load PDR, call its init() if there is one.
-Call open_image_file(), which sets pdepth to a value greater than 8 and returns Success.
-Call close_image_file().
-Call open_image_file() again. (It agains sets pdepth greater than 8.)
-Call read_first_frame(). This either performs the RGB conversion internally and leaves the resulting image in the host-provided raster, or it simply returns Err_rgb_convert to indicate it can't handle the image internally.
-Call close_image_file().
-Call PDR's cleanup() if there is one, then unload the module.
When the host can handle RGB input directly, it makes the following sequence of calls:
-Load PDR, call its init() if there is one.
-Call open_image_file(), which sets pdepth to a value greater than 8 and returns Success.
-Call close_image_file().
-Call open_image_file() again. (It agains sets pdepth greater than 8.)
-Call rgb_seekstart().
-Call rgb_readline() once for each line in the file. The line count is determined by the value set into height by open_image_file().
-Call rgb_seekstart() again.
-Call rgb_readlines() repeatedly again, to read all the lines a second time.
-Call close_image_file().
-Call PDR's cleanup() if there is one, then unload the module.
The RGB-aware host makes two passes through the data in the file. The first pass builds a color map, and the second pass fits the pixels to the map and renders them to the raster. There is no need for the driver to render directly to the raster with an RGB-aware host.
rgb_seekstart()
Prototype:
Errcode rgb_seekstart(Image_file *ifile);
The rgb_seekstart() function is a signal from the host to the driver that the next call to rgb_readline() should return the first line of pixels from the data stream. This may involve seeking to the start of the data in the image file, setting internal flags the rgb_readline() routine uses, or other internal actions as needed by the driver.
The return value from this function informs the host of how the image is stored in the file. A value of zero (Success) indicates that the image is rightside
-up; the first line returned by rgb_readline() is displayed at the top of the screen. A return value greater than zero indicates the image is upside-down; the first line returned by rgb_readline() is displayed at the bottom of the screen. A negative return value indicates an error, as usual.
rgb_readline()
Prototype:
Errcode rgb_readline(Image_file *ifile,
Rgb3 *linebuf);
This function returns the next line of RGB pixels in the buffer provided by the caller. The pixels are stored into the buffer in Rgb3 format. The Rgb3 structure (defined in CMAP.H) provides a full byte for each of the red, green, and blue components. The buffer will contain 3*width bytes, based on the width set into the host's Anim_info structure by the open_image_file() routine.
The host expects each of the RGB components to be 8 bits. Your driver must scale smaller bit depths up to 8-bit levels when the source data's pixel depth is less than 8 bits per red, green, or blue component.
Writing Single-frame Images
The picture driver provides four major functions for writing single-frame images:
-create_image_file()
-close_image_file()
-spec_best_fit()
-save_frames()
The following sections contain details on coding each of these functions.
In general, the host will make the following sequence of calls to write one or more image frames to a file:
-Load PDR, call its init() if there is one.
-Call spec_best_fit().
-Call create_image_file(), which returns Success.
-Call save_frames().
-Call close_image_file().
-Call PDR's cleanup() if there is one, then unload the module.
create_image_file()
Prototype:
Errcode create_image_file(struct pdr *pd,
char *path,
Image_file **pif,
Anim_info *spec );
The host calls create_image_file() to begin output of an image (or series of images). The driver allocates any needed resources, creates the physical file, and stores the values from the host's Anim_info structure into local storage for later use in the save_frames() function.
If the output file already exists, the driver must arbitrarily recreate it anew. The user has already been prompted, and has confirmed the intention to overwrite the existing file.
If your driver needs a work raster, the create_image_file() function should set the needs_work_raster field of the Image_file structure to TRUE. The host will then allocate a work raster and provide a pointer to it when it calls save_frames().
spec_best_fit()
Prototype:
Boolean spec_best_fit(Anim_info *spec);
The host calls spec_best_fit() before calling the create_image_file() function. The host uses spec_best_fit() to determine whether the image can be stored exactly as the user requested, in terms of:
-width
-height
-pixel depth
-frame count
-aspect ratio
The values are stored in the Anim_info structure passed from the host to the spec_best_fit() function. The driver should examine the values in these fields, and if it can comply with the request, return TRUE.
If the driver cannot comply with the request exactly, it should modify the offending field to the value representing the closest thing the driver can do, and return FALSE to indicate that the fit is not exact. An example of this would be when the host wants to save a 200x100 image, but the driver's format is limited to 320x200. In this case, the driver would load 320x200 into the width and height fields in the Anim_info and return FALSE.
When spec_best_fit() returns FALSE, the host builds a virtual raster that matches the new values in the Anim_info. The virtual raster will properly clip an oversized image, or read zeroes around the edges of an undersized image, so that your save_frames() routine need not deal with clipping and offsets when reading from the input raster. The new values are also passed
to your create_image_file() function (IE, if you indicated you can only do 320x200, then those values will be passed create_image_file()).
save_frames()
Prototype:
typedef Errcode (*Sfunc_t)(int ix,void *sdata);
Errcode save_frames(Image_file *ifile,
Rcel *screen,
int num_frames,
Sfunc_T *seek_func,
void *seek_data,
Rcel *work_screen );
The host calls save_frames() after a successfull call to create_image_file(). Your save_frames() routine writes one or more frames to the output file, based on the frame_count paramter passed to it by the host. The frame count will only be greater than one only if the driver's Pdr structure indicates it can handle multiple frames.
The driver reads color map information and pixels from the raster provided by the host, and writes the information to a file. The functions in the GFX library are used to read pixels from the host's raster. The color map is accessed directly via the
Cmap pointer in the raster.
Writing Multi-frame Images
Writing multiple frames is very similar to writing a single frame. The primary difference is that the host passes to the save_frames() routine a pointer to a seek function, and a seek data parameter. After writing each frame to the file, the driver calls the host's seek function, passing the seek data and the index of the frame to seek to. (The index is zero-based.) Each call to the host's seek causes the next image to be placed into the host's raster. Your save_frames() routine loops through the frames until the number of frames indicated by the frame_count parameter have been written.
If your create_image_file() routine set the needs_work_raster field to TRUE, the host also provides a work raster in the paramters to save_frames(). When your output format is delta-based, we recommend that you copy the current frame image into the work raster, then seek to the next frame, and base your deltas on the difference between the work and current rasters. Avoid excessive calls to the host's seek function for best performance.
A call to the host's seek function that specifies the index of the current frame will not change the contents of the current raster. But, it does pass
through the host's abort-check logic, and can be used as a way of occasionally polling for a user-requested abort.
GFXLIB - Graphics Library Functions
The graphics functions operate on the pixel data stored in a raster. They work on any type of raster (e.g., RAM rasters, video hardware rasters). They support simple drawing (dots, lines, segments) and complex blits (keyed blits, masked blits, zoom blits, etc). They do not support complex drawing operations such as circles and polygons.
These functions are the documented interface to the I/O library attached to a raster. Do not call raster I/O functions directly through the raster's lib pointer. The graphics functions documented below contain logic to resolve differences in raster types (eg, blit from hardware to RAM); the direct entry points will fail without the pre-conditioning of parms done by the documented functions.
All of the functions listed below perform clipping when the operation would exceed the boundaries of the destination raster. For each pj_whatever() function listed below, there is also a pj__whatever() function (two underbars after the pj) which is an unclipped version. If you call an unclipped raster output function with coordinates that cause data to be placed off the raster, you generally get a page fault or other fatal error which crashes Animator and causes the loss of the end user's work-in-progress.
Errcode pj_rcel_copy(FlicRaster *psource, FlicRaster *pdest)
Function:Copies all pixel and color map data from the source raster into the destination raster. The source and destination rasters may be of any type (including differing types), but they must be exactly the same size (width, height and depth).
Input:psourceThe source raster handle.
pdestThe destination raster handle.
Return Value:Success, or a standard error code as defined in PJECODES.H
void pj_put_dot(FlicRaster *r, Pixel color, Coor x, Coor y);
Function:Sets a single pixel to the specified color.
Input:rRaster pointer.
colorColor of the pixel.
xX position.
yY position.
Return Value:None.
Pixel pj_get_dot(FlicRaster *r, Coor x, Coor y);
Function:Returns the color of a single pixel.
Input:rRaster pointer.
xX position.
yY position.
Return Value:Color of the pixel, or zero if clipped.
void pj_put_hseg(FlicRaster *r, void *pixbuf, Coor x, Coor y, Ucoor w);
Function:Copies pixels from pixbuf to a horizontal line segment in the raster.
Input:rRaster pointer.
pixbufMemory buffer containing pixels.
xX coordinate of left end of segment.
yY coordinate of segment.
wWidth of segment.
Return Value:None.
void pj_get_hseg(FlicRaster *r, void *pixbuf, Ucoor x, Ucoor y, Ucoor w);
Function:Copies pixels from a horizontal line segment in the raster to pixbuf.
Input:rRaster pointer.
pixbufMemory buffer to receive pixels.
xX coordinate of left end of segment.
yY coordinate of segment.
wWidth of segment.
Return Value:None.
void pj_put_vseg(FlicRaster *r, void *pixbuf, Ucoor x, Ucoor y, Ucoor h);
Function:Copies pixels from pixbuf to a vertical line segment in the raster.
Input:rRaster pointer.
pixbufMemory buffer containing the pixels.
xX coordinate of segment.
yY coordinate of top of segment.
hHeight of segment.
Return Value:None.
void pj_get_vseg(FlicRaster *r, void *pixbuf, Ucoor x, Ucoor y, Ucoor h);
Function:Copies pixels from a vertical segment in the raster to pixbuf.
Input:rRaster pointer.
pixbufMemory buffer to receive the pixels.
xX coordinate of segment.
yY coordinate of top of segment.
hHeight of segment.
Return Value:None.
void pj_put_rectpix(FlicRaster *r, void *pixbuf, Coor x, Coor y, Ucoor w, Ucoor h);
Function:Copies pixels from a memory buffer to a rectangle in the raster. The memory buffer is a two-dimensional array of pixels with the top horizontal line of pixels first and the bottom horizontal line of pixels last (ie, Pixel pixbuf[h][w]).
Input:rRaster pointer.
pixbufMemory buffer containing the pixels.
xLeft edge of rectangle.
yTop edge of rectangle.
wWidth of rectangle.
hHeight of rectangle.
Return Value:None.
void pj_get_rectpix(FlicRaster *r, void *pixbuf, Coor x, Coor y, Ucoor w, Ucoor h);
Function:Copies pixels from a rectangle in the raster to a memory buffer. The memory buffer is organized as two-dimensional array with the same format used by pj_put_rectpix().
Input:rRaster pointer.
pixbufMemory buffer to receive the pixels.
xLeft edge of rectangle.
yTop edge of rectangle.
wWidth of rectangle.
hHeight of rectangle.
Return Value:None.
void pj_set_hline(FlicRaster *r, Pixel color, Coor x, Coor y, Ucoor w);
Function:Draws a solid horizontal line segment.
Input:rRaster pointer.
colorColor of segment.
xLeft end of segment.
yY coordinate of segment.
wWidth of segment.
Return Value:None.
void pj_set_vline(FlicRaster *r, Pixel color, Coor x, Coor y, Ucoor h);
Function:Draws a solid vertical line segment.
Input:rRaster pointer.
colorColor of segment.
xX coordinate of segment.
yTop end of segment.
hHeight of segment.
Return Value:None.
void pj_set_rect(FlicRaster *r, Pixel color, Coor x, Coor y, Ucoor w, Ucoor h);
Function:Draws a solid color rectangle.
Input:rRaster pointer.
colorColor of rectangle.
xLeft edge.
yTop edge.
wWidth.
hHeight.
Return Value:None.
void pj_set_rast(FlicRaster *r, Pixel color);
Function:Sets an entire raster to a solid color.
Input:rRaster pointer.
colorColor.
Return Value:None.
void pj_xor_rect(FlicRaster *r, Pixel color, Coor x, Coor y, Ucoor w, Ucoor h);
Function:Exclusive-ORs a rectangle in a raster with a solid color.
Input:rRaster pointer.
colorColor to XOR rectangle with.
xLeft edge.
yTop edge.
wWidth.
hHeight.
Return Value:None.
void pj_mask1blit(UBYTE *mbytes, Coor mbpr, Coor mx, Coor my, FlicRaster *r, Coor rx, Coor ry, Ucoor width, Ucoor height, Pixel oncolor );
Function:Expands a rectangle from a bitmap in memory to a full-pixel image in the raster. Zeros in the bitmap are left unchanged in the raster and ones in the bitmap are changed to oncolor (ie, a transparent blit).
Input:mbytesPointer to a block of memory arranged as a two-dimensional
bitmap. In the bitmap, bits are packed into bytes with the leftmost bits stored in the uppermost bits of each byte.
mbprThe number of bytes per line within the bitmap.
mx,myThe coordinates of the upper-left corner of the area to expand from within the bitmap.
rDestination raster pointer.
rx,ryThe coordinates of the upper-left corner of the destination rectangle to expand into within the raster.
widthWidth of rectangle to expand, in pixels.
heightHeight of rectangle to expand, in pixels.
oncolorOnes in the source bitmap get mapped to this color in the destination raster.
Return Value:void
void pj_mask2blit(UBYTE *bitplane, Coor mbpr, Coor mx, Coor my, FlicRaster *r, Coor rx, Coor ry, coor width, Ucoor height, Pixel oncolor, Pixel offcolor);
Function:Expands a rectangle from a memory bitmap to a raster. Zeros in the bitmap are mapped to offcolor in the raster and ones are mapped to oncolor. This function is similar to pj_mask1blit(), except that it is an opaque rather than transparent blit.
Input:mbytesPointer to a block of memory arranged as a two-dimensional bitmap.
mbprThe number of bytes per line within the bitmap.
mx,myThe coordinates of the upper-left corner of the area to expand in the bitmap.
rDestination raster pointer.
rx,ryThe coordinates of the upper-left corner of the destination rectangle to be expanded in the raster.
widthWidth of rectangle to expand.
heightHeight of rectangle to expand.
oncolorOnes in the source bitmap are mapped to this color in the destination raster.
offcolorZeros in the source bitmap are mapped to this color in the destination raster.
Return Value:None.
void pj_blitrect(FlicRaster *source, Coor src_x, Coor src_y,
FlicRaster *dest, Coor dest_x, Coor dest_y, Coor width, Coor height)
Function:Copies all pixels from one rectangular area to another. The source and dest rasters may be the same raster; the case of overlapping source and dest rectangles is handled properly. The source and dest rasters may be different types and sizes of raster.
Input:sourceSource raster.
src_xLeft edge of rectangle in source.
src_yTop edge in source.
destDestination raster.
dest_xLeft edge of rectangle in destination.
dest_yTop edge in destination.
widthWidth of rectangle to copy.
heightHeight of rectangle to copy.
Return Value:None.
void pj_tblitrect(FlicRaster *s, Coor sx, Coor sy, FlicRaster *d, Coor dx, Coor dy, Coor width, Coor height, Pixel tcolor)
Function:Transparently copies pixels from one rectangular area to another. Pixels in the source that are the same color as tcolor are not copied; the corresponding pixel in the destination raster is unchanged.
The source and dest rasters may be the same raster; the case of overlapping source and dest rectangles is handled properly. The source and dest rasters may be different types and sizes of raster.
Input:sourceSource raster.
src_xLeft edge of rectangle in source.
src_yTop edge in source.
destDestination raster.
dest_xLeft edge of rectangle in destination.
dest_yTop edge in destination.
widthWidth of rectangle to copy.
heightHeight of rectangle to copy.
tcolorTransparent color of source.
Return Value:None.
void pj_swaprect(FlicRaster *ra, Coor ax, Coor ay, FlicRaster *rb, Coor bx, Coor by, Coor width, Coor height)
Function:Exchanges all pixels in a pair of rectangular areas. The source and dest rasters may be the same raster; the case of overlapping source and dest rectangles is handled properly. The source and dest rasters may be different types and sizes of raster.
Input:raSource raster.
axLeft edge of rectangle in raster ra.
ayTop edge of rectangle in raster ra.
rbDestination hardware raster.
bxLeft edge of rectangle in raster rb.
byTop edge of rectangle in raster rb.
widthWidth of rectangle to swap.
heightHeight of rectangle to swap.
Return Value:None.
void pj_xor_rast(FlicRaster *s, FlicRaster *d);
Function:Exclusive-ORs all pixels in raster s against the pixels in raster d, putting the result into d.
The source and destination may not be the same raster. The two rasters must be the same dimensions, but may be of differing types.
Input:sSource raster.
dDestination raster.
Return Value:None.
void pj_zoomblit(FlicRaster *source, Coor src_x, Coor src_y, FlicRaster *dest, Coor dest_x, Coor dest_y, Ucoor width, Ucoor height, LONG zoom_x, LONG zoom_y )
Function:Copies a rectangular area of the source raster to the destination raster, expanding each pixel into a box that is zoom_x by zoom_y in size.
The width and height values are expressed in destination coordinates. It is possible that width
will not be an exact multiple of zoom_x and likewise height not an integral multiple of zoom_y. In this case the expanded pixels on the right and bottom edges are clipped.
The source and dest rasters may be the same raster; the case of overlapping source and dest rectangles is handled properly. The source and dest rasters may be different types and sizes of raster.
Input:sourceSource raster.
src_xLeft edge of source.
src_yUpper edge of source.
destDestination raster.
dest_xLeft edge of destination.
dest_yUpper edge of destination.
widthWidth of destination...
Width of source is:
(width+zoom_x-1)/zoom_x
heightHeight of destination.
Height of source is:
(width+zoom_y-1)/zoom_y
zoom_xAmount to stretch each pixel in horizonal direction.
zoom_y Amount to stretch each pixel in vertical direction.
Return Value:None.
void pj_unbrun_rect(FlicRaster *r, void *ucbuf, long pixsize,
Coor x, Coor y, Ucoor width, Ucoor height);
Function:Un-run-length-compresses from memory onto the raster. The width and height values must always exactly match the width and height of the output raster. Also, they must be the width and height of the original source data when it was compressed.
This routine does not perform width or height clipping. It will fail if the width and height rules listed above are not followed.
Input:rRaster pointer.
ucbufCompressed image data.
pixsizeSize in bytes of a single pixel. Always 1 in this version of the software.
xLeft edge of decompression destination.
yTop edge.
widthWidth of decompression destination.
heightHeight of destination.
Return Value:None.
void pj_unss2_rect(FlicRaster *r, void *ucbuf, long pixsize, Coor xstart, Coor ystart, Ucoor width, Ucoor height);
Function:Un-delta-compresses from memory onto the raster. This is the main decompression routine for Animator Pro FLC-format files; all frames (other than the first frame) are compressed in this format, if compressed at all.
The width and height values must always exactly match the width and height of the output raster. Also, they must be the width and height of the original source data when it was compressed.
This routine does not perform width or height clipping. It will fail if the width and height rules listed above are not followed.
Input:rRaster pointer.
ucbufCompressed delta image.
pixsizeSize in bytes of a pixel. Always 1 for now.
xstartLeft edge of each line of the decompression destination.
ystartTop edge.
widthWidth of decompression destination.
heightHeight of destination.
void pj_unlccomp_rect(FlicRaster *r, void *ucbuf, long pixsize, Coor x, Coor y, Ucoor width, Ucoor height);
Function:Un-delta-compresses from memory onto the raster. This is the main decompression routine for Animator 1.0 FLI-format files; all frames (other than the first frame) are compressed in this format, if compressed at all.
This routine does not perform width or height clipping. It will fail if the width and height rules listed above are not followed.
Input:rRaster pointer.
ucbufCompressed delta image.
pixsizeSize in bytes of a pixel. Always 1 for now.
xLeft edge of area to decompress into.
yTop edge.
widthWidth of area to decompress into.
heightHeight.
Return Value:None.
void pj_set_colors(FlicRaster *r, long start, long count, void *rgb_buf);
Function:Sets a portion of the hardware color map to the rgb values contained in cbuf. This function does nothing if r is not a video hardware raster.
This function does not update the RAM-based color map attached to the raster; it updates video hardware color registers only. We recommend that you alter colors by first changing the RAM-based color map, then calling pj_cmap_update() rather that using this function to alter the hardware directly.
Input:rRaster pointer.
startStart index in color map between 0 and 255.
countNumber of colors to set between 0 and 256.
rgb_bufPointer to rgb data. For each color to be changed there are 3 bytes - one each for red, green and blue. The values of these color components range from 0 to 255.
Return Value:None.
void pj_wait_rast_vsync(FlicRaster *r);
Function:Waits until the monitor is in vertical blank. This function returns immediately when r is not a video hardware raster.
Input:rRaster pointer.
Return Value:None.
void pj_uncc256(FlicRaster *r, void *ucbuf);
Function:Decompresses a delta color map. This function does nothing if r is not a video hardware raster. This updates the hardware palette registers only, it does not update the RAM-based color map attached to the raster.
Input:rRaster pointer.
ucbufCompressed color data.
Return Value:None.
void pj_uncc64(FlicRaster *r, void *ucbuf);
Function:Old-style routine to decompress a delta color map.
Same as ucbuf in uncc256, but the rgb data ranges from 0-63 (like the VGA color palette) rather than 0-256.)
Input:rRaster pointer.
ucbufCompressed color data.
Return Value:None.
SYSLIB - String, Memory, and Unbuffered I/O Functions
The SYSLIB.H and SYSLIB.LIB files contain the string, memory, and I/O functions listed below. When you request the AA_SYSLIB host library, these functions will be available.
Standard functions supported by AA_SYSLIB:
Please refer to your compiler's runtime library documentation for details on these functions.
free malloc memcmp memcpy
memset strcmp strcpy strlen
zalloc
The zalloc() function is identical to malloc() except that it initializes the memory block to zeroes.
Additional functions:
AA_SYSLIB supports the following additional functions, not found in standard C runtime libraries. These functions provide unbuffered I/O similar (but not identical) to the functions found in a standard runtime library. To use these functions, #include the JFILE.H header file.
Jfile pj_open(char *filename, int mode)
Function:Opens a file for unbuffered reading and/or writing.
Input:filenameName of file to open.
modeFile access mode, one of:
0 (DREADONLY)
1 (DWRITEONLY)
2 (DREADWRITE)
Return Value:File handle or NULL.
Jfile pj_create(char *filename, int mode)
Function:Creates a new file for unbuffered reading/writing.
Currently, in spite of the mode parameter, the file is always readable and writable.
Input:filenameName of file to create.
modeFile access mode, one of:
0 (DREADONLY)
1 (DWRITEONLY)
2 (DREADWRITE)
Return Value:File handle or NULL.
Errcode pj_close(Jfile fhandle)
Function:Closes a file opened via pj_open() or pj_create().
Input:fhandleHandle of file to close.
Return Value:Success, or an appropriate Errcode value.
long pj_read(Jfile fhandle, void *buf, long size)
Function:Reads data from file into a memory buffer.
Input:fhandleFile handle returned from pj_open() or pj_create().
bufMemory buffer; destination of read.
sizeNumber of bytes to read.
Return Value:Number of bytes actually read. If zero, you are at end of file. If less than size an error occurred.
long pj_write(Jfile fhandle, void *buf, long size)
Function:Writes data from a memory buffer into a file.
Input:fhandleFile handle returned from pj_open() or pj_create().
bufMemory buffer; source of write.
sizeNumber of bytes to write.
Return Value:Number of bytes actually written. If less than size an error occurred.
long pj_seek(Jfile fhandle, long offset, int mode)
Function:Seek to an arbitrary location in a file.
Input:fhandleFile handle returned from pj_open() or pj_create().
offsetNew file position. Exact meaning depends on mode parameter.
modeCan be one of three values:
0 (DSEEK_START)
offset is relative to the start of the file.
1 (DSEEK_REL)
offset is amount to move from current file position.
2 (DSEEK_END)
offset is relative to the end of the file.
Return Value:New file position relative to the start of the file. Negative Errcode value if an error occurs.
long pj_tell(Jfile fhandle)
Function:Returns current file position relative to the start of file.
Input:fhandleFile handle returned from pj_open() or pj_create().
Return Value:Current file position.
Errcode pj_delete(char *filename)
Function:Deletes a file.
Input:filenameName of file. May include device and directory information.
Return Value:Success if file was deleted, otherwise an Errcode that describes the problem.
Errcode pj_rename(char *oldname, char *newname)
Function:Renames a file.
Input:oldnameCurrent file name.
newnameNew file name.
Return Value:Success if file was renamed, otherwise an Errcode that describes the problem.
Boolean pj_exists(char *filename)
Function:Determines whether a file exists.
Input:filenameName of the file to check for.
Return Value:TRUE if file exists, FALSE if it does not exist.
Errcode pj_ioerr(void)
Function:Returns the status of the last unbuffered file I/O operation.
After an unbuffered I/O function has returned a generic error status (e.g., a NULL pointer), this function will return an Animator Errcode value that describes the problem in detail.
Input:(none)
Return Value:Success if the last I/O function worked, otherwise an appropriate Errcode value.
char *pj_get_load_path(void)
Function:Returns the name of the path the REX module was loaded from. Returned string will be in the format:
device:\path\etc\yourname.typ
Input:(none)
Return Value:A pointer to the path. This points into the host data space, do not modify the string in-place!
char *pj_get_path_name(char *path)
Function:Returns a pointer to last name in a path (i.e., a pointer to the filename on the end of a full path-with-filename string).
Input:pathPointer to pathname.
Return Value:Pointer to the last name in the path string.
char *pj_get_path_suffix(char *path)
Function:Returns pointer to the '.' in the last name in a path, or to the terminating '\0' if the last name does not have a suffix.
Input:pathPointer to pathname.
Return Value:Pointer to the suffix of the last name (the '.'), or pointer to '\0'.
STDIOLIB - Standard C Stream I/O Functions
The STDIO.H and STDIOLIB.LIB files contain the standard stream I/O functions listed below. When you request the AA_STDIOLIB host library, these functions will be available.
Standard Stream I/O functions supported by AA_STDIOLIB:
Please refer to your compiler's runtime library documentation for details on these functions.
clearerr fclose feof ferror fflush
fgetc fgets fopen fprintf fputc
fputs fread fseek ftell fwrite
printf rewind sprintf ungetc
Additional functions:
AA_STDIOLIB supports the following additional function, not found in standard C runtime libraries.
Errcode pj_errno_errcode(void)
Function:Returns the status of the last stream I/O function.
After a stream I/O function has returned a generic error status (e.g., a NULL pointer), this function will return an Animator Errcode value that describes the problem in detail.
Input:None.
Return value:Success if the last I/O function worked, otherwise an appropriate Errcode value.