Render
======
Render is a component of the image library, currently only used by the GIF
decoder which provides a mechanism for holding and displaying compressed
image data and also for holding and displaying animations. It's function in
respect to still images is quite different to it's function in respect to
animated images and it is up to the client application (such as the GIF
decoder) to decide whether to call the animation routines or the still
routines.

Still (inanimate) images
------------------------
The basic idea with still images is that a client outputs a bitstream to
render which compresses it using an LZW derived internal format. This
internal format is designed so that the newly compressed image can be
plotted directly to the screen relatively quickly, thus avoiding the need to
store images as sprites (consuming a relatively large amount of memory). The
obvious application for such a method is fetching of images in a web
browser. The browser pumps the data into the image library as it arrives.
This in turn funnels the data into the GIF decoder which sends the decoded
data a row at a time to render.

Fetching
--------
The fetching process proceeds as follows :

- The client application first calls render_start to begin the compression
  process, specifying the image's width, height, transparent colour and
  various flags. A handle is returned which the client then uses in all
  future dealings involving the image. Also returned is an address to begin
  putting the bitstream. Currently, only 8bit images are supported, so the
  bitstream should be a sequence of 8bit colour numbers.

- At the end of each row of data, a call is made to render_row. Render uses
  this to compress the row of data. The call returns an address to put the
  next row of data in.

- When the whole image has been decoded, render_end is called to tell render
  the image is complete.

Internally, render compresses the data using an LZW algorithm, but with a
known blocksize of eight lines. Render stores offsets to each eight line
block so that if a particular row of data needs to be redrawn (eg. in a
desktop environment if a menu has been dragged over an image), it is only
necessary to work through and decompress a maximum of seven lines of data
before we come to the row we want. This is in contrast to, for example, the
GIF format, where it is necessary to decompress the whole of the image from
the start until the row we wish to plot.

Plotting
--------
- The application calls render_whole_scaled, specifying the x and y
  co-ordinate to plot at, plus a scale factor.

- To plot the image, render makes use of a sprite one pixel high and the
  width of the image. Each row's data is put into the sprite and the row
  plotted to the screen using SpriteExtend.

- When an image is no longer required, a call to render_delete will remove
  it from memory.

When render_whole_scaled is called, a check is made by render to see if the
scale is 100%. If so, another routine which is optimised towards 100% plots
is called. Both this routine, render_whole, and render_whole_scaled then
make checks for if the image is interlaced (in which case call another
routine which will cope with interlacing) or if only a portion of the image
needs to be redraw (in which case call another routine).

It is worth noting at this point that an interlaced plot will only be
required while data is being fetched (ie. the image is incomplete). Once
render_end has been called, render will convert the interlaced image to be
non-interlaced, to aid the speed of later plots.

Animated images
---------------
Animated images are not stored in a compressed format because plotting would
be too time consuming. Instead, they are stored internally as a series of
sprites.

Fetching
--------
- The client application first calls render_animate_start, specifying the
  screen width and height. This is the area occupied by the animation and is
  equivalent to that detailed in the GIF specification. The call returns a
  handle which is used in all future calls to render.

- Next, before each frame's bitstream is to be output, a call is made to
  render_animate_new_frame, supplying a pointer to a block of frame data,
  plus the background colour index. The structure of the frame data is
  specified in the h.datastruct header file in the sources, and contains
  details such as the width and height of the image, where to plot it within
  the screen specified in render_animate_start and various flags. The call
  will return a pointer to the location in memory to begin putting the
  bitstream (which should at present be 8bit colour numbers).

- The bistream is supplied to render a row at a time, via the call
  render_animate_row. It assumes that the client has put a row of data at
  the location supplied previously. The call returns a pointer to the
  address in memory to put the next row of data. If the image is interlaced
  (this will have been specified in the frame data), then render will be
  aware of this and will alter the pointer accordingly.

- After each frame, a call is made to render_animate_done_frame. The routine
  works it's way through the image data for the newly completed frame and
  fills in the mask where appropriate.

- Finally, when all frames have been processed, the client calls
  render_animate_end.

Plotting
--------
To plot an animation, a call is made to render_animate_plot, specifying the
x and y co-ordinate to plot at, plus the percentage scale. Internally, the
process of plotting an animation is quite complex, basically because the GIF
format is quite complex and is not aimed at animations (the CompuServe
specification  states it is not designed for animations).

Each frame of the animation is stored as an 8bpp sprite, with it's own
palette.

For each animation, a copy of the screen (not the physical screen, but the
screen specified to render_animate_start) is kept as a sprite in the current
mode and referred to as last_screen in the sources.

To plot a frame, the process is then...
 1. Take last_screen sprite.
 2. Perform disposal of the last_frame. Render will perform all the disposal
    methods that the GIF format specifies, specifically:
     i.   Restore the area which the last_frame covered, to what it was before
          last_frame was plotted.
     ii.  Blank the area which the last_frame covered to the background colour.
     iii. Leave the last_frame in place.
 3. If the disposal type for the current frame is to restore the screen, then
    store the contents of last_screen (image and mask) occupied by the current
    frame, in a restore buffer.
 4. Next, the current_frame is plotted on top of the last_screen image.
 5. A sprite the same size as the current_frame is created in the current
    mode. If the client has registered a background filling function, then vdu
    output is directed to the new sprite and the filling function called to fill
    the background in.
 6. The last_screen sprite is then plotted over the top of the background
    sprite, it's mask allowing the background to show through at the right
    places.

The above process is only necessary when a new frame is being displayed. If
it is not yet time to display a new frame, but the animation needs
redrawing, it is only necessary to plot the last_screen sprite. Render
decides if it is time to plot a new frame by storing the value of the
monotomic clock when the last frame was first plotted. The current value of
the clock is then compared with this and the delay specified for the frame
by the client. 

When an animation is finished with, a call to render_animate_delete will
remove the data from memory.
