### Writing Custom Display Drivers

A display driver is a module [dll/so] that handles the image output. The renderer will essentially send the rendered tiles of the image to a display driver and then the driver can display/save it. To write a display driver, you need to create a [dll/so] that exports the following three functions:

void *displayStart( | const char *name,
| int width,
| int height,
| int numSamples,
| const char *samples,
| TDisplayParameterFunction parameterFunc);

This function is called right after WorldBegin and should initialize your display driver. Most of the parameters have obvious meanings: name is the display name given by Display. width, height give the image size given by Format. numSamples, samples give the number of samples per pixel and the textual definition of the samples given in Display. For example:

Display "ri" "file" "rgb"

will call the displayStart function of the display driver file with numSamples=3, samples="rgb". The last parameter parameterFunc can be used to fetch individual options or parameters given in the Display. The prototype for this function is defined in dsply.h in the include directory. The return value from this function is a transparent display handle. This handle will be used to identify the display in the subsequent calls. A return value of NULL indicates an error. In this case, no data about this image will be sent to the driver and thus the functions below will not be called.

int displayData( | void *image,
| int x,
| int y,
| int w,
| int h,
| float *data);

This function is called to deliver data to the display driver. image is the transparent display handle returned by displayStart. x,y give the coordinates of the top left corner of the tile and w,h give the width and height of the tile. The renderer will always cover every pixel once and only once. However, the renderer makes no guarantees about the order or the size of the tiles (i.e. the renderer may change the tile size and send tiles out of order). The raw data is given in data where every float gives a sample (i.e. first numSamples floats give the first pixel). The data is not quantized or clamped to (0,1) before calling this function. It is the receiver's responsibility to do that. This function must return 1 on success and 0 on failure. On failure, the renderer will not send any more data and will not call the function below (So you should clean whatever data you allocated before returning).

void displayFinish(void *image);

This function is called after WorldEnd to signal the driver that the rendering is complete and all the pixels have been sent. The image is the transparent display handle returned by displayStart. This function will not be called if displayStart returns NULL or displayData returns 0.

Notice that displayStart is called in WorldBegin and displayFinish is called in WorldEnd. The implementation of the default display drivers file and framebuffer are provided in source distribution directory. The parameters in the table below are always defined and the function parameterFunc will return them. A display driver must implement all three functions to be accepted by the renderer. The following parameters are defined by default:

Name | Type | Description
quantize | float[4] | The quantization(min,max,zero,one)
dither | float | The dithering amount
near | float | The near clipping plane
far | float | The far clipping plane
Nl | float[16] | Column major world to camera transformation matrix
Np | float[16] | Column major world to NDC transformation matrix

Pixie supports opening multiple displays with any combination of global or user defined variable output types. So you can define a variable before the "Display" statement and use it as the output type. Note that if your shaders do not set this global output variable, the result will be garbage. You can also pass different quantization constants to different displays by specifying "custom" as the quantization type in "Quantize" call (i.e., Quantize "custom" 0 0 0 0 0). This will cause the last display to use this quantization settings.

### Default display drivers

Pixie supports the following display drivers by default:

file (tiff, shadow)

This is the default display driver that saved the scene into a TIF file. This is the same driver as tiff and shadow (the renderer will replace those names with file). You can specify the compression method by:

Display "name" "file" "mode" "string compression" "compression"

Where compression argument is either one of NONE,LZW,JPEG or Deflate. If no compression is specified, the output file will be uncompressed. You can have Pixie generate a high dynamic range TIFF output by the following line:

Quantize "rgba" 0 0 0 0

Ps: Due to the LZW papent dispute, it may not be available on all platforms.

framebuffer

This driver will simply display the rendered image on the screen. The default background image is a checkerboard image. So if you have alpha channel in your output, the image will be composited automatically to the image generated by the renderer.

rgbe

This driver generates a Radiance PIC output. No compression is supported and the output image is always high dynamic range.

tsm

This driver stands for Transparency Shadow Map. TSM is very similar to Deep Shadow Maps. This driver will only save a shadow map which contains an opacity function for each pixel. So the output mode is ignored. In fact, this driver is hard-coded into the renderer. So there is no module for this driver. In general, for scenes with volumetric objects, this shadow map can be quite large. You can compress the generated shadow map by passing an opacity threshold by:

Display "name" "tsm" "mode" "float threshold" "t"

where t is the opacity threshold. The compressed file will not have an opacity error greater than this number. Unlike regular shadow maps, tsm can be filtered and can contain motion blur or depth of field effects as well as colored / transparent objects. If you have a scene with lots of transparent stuff casting transparent / colored shadows, this driver is heavily recommended.