This is Allegro Vivace, seventh draft (26 August 1999).

Allegro Vivace
**************

Copyright (C) 1997-1999 George Foot

Permission is granted to distribute this documentation verbatim
in any form without restriction and to distribute modified
copies provided it is stated that modifications have been made.

This is the seventh draft.  The Texinfo source was updated on
26 August 1999 and built on 25 August 2000.

Legal issues
************

Distribution
============

You may freely distribute this document in any form without
modifying the text; I don't expect anything in return, but an
email would be nice.

You may also distribute modified copies in any form, provided
it is made clear that such copies have been modified.

Disclaimer
==========

I accept no liability for any damage use or abuse of this
tutorial may cause to anything at all.  The examples presented
as part of this package are not guarranteed to work, and are
not guarranteed to be safe.  In general you shouldn't compile
programs you don't understand anyway.

1. Introduction
***************

1.1 About the tutorial
======================

This tutorial is available in several different formats - plain
text, Info format (which also works with RHIDE) and as Texinfo
source.  The source distribution includes utility files to
create the other formats, including DVI and Postscript, which
can be printed on paper.  Support for HTML format is planned.

The tutorial is accompanied by a suite of example programs,
mostly written by Grzegorz Adam Hanciewicz.  They demonstrate
the functions and techniques discussed in the tutorial text, and
are a valuable resource if you get stuck trying to understand
something.

All parts of Allegro Vivace - the tutorial in the main formats,
the tutorial source distribution, and the example programs -
can be downloaded, individually or in groups, from the web site:

     http://www.canvaslink.com/gfoot/vivace/

If you want to contact me, my email address is:

     gfoot@users.sourceforge.net

Comments, suggestions and complaints are, as always, much
appreciated.

1.2 Aim
=======

The aim of this tutorial is to guide newcomers to game
programming and Allegro through the process of writing a simple
game.

1.3 Target audience
===================

As stated above, this tutorial is aimed at newcomers to game
programming and Allegro.  It is not aimed at complete newcomers
to the C language.  By this, I mean some knowledge of and
experience using the C language will be assumed, and I expect
you to already have a working compiler that Allegro supports.

1.4 Requirements
================

   * Working compiler (recommended: gcc v2.7.2.1 or better; use
     djgpp v2.01 or better for DOS)

   * Allegro version 4.0 or compatible (see below for comments
     on other versions)

   * GNU Make utility (for building Allegro, and because it's
     useful anyway)

By "working compiler" I mean one that is capable of compiling C
programs and linking them to executables for your platform.  It
also needs to be able to work with the Allegro library, of
course, but we'll go through that below.

If your compiler does not work properly, you need to
troubleshoot the problem, and this is not the place for me to
explain this in detail.  For djgpp, read `readme.1st' and the
djgpp FAQ; if this doesn't help follow the instructions given
in the FAQ for posting a help request to the djgpp
newsgroup/mailing list.  If your version of djgpp is v2.00, you
are strongly advised to upgrade it.

This tutorial was last updated during the WIP phase of Allegro
4.0, but does not yet fully cover the new features.
Nevertheless, Allegro 4.0 is the primary version this tutorial
should be consistent with, and I am updating it.

Most things should still work for older versions, but some
things may not -- such is life.  I'll do my best to note
changes needed for Allegro 3.x.  Versions of Allegro older than
3.0 all require C++ support to build.  You don't have to program
in C++ but you must have the support.  If you don't, either
upgrade Allegro to the latest WIP (recommended, they're very
stable indeed) or install C++ support (for djgpp, see
`readme.1st').  If you don't upgrade your Allegro version, you
_will_ need to edit parts of the sample code in this tutorial.

Hopefully more recent versions of the above packages will
retain backward-compatibility with these versions; if not, you
will again have to figure the changes out for yourself.

You _will_ need the GNU make utility, despite the fact that
djgpp's `readme.1st' marks it as optional.  It is a highly
useful package, and both Allegro and the examples accompanying
this tutorial are designed to be built (painlessly) using it.
The latest version for djgpp (as of writing) is `mak3761b.zip',
which is compiled with version 2.01 of djgpp and will _not_
work correctly with version 2.00.

Most people seem to program using one of three systems: some
people use IDEs like RHIDE, some prefer Emacs, and others use
simple text editors and the Make utility.  This tutorial will
not attempt to force any of these systems onto you; you should
program in whatever environment you like best.  The examples
should be built using the Make utility, but you could easily
create RHIDE projects for them.

1.5 Before we start...
======================

This tutorial is aimed at people of a range of programming
abilities, from those who have only just learned to those who
have much experience already.  If you feel a section is at all
patronising, don't read all of it -- most likely that section
is aimed at people below your standard and all you need to do
is skim it to familiarise yourself with the commands it
introduces.

I have enclosed some sections' titles with [ and ], indicating
that the topic is advanced, complicated, tedious to implement or
just a bit of a tangent.  Don't read it if you don't want to.

A big issue in writing games is inspiration -- if you can't
think of something to write, then you can't write it.  At first
you will probably either not think of anything, or think of too
many ideas which seem far too complicated to implement.

If you can't think of anything, relax and read this tutorial.
Use the example programs as a base, add new things to them and
personalise them.  As you read through you will get a better
idea of what can and cannot be done.  Look at commercial games,
too -- see if you can firstly see how they do what they do, and
secondly improve upon them.  Don't assume it's completely out
of reach -- as you gain experience you will be able to see
different ways of doing things.  Remember, the authors wrote it
somehow; it must be possible.

If your ideas are too complicated, the above point applies
again -- the more games you write, the better you are at
writing them and the more games you are able to write.  In
almost all situations for beginners, the key point is to start
simple and get a working game early on, then build up from
there.  This technique does have its disadvantages but for now
it should be fine.

Last of all, games are supposed to be fun; that's their
purpose.  You cannot write a fun game if you're not enjoying
writing it.  If you find this tutorial boring then I've written
it badly and it should be changed, so please tell me.  This
tutorial is for you and others like you; enjoy it!

2. Getting, installing and using Allegro
****************************************

2.1 What is Allegro?
====================

Allegro is a game programming library, mainly written and
coordinated by Shawn Hargreaves.  It is a very good library; it
is fast, and has a large number of features, and with version 4
it makes a great cross-platform compatibility layer, letting you
write code that works on platforms you've never touched.  For
full information, see its web pages:

     http://www.talula.demon.co.uk/allegro/

2.2 Where to find Allegro
=========================

Allegro is available primarily from the links on its web site
(see What is Allegro.), and also as part of the djgpp
distribution at `ftp.simtel.net'.  The versions included with
djgpp are usually the most recent stable ones; if you want the
latest work-in-progress versions you must go to the Allegro web
site.

I do recommend that you get a WIP version, because this tutorial
is written with that in mind.  They are very stable.  As of this
writing, 3.9.25 has been out for a few weeks and I don't recall
any major problems with it.

2.3 How to install Allegro
==========================

These instructions are for guidance only - the procedure does
vary from platform to platform, and is explained more fully in
the corresponding readme files that come with the version you
download.

Create a directory for it, anywhere you like, and unzip it
preserving its directory structure (pass `-d' to `pkunzip'
under DOS; Unix unzippers tend to handle this automatically so
no switches are necessary).  Make sure it has, for instance,
created a directory called `docs'.

When that's done, go to Allegro's base directory.  If you are
using a WIP, you now need to fix the distribution to suit your
platform.  For DOS with djgpp, type:

     fixdjgpp

For Unix systems, type:

     chmod 700 fixunix.sh
     ./fixunix.sh

Next you can configure the build.  See the readme files for your
version and platform for details here.

To build the library and utilities, run `make':

     make

This should then go all by itself, and finish with a short
message telling you it worked.  If this does not happen, read
the Allegro documentation if you have not already done so (in
the allegro directory -- `allegro.txt', `faq.txt' and
particularly `readme.txt').

Finally, you need to install the library file and header files,
so that your programs can easily use them:

     make install

In Unix you probably need to be the root user to do this.

If you're still stuck, try asking on the Allegro mailing list
-- `allegro@canvaslink.com'.  See the `Contact Info' section at
the end of Allegro's `readme.txt' for subscription information.
Most people just reply to the mailing list, though, so if
you're not subscribed you should point this out and ask people
to Cc: their replies to you as well.

2.4 Testing the installation and building the Vivace example programs
=====================================================================

The installation is pretty much self-testing, because it
compiles all the Allegro example programs and utilities.
However, for completeness I have included a short program to
check the header file and library can be found.  To perform this
test, cd to this tutorial's `examples' directory and type:

     make test

If there are no errors, great - you can now build the rest of
the Vivace example programs by rerunning `make' without the
`test' argument.

If, however, it couldn't find `allegro.h', `liballeg.a' or
`-lalleg', the installation didn't work correctly and you
should reread the documentation in more detail.

2.5 Using Allegro
=================

This duplicates briefly what the Allegro documentation says.

Firstly, any source file which used Allegro functions or
variables must `#include <allegro.h>'.  Put this _after_ any
standard header files -- in particular, it must go after
`#include <stdio.h>' -- to prevent clashes between the header
files.

Secondly, you should call `allegro_init()' near the start of
your program.  This initialises some important general things
in the library and is essential.  You also need to initialise
any individual subsystems that you will be using, but we'll
come to that later.  I suggest that you make `allegro_init()'
the first thing in your `main' function.

Thirdly, you must [in Allegro 4 and WIPs] write `END_OF_MAIN()'
after the closing brace of your main function.  If you don't do
this, your program will not link properly with the Allegro
library.

Finally, at link stage you must link in the Allegro library.
This is accomplished by adding `-lalleg' to the _end_ of your
linking command.  The linking command is the one which produces
the executable file; it may be the only command you use.
During this tutorial, though, I will encourage you to split
your projects between multiple files.

For an example of all of this, see `test.c' in the
`examples/test/ex_1' subdirectory of the main tutorial
directory.

Anyway, enough of that -- let's get on to the interesting bits.

3. A basic game structure
*************************

3.1 What does a game need to do?
================================

Most games are built around the same basic concepts.  There
are, of course, exceptions, and I am not a professional game
coder, but in my experience the following system generally
works very well.

  1. Initialisation

     First of all we need to put the game into a known state,
     so that it always starts in the same way.  For example,
     you might want to start the player in the middle of the
     screen, make a maze, or create a random map.  All that
     would go in here.

  2. Main game loop

     The game will need to keep doing things, over and over
     again, until the player dies, wins, gives up, or whatever.
     So we have a main game loop.  It has three main
     components:

       A. Input -- getting input from the player

       B. Processing -- moving things around, responding to the
          input

       C. Output -- sending information back to the player,
          usually by putting it on the screen but sometimes by
          other means, for example playing sounds

  3. After the game

     When the game has finished, we may need to do some other
     things, like tell the player why it finished, update a
     high score table, or something like that.

In reality the above sequence is usually also contained in a
larger loop, so that the game can be played over and over
without dropping to the OS in between, and there's some
initialisation before the outer loop and tidy-up code after it,
e.g. loading the high score table from disk on startup and
saving it again on exit.  At first, though, we'll just do a
single run of the game per execution.

3.2 Proposed structure
======================

Here, then, is the above structure in C code:

     #include <allegro.h>
     #include "game.h"

     int end_game;                   /* flag we'll set to end the game */

     int main (void)
     {
         allegro_init();             /* initialise the Allegro library */
         init();                     /* initialise the game */

         end_game = 0;               /* reset flag */
         do {                        /* loop */
             input();                /* get input */
             process();              /* process it */
             output();               /* give output */
         } while (end_game == 0);    /* until the flag is set */

         shutdown();                 /* shut down anything that needs it */
         allegro_exit();             /* just for luck */
         return 0;                   /* tell the OS that all went well */
     }
     END_OF_MAIN()

In the above example, `game.h' would be a header file
prototyping the functions `init', `input', `process', `output'
and `shutdown' which must be defined somewhere else in the
project.

3.3 Multi-file projects
=======================

I mentioned earlier that I was going to encourage you to split
your source between files.  A lot of people find this hard to
do at first, and don't see why it is worthwhile.  In this
section of the tutorial I intend to justify it and present what
I consider to be a good system for organising a project.

Justification
-------------

Firstly, then, why are multi-file projects a good thing?  They
appear to complicate things no end, requiring header files,
extern declarations, and meaning you need to search through
more files to find the function you're looking for.

In fact, though, there are strong pros to this argument.  When
you modify a line of your code, gcc has to recompile everything
to create a new executable.  However, if your project is in
several files and you modify one of them, gcc already has the
object files it generated from your source last time you
compiled it, and so it only needs to recompile the file that was
changed.  In a large project this can mean the difference
between a lengthy (5 minutes or more, depending on computer
speed) recompile and a twenty second adjustment.

With a little organisation, splitting a project between files
can make it much easier to find the piece of code you are
looking for.  It's simple -- you split the code between the
files based on what it does.  Then if you're looking for the
routine to draw the player, you know it will be in the graphics
source file.

Also, since your program is very modular with the minimum
amount of sharing between files, bugs are easier to track down;
if not many files have access to a certain variable, an
erroneous value must be a bug in one of those files.

Suggested system
----------------

This is strictly IMHO; other people may prefer to lay things
out differently.  But since I find these guidelines useful, I
suggest you follow them.

   * Don't make header files which span several source files
     (exception: library header files).  It's much easier to
     track and usually more efficient if each header file only
     declares symbols from one source file.

   * Where appropriate, do use more than one header file for a
     source file.

   * Don't duplicate information in several header files.  If
     you need to, `#include' one in the other, but don't write
     out the same header information twice.  This way, if you
     change the information in the future you will only need to
     change it once, rather than hunting for duplicates which
     would also need modifying.

   * Make each source file includes all the header files which
     declare information in the source file.  Doing this means
     that the compiler is more likely to pick out mistakes,
     where a declaration in a header file does not match the
     definition in a source file.

I hope you can see the advantages of splitting up your
projects, but if you don't, by all means keep your project in a
single file.  The examples I will use later on will normally be
multi-file, based around the guidelines above and the game
structure discussed earlier (see Proposed structure.), so
there will be plenty more opportunities to see the benefits of
this.

If you are still confused about this, please have a look at the
article I wrote for the electronic magazine C-Scene:

     http://www.cscene.org/

The article is in issue 2, entitled `Multi-file projects and
the GNU Make utility'.  It duplicates the information here, in
more detail, and explains some common problems newcomers have
to this technique.

4. Introducing graphics
***********************

Note
====

This section assumes you are familiar with the idea of graphics
programming, i.e. coordinate systems, resolution, etc.  If you
are not, try reading it anyway; if you don't understand you
should get a book on computer graphics.

4.1 Selecting a graphics mode
=============================

To put the computer into a graphics mode, you use this function:

     int set_gfx_mode (int CARD, int W, int H, int V_W, int V_H);

For CARD, you put one of the `GFX_*' constants, normally
`GFX_AUTODETECT'.  W and H are the minimum width and height of
screen space you want; the actual mode selected might have a
slightly larger display area.  For now just pass 0 for V_W and
V_H.

4.2 Drawing things
==================

4.2.1 The BITMAP struct
-----------------------

Allegro's graphics routines aren't restricted to writing to the
screen; they write to "bitmaps".  A bitmap could be the screen,
it could be a block of memory, or it could be a "subbitmap"
(part of another bitmap).  When you call Allegro's graphics
routines you pass them a pointer to a `BITMAP' struct, which
contains information about the bitmap you want to write to.

It's best to think of your pointer simply as a "handle" to the
bitmap -- it's just like a reference number.  Allegro will
assign it initially, and you then pass it back to the graphics
routines to tell them where to draw.

The only interesting parts of the `BITMAP' struct as far as
we're concerned are the `w' and `h' fields; these hold the
width and height of the bitmap respectively, in pixels.

Allegro defines the variable `screen' to be a pointer to a
`BITMAP' struct representing the screen, so for example:

     clear_to_color (screen, 5);

will clear the screen to colour 5 (often magenta).

4.2.2 Plotting pixels
---------------------

To plot a pixel you use the Allegro function:

     void putpixel (BITMAP *BMP, int X, int Y, int COLOR);

This sets the pixel in the bitmap referenced by BMP at
coordinates X,Y to the colour COLOR.  Simple enough.

See the example program in `examples/chap_04/ex_2_2' for an
example of the use of `set_gfx_mode', `clear_to_color' and
`putpixel'.

4.2.3 Some other primitives
---------------------------

Functions like putpixel are called graphics "primitives",
because they are the basic graphics output functions.

Some other simple graphics routines are:

     void vline(BITMAP *bmp, int x, int y1, int y2, int color);
     void hline(BITMAP *bmp, int x1, int y, int x2, int color);
     void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
     void triangle(BITMAP *bmp, int x1, y1, x2, y2, x3, y3, int color);
     void rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
     void rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
     void circle(BITMAP *bmp, int x, int y, int radius, int color);
     void circlefill(BITMAP *bmp, int x, int y, int radius, int color);

Try modifying the example program from the last section
(`examples/chap_04/ex_2_2') to use some of these.  For
information about them, read the file `allegro.txt' in the
`docs' subdirectory of your Allegro directory.

If you have trouble with this, look at the example
`examples/chap_04/ex_2_3'.

4.2.4 Writing text
------------------

To write text onto the screen, you use the following functions:

     void textout(BITMAP *bmp, FONT *f, unsigned char *s, int x, y, int c);
     void textout_center(BITMAP *bmp, FONT *f, unsigned char *s, int x, y, int c);
     void textprintf

`bmp' is, of course, the bitmap onto which you want to write.

The `FONT' struct is defined in `allegro.h' and is used to
refer to different fonts in memory.  You use it in much the
same way that you use the `BITMAP' struct -- most of the time
you just pass pointers to them to various functions, and don't
need to know anything about what is actually in the struct.

You can create your own fonts, use the ones from the
distribution of GRX (another graphics library), which
originally come from XFree86 (a windowing system for Unix), and
convert fonts from Windows's TTF format.  For all of these you
need to know how to use Allegro's Grabber utility and
datafiles.  You can see `grabber.txt' for more information, but
datafiles aren't discussed until much later in this tutorial.
For now, though, you can just pass `font' to these routines;
it's a `FONT *' declared in `allegro.h' and refers to the 8x8
BIOS font.

`s' is the string you want to print, `x' and `y' are the
coordinates, and `c' is the colour.  If `c' is -1 and the font
is proportional, Allegro will use the colour information stored
in the font, allowing multicolour fonts.

`textout_center' is almost identical; the only difference is
that it centres text about the x-coordinate.

`textprintf' is a wrapper around `textout' which takes a format
string in the same way as `printf'.  `textout' is faster, but
`textprintf' is more versatile.

The background colour for text output can be set with:

     void text_mode(int mode);

where `mode' is the new background colour.  If mode is negative
the background will not be drawn, and what was there before
will show through.

Play around with these for yourself, or look at
`examples/chap_04/ex_2_4' which demonstrates them.

4.3 Palette manipulation
========================

Note
----

For most purposes, palettes only have meaning in 8-bit (256
colour) modes.  You can also set modes with higher colour
depths; if you do then the rest of this section won't have much
effect.  See Shawn Hargreaves's Pot of Gold, linked from the
Documentation part of the Allegro web pages, for information on
higher colour depths.

4.3.1 Palette explanation
-------------------------

When you draw to the screen in an 8-bit mode, you specify a
colour number from 0 to 255.  Conventionally the lower 16
colours are black, blue, green, cyan, red, magenta, brown, light
grey, dark grey, bright blue, bright green, ..., bright magenta,
yellow, white (but that may not be the case).

The remaining 240 colours are not always the same.  Before using
them you should tell the computer what colour you want to appear
on the screen when you set pixels to the given colour number.
It's safest to explicitly set all colours you use, including the
lower 16 colours; that way you can be sure that they'll appear
how you want them to appear.

I will call the colour numbers you send to the graphics
functions "logical" colours and the actual colour which appears
on the screen for each will be the associated "physical"
colour.  So we need functions to assign physical colours to
logical colours.

Logical colours are expressed as numbers from 0 to 255.  Each
possible physical colour is expressed as three numbers, each of
which ranges from 0 to 63.  These numbers represent the
strengths of red, green and blue in the colour.  63 is full
strength of course.  To store physical colours, use the RGB
struct which is defined in `allegro.h':

     typedef struct RGB
     {
         unsigned char r, g, b;
     } RGB;

Needless to say, `r', `g' and `b' are the red, green and blue
intensities of the colour, as described above.

4.3.2 Changing a single logical colour's physical appearance
------------------------------------------------------------

To change the appearance of a logical colour, use the function:

     void set_color (int index, RGB *p);

`index' is the logical colour number and `p' points to an RGB
record as above.

The example program `examples/chap_04/ex_3_2' demonstrates the
use of this function by setting colour 0 (the background
colour) to be different colours as you press keys.  Press <ESC>
to quit.

Note that there is a slight complication here, in that if you
intend to change colours repeatedly over a period of time, you
should call the Allegro function `vsync' between changes (which
will also add a certain delay). The main reason for this is
that some video cards don't like you fiddling with the palette
when they are trying to display things, and they display the
wrong colours from time to time, resulting in "snow" appearing.
`vsync' waits for the monitor to reach the end of the frame,
which removes the problem. We'll see more of `vsync' later on.

4.3.3 Changing the entire palette
---------------------------------

To change the whole palette at once we could call `set_color'
repeatedly, but this would be slow and awkward.  Instead,
`allegro.h' defines the type `PALETTE' to be an array of 256
RGB records, one for each logical colour.  You can create your
entire palette in this array and then set it with a single
function call:

     void set_palette (PALETTE p);

The example `examples/chap_04/ex_3_3' demonstrates this
function by drawing a rainbow of colours and then switching the
palette to a greyscale one.

4.3.4 Fading in and out
-----------------------

In low colour-depth modes (e.g. 256 colours) this is simple: to
fade out you keep making the palette darker and darker until
it's all black, and to fade in you do it the other way around.

Allegro has several functions to do this; the most basic are:

     void fade_in (PALETTE p, int speed);
     void fade_out (int speed);

Note that `fade_in' requires you to say what palette you are
fading to; `fade_out' doesn't need a palette because it assumes
you mean to fade from the current palette.

`speed' is the speed of the fade, ranging from 1 to 64 with 64
being an instantaneous change.

`examples/chap_04/ex_3_4' demonstrates these functions.

4.4 Simple animation
====================

4.4.1 What is animation?
------------------------

Animation is making things appear to move.  This could mean
making a pixel move around the screen, but it is usually taken
to mean repeatedly changing something's appearance so that it
seems to propel itself.

For now we will just look at how to make simple things move
around the screen; the second interpretation will be dealt with
later on when we look at sprites.

4.4.2 Making things appear to move
----------------------------------

The simplest way to make something appear to move is to erase
it from where it is and put it on the screen again somewhere
else.  It's a philosophical matter whether it has in fact
moved; since it doesn't exist anyway there's not a lot of point
worrying about it.  So we'll just say that it has moved.

To make a solid circle move across the screen you could do
something like this:

     int x;
     install_timer();                           /* required for `rest' */
     circlefill (screen, 0, 100, 5, 15);        /* draw first time */
     for (x = 1; x < 320; x++) {               /* loop across the screen */
         rest (10);                             /* slow it down */
         circlefill (screen, x - 1, 100, 5, 0); /* erase from last place */
         circlefill (screen, x, 100, 5, 15);    /* redraw at new place */
     }

Try this out to see that it works.  Now make the circle bigger
(radius 50, say) and see what happens.

4.4.3 Reducing flicker
----------------------

Okay, so that started flickering quite a bit.  If it didn't,
make the circle bigger.  If it still doesn't, well, it would if
you had used a high-resolution screen mode (try it).  If you
can't make it flicker at all then congratulations, you have a
supercomputer.

Us mere mortals, though, have to do something about the
flickering.  There are many approaches; some are more
complicated than others, some are more effective, and some are
simply good because they don't take much CPU time (and so the
game runs at a higher frame rate).

4.4.3.1 Synchronising to the vertical retrace
.............................................

This is the most important thing to do.  The vertical retrace
is the time period during which your monitor is preparing to
draw a new frame.  During this time nothing is drawn on the
screen, so if we can erase the object and redraw it before the
monitor starts the next frame our problem is solved.

The `vsync' function waits until the start of the next vertical
retrace period.  When this happens, we want to update the
screen display as quickly as possible.  So, replace the
`rest(10)' with `vsync()' and try it again.  Much better.

Note that the vertical retrace is like a timer in a way; it
occurs at a fixed rate (for each video mode; it varies between
modes).  Consequently, since we have to sync with it anyway, it
can be a useful way to regulate the game speed.  We'll find
better ways in chapter 9, though, when we deal with Allegro's
timer system.

4.4.3.2 Maximising drawn time
.............................

If we are drawing so much that we can't get it all done during
the retrace, we need to reduce flicker in some other way as
well.  Consider what the situation would be if we had a lot of
circles, and we erased all of them before redrawing them all.
They would all be undrawn for a relatively long time; there's a
high chance that the monitor will try to display their area of
screen when they aren't drawn.

We could solve this problem by erasing and redrawing them one
by one.  This would help reduce flicker, but it would introduce
other problems.  The point, though, is that maximising the
amount of time things are drawn for is a good aim.

For example, if you erase all your objects and then work out
where you should redraw them, they're off the screen while
you're calculating.  If you can do the calculations before
erasing them, they'll spend more time on the screen and less
time off it.

4.4.3.3 Optimising drawing order
................................

As we noted above, sometimes we might not get all our drawing
done during the retrace period.  So what happens next?  The
monitor begins displaying the screen, from the top down.  So,
if we're only going to get some of the drawing done in time, it
would be better to get the stuff at the top ready so that the
monitor can draw it.

In fact, the important thing is not to erase something while
the monitor is trying to display it.  We can't know for sure
which part of the screen is being updated at any time though,
unless we use a very high-resolution timer, which has other
drawbacks.

Several drawing orders are sensible.  You can draw things
strictly from the top down.  This also improves the frame
redraw speed in higher resolution/colour depth modes by
reducing video bank switches.  You could consider how complex
each object is, and perhaps draw the simplest ones first.

Another technique is to draw from the _bottom up_.  This may
sound odd, but if you do this you'll only run into the retrace
once, and only for a short period.  Using this system there
will be some flicker, but it's likely to be less severe.

Think about travelling quickly along a motorway in a car,
looking sideways out of the window.  Better make sure somebody
else is driving though.  You're trying to get a good view of the
hedge.  Cars travelling in the same direction as you have a low
relative velocity, and so they block your view of the hedge for
long periods.  Cars travelling in the opposite direction will
only block your view for very short periods, though.

4.4.3.4 Double buffering
........................

This is a very popular, simple system, which works well in fast
(i.e. low resolution) video modes.  Newer graphics cards (AGP
and to a lesser extent PCI) can also handle it in higher
resolutions.

The technique of double buffering involves writing all the
graphics to a temporary bitmap, until a whole frame has been
updated, and then copying the final image to the real screen
memory in one big chunk.

This can be effective for several reasons.  Firstly, it means
that we are no longer erasing anything from the screen -- we
are just replacing one image (with everything drawn) with
another (still with everything drawn).

Secondly, video memory is rather slow.  If we tend to overwrite
areas of the screen a lot when drawing the frame, it will be
faster to do all these writes to the (fast) system memory and
then copy that to the (slow) screen memory than it would be to
perform the writes directly to the screen memory.  In addition,
reading from screen memory is often even slower; so if we will
want to read from the image it is far better to read from a
copy in system memory.  This is very much like disk caching,
where copies of bits of the disk are kept in system memory to
avoid having to access the disk directly.

So, instead of drawing to the screen, we draw to another bitmap
in memory.  Then, when we're ready, we `vsync()' and then copy
the entire buffer onto the screen.  In the 320x200x256 mode
this fits well inside the retrace interval, so there should be
no flicker at all.  In higher resolutions or colour depths
there is of course more image data to copy, so it takes longer.
The effects of this range from shearing (where the top part of
the screen shows one frame and the bottom part shows another)
to drops in frame rate (where it takes so long that we miss the
start of the next retrace period, so `vsync' waits for the one
after that).

See the example program `examples/chap_04/ex_4'.  We won't look
too deeply at memory bitmaps and the blit function yet; they'll
come up in more detail in chapter 7.

4.4.3.5 Dirty rectangles
........................

This is a variant of double buffering that doesn't require such
a fast video mode, but it is trickier to implement.  The theory
is that you do exactly as you would when double-buffering, i.e.
do all your screen updates to a memory bitmap, but you only
copy to the screen those regions which have changed.

This involves keeping track of which areas have changed; the
simplest way is to mark rectangles as "dirty" when you write to
them.  Then you can easily blit all of these rectangles to the
screen.

This is better than double buffering if not much has changed,
but if a lot has changed it can be worse, partly because a
single blit of a large area is more efficient than a lot of
blits of smaller areas, and partly because you may have two
dirty rectangles which overlap; unless you take care to avoid
this, that region of the image will be copied twice.  However,
if you can detect situations where double buffering would be
more efficient, you can simply blit the whole image in one
chunk, as you would when double buffering.  The two techniques
have a lot in common.

Dirty rectangles are more awkward to implement, and if you make
small mistakes you can get strange results.  We'll return to
these in chapter 7 too.

4.4.3.6 Alternate line blitting
...............................

Again, this is a variant of double buffering.  The idea here is
to copy to the screen only every other line.  You can copy just
the even numbered lines, and leave the odd ones blank; then you
get a slightly darker picture with effectively half the
vertical resolution.  You could also copy the odd lines in one
frame and the even lines in the next; this way you don't lose
any brightness, but some lines are `older' than others,
resulting in some blur.  These techniques work best for things
like video.

5. Making several things happen at once
***************************************

5.1 Moving more circles
=======================

This sounds pretty simple, and it would be, but we're also
going to alter it in a few more ways.  Our goal here is to fit
it into the game structure presented earlier.

This time we're going to use a struct to hold together all the
elements which describe each circle -- its location, its
colour, its radius, and the speed with which it is moving in
each direction.  It will also be convenient to remember what
location it was drawn at, to simplify the erasing function.  So
let's start by defining the struct:

     struct circle_t {
         int x,y,r;         /* x, y, radius */
         int col;           /* colour */
         int xs,ys;         /* x speed, y speed */
         int dx,dy;         /* drawn x, drawn y */
     };

Now, a good way to write modular code like this is to first
think about the interface a litte; decide what you want the
layer that's calling the module to see.  Then you can write the
functions themselves, having decided roughly what they should
do -- or you can write the calling routines, even if you
haven't yet written the functions that they're calling.  An
advantage of this is that if you have more than one person
working on the game, one of you could write the object's
routines and the other could write the caller.

Another advantage, which we'll see later, is that it's easy to
add new objects to this sort of system -- all the objects will
use the same interface functions.  So the person who's writing
the coordinator, which calls all the objects' routines, could
start by using dummy objects that don't do much, to check their
routines work, then plug in the real objects later.

Let's decide what functions each object should have.  Ideally,
we want to have the following routines for a circle:  a function
to draw it, a function to erase it, and a function to update its
internal variables.  These will be called frequently, from the
main game loop.  In addition we require a function to create
it, initialising its internal variables, along with a function
to destroy it, which won't do much in this case but would, for
example, deallocate any memory which may have been allocated
for this circle.

We'll prototype our functions like this:

     void circle_draw (struct circle_t *circle, BITMAP *bmp);
     void circle_erase (struct circle_t *circle, BITMAP *bmp);
     void circle_update (struct circle_t *circle);
     struct circle_t *circle_init (int new_x, int new_y, int new_radius, int new_col, int new_xs, int new_ys);
     void circle_destroy (struct circle_t *circle);

Note that I've prefixed these functions' names with `circle_'.
This is a useful thing to do, because these functions will be
global, and we don't want clashes with functions for updating
other types of object.  Also, the prefix reminds us that
they're in the circle module.  If we weren't sure of this, we
could of course look in the header files to find out which
module they were from, but it's faster if you know just by
looking at the functions' names.

We'll have an array of pointers to `circle_t' structs, and our
main `init' function will initialise them all by calling
`circle_init' with various parameters.

Having initialised them, we'll draw them all, before we return
from the `init' function.

For now the `input' function will not do anything other than
setting the end-of-game flag if <ESC> is pressed.  The use of
the keyboard will be explained in the next section.

In `process', we will calculate the new positions of all the
circles.  To do this, we need to set up a for loop stepping
through the array of circles, and call `circle_update' for each.

In `output' we need to set up a similar loop, calling
`circle_draw' for each circle.  In most cases (depending upon
what animation technique we're using) we need to call the
`circle_erase' functions first.

Finally, when we exit it is tidy to deallocate the circles
created by `circle_init', using `circle_destroy'.

I suggest now that you try to implement this yourself, for a
single circle, then expand the program to move more of them.
The example programs `examples/chap_05/1_a' and
`examples/chap_05/1_b' demonstrate these.  If you have trouble
making your own program to move just one circle, I suggest you
look at the first example, and try to modify that to move more
than one.

Note though that when moving more than one circle, if you erase
and draw them one by one, the erasing of the later circles can
rub out parts of the earlier ones, which have already been
drawn.  To solve this, erase all the circles at once, and then
redraw them all.  However, this could increase the amount of
flicker seen (remember maximising the drawn time?), unless you
use a double buffer.

5.2 Now moving a square as well
===============================

The above technique works fine for many similar objects.  In a
real game, though, there are usually many different types of
object.  So let's look at some ways of dealing with squares as
well as circles, for example.

One solution is to add more information to the struct, enabling
it to describe a circle or a square, with a field to say which.
Then we could modify the functions to differentiate between
the two and draw them differently.  Some functions might not
need changing at all.

Another solution is to create a new struct for the squares, and
a new set of functions to deal with them.

These two techniques both have their advantages.  The first one
works well when the two types are very similar; in these cases
many functions wouldn't need changing.  All the objects could
be stored in one array, and only one loop would be needed to
draw them, move them, etc.  In addition, the similarities can
be exploited so that we can make generic routines for things
like collision detection.

The second technique works well when the objects are quite
different.  In this case it gets awkward to make a struct that
can hold the data for any of the several objects, and the
functions no longer share much code.  With this technique you
need a separate array for each object type, and you need to
scan the arrays one by one when drawing/erasing/updating them.

In practise, a set of many different object types can be
partitioned into classes of object type.  For example, the
criterion could be behaviour, appeareance, or which player owns
the object.  Each class can then be treated using the first
mentioned system, with a general struct for each class capable
of describing any object in that class, and these separate
classes are treated like separate objects in the second system.

If you have understood this, try to adapt the multiple circle
program above to deal also with squares, using each of the first
two methods.  In case you get stuck, there are some examples for
you to look at: `examples/chap_05/ex_2_a' and
`examples/chap_05/ex_2_b'.  If you do not manage it on your
own, look at these and try to add another object type to each.

As an exercise based on the mixed technique, try making a
program to move circles, squares and... er... triangles
(running out of shapes!) around, with the circles and squares
moving as before, but with the triangles not bouncing; make them
come back on from the opposite side to where they went off.  An
example of this is `examples/chap_05/ex_2_c'; you might want to
run it to see what it does, and then try to mimic its behaviour
with your own program.

5.3 Keeping track of things
===========================

Now suppose we want to be change the number of shapes at
run-time.  In all the examples above we have had a set number
of each shape moving around.  We could make it animate less
shapes by reducing the loop count, but we'd always be
destroying the last shape in the list, and we could never add
extra shapes (unless we'd destroyed some first).  In short,
what the game could do was limited at compile-time by the sizes
of the arrays.

There are two techniques I want to introduce here:  dynamic
allocation and linked lists.  Linked lists depend on dynamic
allocation, so you should probably read that section first.

5.3.1 Dynamic allocation
------------------------

During this section we'll see what dynamic allocation is, and
look at how we can use it to extend the linear array system
we've been using so far.

Dynamic allocation allows us to ask for memory at run-time
(i.e. when the program is running, as opposed to compile-time).
This means, for example, that we could ask the user at the
start of the program how many of each shape to animate, and
then create the arrays however large they need to be.  Better
still, we can resize the arrays while the game is running, so
if we ever run out of room we can just make the arrays a bit
bigger.

To do this we use the function `malloc'.  This standard C
function takes a parameter of type `size_t' (basically, a
number) and allocates that many of bytes of memory.  The return
value is a `void *', pointing to the block of memory allocated.

So, we want to create an array of `num_circles' circles.  Each
circle will be represented by a `struct circle_t'.  We can use
the `sizeof' keyword to find out how many bytes we need for each
struct, and allocate the memory like this:

     struct circle_t *circles;
     ...
     circles = (struct circle_t *) malloc (num_circles * sizeof (struct circle_t));

The cast to `struct circle_t *' is optional in C programs; a
C++ compiler will complain if you don't use it, though.  Its
use is largely a matter of taste.

If the allocation failed (e.g. out of memory), `malloc' will
return `NULL'.  Under some circumstances you might like to
detect this and inform the user.  It's good practice to do
this, but often people don't bother because there may be no
useful way to recover.  If you're using djgpp with a robust
DPMI host (e.g. CWSDPMI) it will terminate your program if you
ever try to use the NULL pointer.  Some other DPMI hosts just
let your program carry on, which hides the problem from you;
it's best to avoid these when developping, or at least to use
CWSDPMI sometimes (i.e. from plain DOS, no Windows) to check
that things still seem OK.

After the allocation, we can refer to the circles as
circles[0], circles[1], etc, as if we'd made a real array.
What we have is not an array in the strict C sense; it's just a
pointer to a block of memory.  In many ways this behaves much
like an array, though.

Finally, when we've finished with the memory we should free it
so that malloc can reuse it later if necessary:

     free (circles);

Now try modifying your program from section 5.1 (just circles,
no squares or triangles) to allow the user to specify the
number of circles at the start of the program.  If you get
stuck, have a look at `examples/chap_05/ex_3_1'.

Modifying `examples/chap_05/ex_2_a' in the same way should be
fairly simple.  Modifying `examples/chap_05/ex_2_b' will need
more mallocs.

Now, what about letting the game expand the array as it runs?
This isn't possible with a real array, but as noted earlier our
`array' is not really an array.  It was dynamically allocated,
so we can use the realloc() function to reallocate it with a
different size.  The data that was in it before will still be
there when we expand the allocation.  If we're shrinking it,
the data that's still in the new block stays there of course but
the data that is cut off the end of the block is lost.  Even if
you reexpand the block, you shouldn't rely on regaining the
data.

The problem with reallocating the block like this often is that
if the memory area just after our block is already taken then
realloc needs to copy the whole block to somewhere else.  This
isn't particularly slow (memory copy operations are pretty fast
actually) but it's not the sort of thing you want to happen too
often.

Most implementations of `malloc' put some empty space at the
end of each block, but we shouldn't rely too heavily on this.
It's better to reduce the number of reallocations some other
way.  The simplest way to do this is to always request plenty
of extra space - then we don't need to call `realloc' so often.

So, we need to keep track of a few things:

     int num_objs;      /* how many are active */
     int alloced_objs;  /* how many have been allocated */
     int block_size;    /* how many we should allocate at a time */

Then when we want to add a new object, we first check whether
we already have enough space (is `alloced_objs > num_objs'?).
If so, we can just increase `num_objs' and use that space.
Otherwise, we need to increase `alloced_objs' by block_size and
realloc the block like this:

     objects = (struct obj_t *) realloc (objects, alloced_objs * sizeof (stuct obj_t));

Note that realloc's syntax is like malloc's, but you must pass
the pointer's old value.  After calling realloc, you shouldn't
use the pointer's old value any more -- if realloc has moved
the block, the old value is now invalid.  If you'd assigned
another pointer the value of `objects' and realloc had to move
the block somewhere else, the other pointer would be pointing
at a bad block.

After reallocating the new block size, we can of course
increase `num_objs' and use the newly allocated objects.

5.3.2 Linked lists
------------------

Linked lists are an extremely useful data structure.
Unfortunately, for some reason many people find them hard to
understand.  If you can get a good visualisation of them in
your mind, though, they're really very simple, and when you've
used them a few times you get an intuitive feel for how to
maintain them.

In this section we'll look at three types of linked list, and
try using them in the circles/squares/triangles programs from
earlier on.

5.3.2.1 Singly linked lists
...........................

Firstly you'll need to be comfortable with pointers.  Pointers
are just objects that can point to other objects.  Try not to
think of them exactly as memory addresses; this is a common
analogy, but it isn't necessarily correct, and pointer
arithmetic becomes confusing if you think of them in this way.

So pointers can point at other data objects.  Most pointers are
designed to point at a certain type of data.  In particular,
they can point at user-defined structs:

     struct little_struct {
         int number;
     } *ptr;

Here `ptr' can point at any object of type `struct
little_struct'.  To access the field `number' in the object
that `ptr' is pointing at we can write `(*ptr).number' or use
the shorthand `ptr->number', which means the same thing.  Note
that the above definition doesn't actually create an object for
`ptr' to point at; it just creates the object `ptr', which is
capable of pointing at objects of type `struct little_struct'
but initially points nowhere (of course it points somewhere,
but where exactly depends upon other circumstances; you
certainly can't rely on it being a valid pointer though).  Now
how about:

     struct linked_list_node {
         int number;
         struct linked_list_node *next;
     } *ptr;

Here the `linked_list_node' struct contains not only an integer
`number', but also a pointer `next' which can point at an object
of type `struct linked_list_node'.  So if we create an object
of this type, and point `ptr' at it, `ptr->next' can point at
another object of this type.  And `ptr->next->next' can point
at another...  so you see we can have a whole list of these
structures, allocated one at a time (rather than in one large
block), and we can keep track of them all using just one
pointer to the start of the list.  To mark the end of the list
we can set the last node's `next' pointer to NULL.

ptr --> +------------+    +------------+    +---------------+
| number : 7 |    | number : 3 |    | number : 285  |
| next   :  ----> | next   :  ----> | next   : NULL |
+------------+    +------------+    +---------------+

The diagram above shows `ptr' pointing to the first of a list
of three records.  The first record, with `number' 7, has its
`next' pointer pointing at the second, with `number' 3.  That
record's `next' pointer points at record 3, which has `number'
285, and record 3's `next' pointer is NULL because it's the
last record in the list.  The whole list is storing the numbers
7, 3, and 285, in that order.

You're probably wondering why we bother with this system.  It
has several advantages and several disadvantages when compared
to the linear dynamic block storage mentioned above.

Firstly, it's very easy to manipulate things in the linked list.
New records can be added anywhere in the list, old records can
be removed, existing records can be reordered, or moved from
list to list, and lists can be split or joined with little
hassle; you just need to change the values of some of the
`next' pointers.  Any of these operations would be awkward and
time consuming to perform on a linear block -- we might have to
move large amounts of data.

For example, imagine removing the second data item in a large
sequential list -- we'd have to move the rest of the list
forward one place.  In a linked list, we just have to set the
first item's `next' pointer to whatever the second item's
`next' pointer is set to (i.e. point it to the third item, or
NULL if there is no third item), and then we can `free' the
second item's struct.

Similarly, adding a new item to the list is simple.  Assuming we
have a pointer to the item in the list before the place where we
want to put our item, we just set our item's `next' pointer to
that item's `next' pointer, and then set that item's `next'
pointer to point at the new item.

The disadvantages of linked list are memory usage and
inefficiency in finding an item by number.  The memory usage is
greater because of all the pointers in the list, and because
it's generally a large number of small chunks (in particular, as
of writing this, djgpp's `malloc' function has a minimum block
size of 4096 bytes).  Finding an item by number is inefficient
because we need to step through the whole list from the
beginning to get to it, whereas in a sequential list we can
jump straight to it with a single addition.

As always, which system you'll want to use will depend upon what
you're using it for.

It often simplifies code if the first item in a linked list is a
"dummy" item (sometimes referred to as the "list head"), whose
data has no meaning.  The reason for this is that it makes
storing empty lists simpler -- they become lists with only one
item, the dummy.

I suggest at this point that you have a look at
`examples/chap_05/ex_3_2a' for some examples of adding,
removing and finding items in linked lists.

I think you'll probably see now why linked lists can be so
useful -- we can create as many shapes as we like, whenever we
like, and just add them to the list in an efficient way.  We
don't really care what their number is in the list; if we need
to refer to a specific item in the list for some reason we can
use a pointer to that item, rather than its ordinal number.

5.3.2.2 Doubly linked lists
...........................

Assuming you understood the preceeding section, this should be
fairly easy to grasp.  In the singly linked list above, each
node had one pointer to the next node in the list.  In a doubly
linked list, each node has two pointers -- one to the next item
in the list, and one to the _previous_ item in the list.

     struct dllnode {
         struct dllnode *next;
         struct dllnode *prev;
         int number;
     } *ptr;

ptr --> +--------+     +--------+     +--------+
|  next -----> |  next -----> |  next ---> NULL
NULL <--- prev  | <----- prev  | <----- prev  |
| number |     | number |     | number |
+--------+     +--------+     +--------+

Now it is possible to find the whole list given a pointer to any
node in it.  It is still often useful to make the first node in
the list (the one with `prev == NULL') a dummy node whose data
is not used, for the same reason as above.  It can act as a
"handle" to the list -- something to hold on to, that will
always be part of the list.  The other nodes will be added and
removed at times, remember; the head element is the only one
that's guarranteed to be there all the time.

One advantage of using a doubly linked list is that you can
remove a node from a list without needing to know which list it
is in.  Another advantage is that if an entity in the list needs
to scan the list it can do so without needing to be given a
pointer to the head of the list.  Also, given any item in the
list you can add an item on either side without needing to scan
the list.  Doubly linked lists are generally easier (and more
efficient) to maintain, but they do of course have a little more
overhead.

`examples/chap_05/ex_3_2b' is an example of a doubly linked list
and routines to manipulate it.

5.3.2.3 Circularly linked lists
...............................

Again, if you've understood linked lists so far this shouldn't
be too hard.  In our singly linked list we had the `next'
pointer of the last node set to NULL, marking the end of the
list.  In a circularly linked list, the last node's `next'
pointer points back to the start of the list -- so there isn't
really a last node.  Think of it as a ring of nodes, each
pointing to the next.

If the circular list is doubly linked, the first node's `prev'
pointer points to the last node.

Empty circular lists are also a problem; using a dummy node is
useful here too, but you must remember to skip over it when
you're stepping around the loop.  Alternatively you can make
your pointer to the list NULL when it's completely empty (as you
can with any of these linked lists), but you still have to make
special cases.

Circular lists are useful for different things to linear linked
lists; in game programming you generally want to do something to
everything in the list once per game cycle, and for this purpose
a linear linked list is often better.  I mentioned circular
lists here for completeness, and because they're not very
different to linear lists.  For an example, see
`examples/chap_05/ex_3_2c'.

5.3.2.4 Using linked lists
..........................

Try modifying your shape moving program, making it put the
shapes into a linked list and animate them from there.  You
could also make it add a new shape every 100 game cycles, or
make it delete one.  See `examples/chap_05/ex_3_2d' for an
example of this.

This method of putting all game entities into a linked list and
animating them is very useful.  You can put the player's
ship/man/being in there too; if the player's character is
similar in action to the enemies then this can work well.

5.4 Object Oriented Programming
===============================

This section has not yet been written, sorry.

6. User input
*************

An input device is anything you use to give information to the
computer.  The standard PC only has a keyboard, although most
have mice and many have joysticks.  In a way I suppose a disk
drive is also a sort of input device, as are microphones,
scanners, and modems, but they're not generally good things to
use to control a game.

We'll look at each of the main three in detail, then consider
abstracting our input system.  Finally we'll look at different
ways to use the input information.

6.1 Keyboard input
==================

6.1.1 Why the standard PC keyboard routines are useless
-------------------------------------------------------

The standard PC keyboard interface is almost, but not quite,
entirely useless as a game control device.  There are several
reasons for this; firstly, whether you hold a key down or just
tap it the game would only see one keypress for a certain
period (usually a quarter of a second).  Then if you held the
key down it would fill the buffer with many keypresses, which
means the game might still be reading them after you let go of
the key.  Also, if you hold one key down and tap another, the
first key will seem to have been released.

These combine to make the standard PC keyboard routines useless
for controlling action games.  Thankfully Allegro provides a
set of much better routines.

6.1.2 Allegro's keyboard routines
---------------------------------

In your Allegro programs, you should call `install_keyboard()'
during initialisation.  Then you can use Allegro's keyboard
routines.

Most importantly, there is an array of chars called `key' which
has one element for each key on the keyboard.  It is indexed by
scancode (not ASCII code), and you can get the scancode for a
key using the `KEY_*' constants defined in `allegro.h'.  For
example, to see whether the space bar is currently down, test
whether `key[KEY_SPACE]' is non-zero.  You probably remember
seeing the input routine earlier on checking whether or not the
<ESC> key was pressed.

After installing Allegro's keyboard handler, the BIOS routines
won't work anymore.  This includes conio's `getch', stdio's
`getchar', `gets', `scanf' and anything else using stdin.
Allegro provides a replacement for `getch' called `readkey',
which waits for a key to be pressed and returns an integer
composed of its keyboard scancode and the ASCII value; to split
it up, you must do something like this:

     int value, scancode, ascii;
     value = readkey();
     scancode = value >> 8;
     ascii = value & 0xff;

Similarly, `keypressed' is a replacement for conio's `kbhit',
returning nonzero if there's a keypress in the input buffer.

See the Allegro documentation for more information.

6.1.3 Moving something using the keyboard
-----------------------------------------

There are several ways in which the game objects can respond to
the input.  For now we will make the objects move at a constant
speed in the direction the user indicates.  We'll discuss other
models later on.

So, what we require is something like this:

     if (key[KEY_LEFT]) x--;  /* if the user is pressing left arrow, go left */
     if (key[KEY_RIGHT]) x++; /* same for right */
     if (key[KEY_UP]) y--;    /* same for up; note that y _decreases_ to go up */
     if (key[KEY_DOWN]) y++;  /* and for down y _increases_ */

where `x' and `y' are the object's X and Y coordinates.

Try modifying the moving (single) circle program to allow the
user to move it around.  Try to fit your program into the
suggested structure, too.  Example program
`examples/chap_06/ex_1_3' demonstrates this.

6.1.4 Letting the user choose which keys to use
-----------------------------------------------

There are a few problems with using explicit `KEY_*' constants
in your games.  Generally the best use of the `key' array is
when you don't care what the key normally means.  If you ask
somebody to press the <Q> key then you should avoid using the
`key' array to test this, because the mapping of `KEY_*'
constants to physical keys is independent of the software
keyboard mapping.  `KEY_Q' refers to the key next to <TAB>, but
foreign and alternative keyboard mappings may not have the <Q>
key in that position.  This means that you can use the `KEY_*'
constants to choose control keys in comfortable layouts, but
you shouldn't use them if the symbol on the key is important
(e.g. Q for Quit).

Since the PC keyboard wasn't really designed as a game control
device, it cannot track all the keys independently.  It doesn't
even come close.  There are certain key combinations which, when
pressed, mask out other keys -- even when you have good
keyboard routines like Allegro's.  It's a hardware limitation.
Example `examples/chap_06/ex_1_4' is a simple program which
repeatedly prints a list of all keys currently flagged by
Allegro as pressed; run this and try holding down keys, until
you find that a keypress is not detected.  On my keyboard,
holding down <Z>, <X> and <C> together means pressing <F> goes
unnoticed.

Even more unfortunately, not all keyboards "clash" in the same
places.  So how are you supposed to choose keys for your game
if they might not work on all systems?

The answer is, of course, to allow the users to define their own
keys.  Then if there is a keyclash they can choose some other
keys.

To do this, you will want to replace the `KEY_*' constants in
your input routines with variables, which you can initialise to
some default values, and allow the user to change them if they
want to.  Naturally you shouldn't expect the user to know what
all the scancodes are; you should write a routine to check this
for them.

Using the `key' array this is fairly trivial; you simply cycle
from 1 to `KEY_MAX', the highest scancode, and note which key
is pressed.  Put this into your `userkey_left' variable, wait
for the user to let go of it, and then ask for a right key, and
so on.  It's safe to assume the first pressed key you find is
the only one; what stupid luser would press two keys together
when asked for a single key? :)

We'll see an example program that lets the user redefine the
control keys a bit later on.

6.2 Joystick input
==================

6.2.1 Digital readings
----------------------

Reading the joystick digitally is simple.  Make sure the user
has the joystick centred (i.e. tell them to centre it and wait
for them to acknowledge that they've done this), then call
`initialise_joystick()'.  Now whenever you want to read from
the joystick, call `poll_joystick()'.  This reads from the
joystick and, among other things, updates the global variables
`joy_left', `joy_right', `joy_up' and `joy_down', each
indicating whether or not the joystick is pushed in its
direction.

The input code example given in the keyboard section earlier
now becomes:

     poll_joystick();
     if (joy_left) x--;  /* if the joystick is pushed to the left, go left */
     if (joy_right) x++; /* same for right */
     if (joy_up) y--;    /* same for up; note that y _decreases_ to go up */
     if (joy_down) y++;  /* and for down y _increases_ */

Make sure, though, that the joystick is centred when you
initialise it, though.  The `initialise_joystick' function
returns zero only if there is a joystick present, so you could
check this, then ask the user to centre the joystick, and
finally call the `initialise_joystick' function again to update
the centre position.

Try modifying the previous example to read the joystick instead
of the keyboard.  If you get stuck, look at the example program
`examples/chap_06/ex_2_1'.

6.2.2 The fire buttons
----------------------

These are easy to read; the average joystick has two, and their
status is stored in `joy_b1' and `joy_b2', which go TRUE
(non-zero) when the buttons are pressed.  As with all of the
`joy_*' variables, they are only updated when you call the
`poll_joystick' function.  If you never call that function,
they'll always stay the same; you don't need to call it too
often, though.  Once per game cycle should be plenty, except
when you're checking the following...

Apparently, most joysticks do not have their fire buttons
debounced, so you should be aware that pressing a fire button
can cause several changes from `off' to `on' and back; this has
never caused me any problems but maybe my joystick just doesn't
suffer from this.  In most games where this is a problem,
setting a maximum fire rate will get around this anyway (i.e.
not allowing the user to fire a second time until, say, 20 game
cycles have passed). One thing bouncing can really mess up is
double-clicks on the joystick button; single presses may look
like two (or more) presses.  Note though that this is only an
issue if the time between joystick polls is very short.

Try modifying the digital joystick example to make the circle
change colour when the fire button is pressed.  Try to make it
only change once on each press (by waiting for the button to
release each time -- remember to poll the joystick inside your
waiting loop, otherwise the variables won't get updated).  If
the colours don't change in the right order, the button may be
bouncing; try to debounce it.  Now (harder) make it still let
you move the circle around while you're holding down fire.

Examples of all the above are in `examples/chap_06/ex_2_2';
look particularly at the technique used in the last case.

6.2.3 Analogue readings and calibration
---------------------------------------

[Note: this information is out of date.  It'll still work, but
needs updating for Allegro 4.]

The PC joystick is supposed to be an analogue device; in other
words, you can find out not only which way the stick is pointing
but also how far it is pointing in that direction.  However, as
Shawn points out in `allegro.txt':

     ...the exact results of this can vary depending on the
     type of joystick, the speed of your computer, the
     temperature of the room, and the phases of the moon. If
     you want to get meaningful input you have to calibrate the
     joystick before using it, which is a royal pain in the
     arse.

Calibration isn't really that hard, but it is a little
irritating to the user.  Most PC gamers are pretty used to
calibrating their joysticks by now, though.

The point about calibration is that the joystick routines need
to find out what range of values the joystick gives, in both the
X and Y axes.  Allegro does this using three functions:
`initialise_joystick', as mentioned before, marks the centre
values; `calibrate_joystick_tl' notes the values given when the
stick is in the extreme top-left position, and
`calibrate_joystick_br' does the same for bottom-right.

Again, normally you'll want to call `initialise_joystick' once
on startup, to see whether or not a joystick is present.  If
one is, and you later want to calibrate it, follow this
sequence:

  1. Ask the user to centre joystick, then wait for them to
     acknowledge (for example, by pressing a key)

  2. Call the `initialise_joystick' function to note the centre
     position

  3. Ask the user to push it to the top left and acknowledge

  4. Call the `calibrate_joystick_tl' function

  5. Ask the user to pull it to the bottom right and acknowledge

  6. Call the `calibrate_joystick_br' function

Now Allegro has everything it needs to know to be able to give
you analogue positions.  For aesthetic reasons it's a good idea
to now have the joystick returned to its centre position;
otherwise you might dive into something important with them
still holding it in the bottom right hand corner.  Either ask
them to centre it and acknowledge once again, or keep reading
it until they do (see below).

For an example of this in code, have a look at
`examples/chap_06/ex_2_3a'.

Having calibrated the joystick we can at last read its position
in more detail.  The variables `joy_x' and `joy_y' give its X
and Y positions, from -128 to 128, with (-128,-128) being the
top left corner, (0,0) being the centre, and (128,128) the
bottom right corner.

Have a go at modifying the circle-moving program to move the
circle at a speed relative to how far the stick is moved.
`examples/chap_06/ex_2_3b' demostrates this in case you can't
do it.  Note the `#define' near the start; it controls the
maximum speed for the circle, which corresponds to full
deflection of the joystick.  Using a `#define' or a constant
variable rather than just a number makes it simpler to change
the speed in the future.

6.3 Mouse input
===============

You can view the mouse in one of two ways -- either it is a
point-and-click device, or it is somewhat like an analogue
joystick, giving direct control over a character.

6.3.1 Point-and-click
---------------------

The point-and-click approach involves putting a pointer of some
sort on the screen, and making the mouse move it around.  When
a button is pressed you do something, depending on what the
mouse is pointing at.  Examples of this are WIMP GUIs (like
Windows), Dune 1 and 2, Warcraft 1 and 2, numerous front-ends
(menus), etc.  It is a very popular technique.

6.3.1.1 Initialising the mouse
..............................

To initialise the mouse, call `install_mouse()'.  As noted in
allegro.txt, this returns -1 on failure, or the number of
buttons on the mouse if it succeeds.

6.3.1.2 Reading the mouse
.........................

Now you can get the mouse pointer's X and Y coordinates using
the variables `mouse_x' and `mouse_y' (which should be screen
coordinates) and the button status is in `mouse_b', which is a
bit field like this:

     Bits:  2 1 0
            . . X = left button flag
            . X . = right button flag
            X . . = middle button flag

The remaining bits are unused at present.  The three button
flag bits are set if the corresponding button is pressed, clear
if not.  If there is no middle button, its flag bit is always
clear.

So, to read each button you bitwise-AND (&) `mouse_b' with 1, 2
or 4 like so:

     if (mouse_b & 1) printf ("Left ");
     if (mouse_b & 2) printf ("Right ");
     if (mouse_b & 4) printf ("Middle ");
     printf ("\n");

Note though that the value of `mouse_b' can (and does) change
`behind your back'; the following sort of test might give
strange results:

     if (mouse_b) {
         printf ("Buttons pressed: ");
         if (mouse_b & 1) printf ("Left ");
         if (mouse_b & 2) printf ("Right ");
         if (mouse_b & 4) printf ("Middle ");
         printf ("\n");
     }

Imagine what happens if initially one of the buttons is pressed,
so that the `if' condition passes, but then the button is
released; the string "Buttons pressed:" will be printed, but
since now none of the buttons are pressed neither "Left" nor
"Right" nor "Middle" will be printed.

If this sort of oddity could be a problem, you can take a copy
of the `mouse_b' variable and work from that; this is a bit
like polling the joystick, in a way.

     my_mouse_b = mouse_b;
     if (my_mouse_b) {
         printf ("Buttons pressed: ");
         if (my_mouse_b & 1) printf ("Left ");
         /* etc */
     }

6.3.1.3 Displaying the mouse pointer
....................................

To show the pointer on the screen, you simply call the function
`show_mouse', telling it which bitmap to draw onto, for example:

     show_mouse (screen);

Whenever the mouse is moved, Allegro will update the mouse
pointer (unless you've told it not to -- see the Allegro
documentation).  Because of this, you have to hide the mouse
before writing anything to the bitmap it is shown on, otherwise
Bad Things happen to the display.  To do this, call
`show_mouse(NULL)'.

Note, though, that the functions which actually draw the mouse
pointer require Allegro's timer routines to be installed (as do
several other Allegro components) -- that's (partly) how they
manage to do things in the background.  See Timers, and
in particular Initialising the timer system, for more
information.

6.3.1.4 Controlling the mouse pointer
.....................................

If you need to adjust the range of the mouse, you can call:

     set_mouse_range (min_x, min_y, max_x, max_y);

where `min_x' and `min_y' are the minimum X and Y values, and
`max_x' and `max_y' are the maximum values.

If for any reason you want to move the mouse pointer to a
certain location on the screen, call the function
`position_mouse', passing the new X and Y coordinates of the
mouse.

The example program `examples/chap_06/ex_3_1' demonstrates the
point-and-click mouse.

6.3.2 Direct mouse control
--------------------------

This technique involves, at each game cycle, seeing how far the
mouse has moved in each direction and treating this in the same
way as analogue joystick data.  Examples of games that do this
are:

   * All of id Software's recent games -- e.g. Wolfenstein 3D,
     and all of the Doom, Heretic and Quake games.

   * Other first person perspective shoot-'em-ups.  Well, id
     Software deserved to have a class to themselves since
     (until recently, at least) they have always excelled at
     creating gameplay and atmosphere.  Examples here: the
     Descent series, Duke Nukem 3D, Dark Forces.

   * Flight simulators -- e.g. Jetfighter II, the Wing
     Commander games, X-Wing, Tie Fighter, etc.

I don't think it's a coincidence that this list contains only
first person perspective games (i.e. games where the display is
from the player's point of view).  That's not to say that this
method can't work well for other games; I think it's more
obvious when this type of game benefits from it.

When using this system, you initialise the mouse in the same way
as for the point-and-click system (see Initialising the mouse.).

To make this sort of control system you ask the mouse driver for
a mickey update.  A "mickey" is a very fine measure of mouse
movement, and is given relative to last time you asked.  Allegro
provides the `get_mouse_mickeys' function to do this:

     void get_mouse_mickeys (int *mickeyx, int *mickeyy);

Pass this function two pointers to `int' variables, and it will
fill the variables pointed to with the change in the mouse's X
and Y positions since the last call to this function.  For
example, if `dx' and `dy' are `int' variables,

     get_mouse_mickeys (&dx, &dy);

will put the mickey differences into `dx' and `dy'.  Note that
the units are not the same as the units of `mouse_x' and
`mouse_y' -- the mickey is a much smaller unit.

The example for this section, `examples/chap_06/ex_3_2', uses
this technique to move our wonderful circle around by tying the
mouse movement to acceleration.  As [ed: will be] discussed
below, this is a common model for more realistic games,
effectively linking mouse movement and force applied to the
object.  You ought to take a look at this example, just to see
how it works.

6.4 Generic input
=================

Given all the above input types, we have written several
programs allowing us to control things with each.  However, how
can we write a game which allows the user to use whichever
device they want to?

We could write versions of the reaction code to interpret each
type of information, and only use the ones corresponding to the
user's choice of device, but it would be better to minimise the
number of links between our input routine and the reaction
routine.  The example in `examples/chap_06/ex_4' shows a way of
doing this; I suggest you refer to it while reading this.  Look
in particular at `input.c' and `input.h'.

We need a common format for the data which is sent to the
reaction routines. We need information about how far the input
device is in each direction, and information about the status
of any fire buttons.  I created this struct to hold the
information:

     struct input_t {
         int dx, dy;
         int fire1, fire2;
     };

Let's define `dx' and `dy' to be from -128 to 128, as in the
joystick routines, indicating which direction the device is
pointing and how much.  `fire1' and `fire2' will be non-zero
when the fire button in question is pressed.  We're limited to
two, because most joysticks only have two; it's often sensible
to aim for the lowest common denominator when writing code to
work over a variety of systems or configurations.

The input routine will need to fill in the information required
every time it is called.  For joystick input, this is simple;
just copy the values across, since the magnitudes match up.  If
the joystick is digital, though, we should check `joy_left',
`joy_right', etc, using the same system as for the keyboard,
which follows.

For the keyboard, we will need to work out where it is
"pointing'".  Given a `left_key' and a `right_key', we can work
out the "rightness" as follows:

     rightness = (key[left_key] ? -1 : 0) + (key[right_key] ? 1 : 0);

Think about what this means in each situation:  If neither key
is pressed, both brackets are zero and it returns 0.  If both
are pressed, the first bracket given -1 and the second gives 1;
so it returns 0 again.  If only left is pressed, the first
bracket gives -1 and the second gives 0, so it returns -1, and
if the right key is pressed it returns 0+1, which is 1.  Now we
can adapt this to fit our structure by saying:

     dx = (key[left_key] ? -128 : 0) + (key[right_key] ? 128 : 0);
     dy = (key[up_key]   ? -128 : 0) + (key[down_key]  ? 128 : 0);
     fire1 = key[fire1_key];
     fire2 = key[fire2_key];

Hence any keyboard input is always like full deflection of the
joystick.

As for the mouse, we'll use the direct control method; if we
wanted a point-and-click interface we would be pretty much
dependent on the user using a mouse.  You could use these input
routines to simulate that system with any input device, but we
won't go into that here.

To map the `dx' and `dy' from the mouse code onto the range
[-128,128] that we are using here, we need to divide by
`max_mousespeed' and multiply by 128, where `max_mousespeed' is
a variable controlling the sensitivity of the mouse.  We will
do this the other way around, though, because then we can leave
it as an integer calculation.  Where possible, you should avoid
casting between floating point types and integer types -- it's
slow to convert between them.

The complete code for what we have discussed so far is in
function `input_getinput'.

Before we can use that, though, we need a way of telling this
input module what sort of input we're looking for.  This will
be by a call to `input_create_*', which may take some
parameters (depending on what `*' actually is), make an input
structure, and return a pointer to it.  The joystick input
routine doesn't need any extra information, but the mouse input
routine needs to know what value to use for `max_mousespeed',
and the keyboard input routine needs to know which keys to use.
We could have used a single function with a variable number of
parameters, but that's a bit complicated for this tutorial.

So we define these functions:

     input_t *input_create_joystick ();
     input_t *input_create_mouse (int max_mousespeed);
     input_t *input_create_keybd (int left_key, int right_key,
                                  int up_key, int down_key,
                                  int fire1_key, int fire2_key);

We also need a function to initialise the input module, a
shutdown function for it, and a function to destroy
previously-registered input devices (e.g. if you change the
keys); we'll prototype these:

     void input_init ();
     void input_shutdown ();
     void input_destroy (input_t *what);

In summary, programs will call `input_init' initially, to set
up the module.  They will then call some of the
`input_create_*' functions to register input devices for the
players; the `input_create_keybd' may be called more than once,
with different keys, to allow for more than one player on the
keyboard.  The `input_create_*' functions return pointers to
`input_t' structs, whose fields will be updated on each call to
`input_getinput'.  Registered devices can be unregistered using
`input_destroy' by passing the `struct input_t' pointer; this
will also deallocate the structure pointed to.  The
`input_shutdown' function will unregister all devices and
deallocate any memory still allocated.

The input_t struct contains fields `dx', `dy', `fire1' and
`fire2'.  `dx' and `dy' range from -128 to 128, indicating the
amount of movement in each direction, and `fire1' and `fire2'
are non-zero if the corresponding fire button is pressed.

Once again, see the program in `examples/chap_06/ex_4' for an
example of how to use this system.

6.5 Ways of interpretting input
===============================

This section isn't written yet.  When it is written, it will
contain information about physical models (no, it's not as
boring as it sounds!) and how you can use the input data.

7. More 2D graphics
*******************

This section isn't written yet.  When it is, it will talk about:

   * memory bitmaps

   * sprites

   * moving things without disturbing the background

   * double buffering and dirty rectangles again, and
     introducing page flipping

8. Sound
********

8.1 Sound configuration
=======================

8.1.1 Initialising sound drivers
--------------------------------

To install the sound drivers, you call the function:

     install_sound (digi_driver, midi_driver, NULL);

putting a `DIGI_*' constant in place of `digi_driver' and a
`MIDI_*' constant in place of `midi_driver'.  The third
parameter is obselete and you should just pass NULL.

The function returns zero if it was successful.  A non-zero
return probably means that the driver you requested is not
available.  If you used a `*_AUTODETECT' setting for either
driver, this may mean that a config file specified a precise
driver to use, and that driver was unusable.

I think there's rarely any good reason not to use
`DIGI_AUTODETECT' and `MIDI_AUTODETECT'.  My reasoning here is
that if you specify a device explicitly the game won't work if
that device is not available, and won't be able to make use of
a better device if one is available.  Even if you have some
hardware conflict which makes these options fail normally,
that's no reason to stop your game working properly on other
people's machines -- you should create a configuration file
(see below).  Config files always override the autodetection
routines, so the conflict should disappear -- you're relying on
this to be true so that the end-users can fix such problems if
they occur.  If you hardcode values here people won't be able to
override the settings without rebuilding -- bad news!

So unless there's a very good reason (I can't think of any) just
use the `*_AUTODETECT' constants here.  Even the `play.exe'
example program in Allegro's tests directory is borderline in
my mind -- it uses a hardcoded table of driver numbers and
names.  That's pretty bad; the justification (I think) is that
its purpose is to test drivers quickly.  Not much justification
really...

One further thing to note is that the MIDI player uses Allegro's
timer routines to operate, so you must initialise those before
you'll be able to play MIDI files.  See Initialising the timer system,
for more details.

8.1.2 Using a configuration file
--------------------------------

Allegro supports a wide range of features in config files; sound
configuration is just part of the standard data, and you can add
data of your own for your game's internal use.  For full details
on using config files, see Allegro's help system (type `info
allegro config' at a DOS prompt, if you use Info).  Here I'll
only mention what applies to the sound drivers.

Unless you say otherwise, the files `allegro.cfg' and
`sound.cfg' will be checked for in the program's home
directory.  To specify a different filename, pass it to the
`set_config_file' function.

The sound configuration information is in the `[sound]' section
of the file, and holds information about which drivers to use
if you ask for autodetection and the settings for those
drivers, among other things.  The way the autodetection works in
Allegro is such that if you specify a driver explicitly in the
config file then that driver will be used.  If you don't specify
one then Allegro will start poking around trying to see what's
there; this _may_ have adverse effects, and in addition some
things (like an external MIDI device) are never autodetected
for technical reasons.

The safest and easiest way to write config files is through the
setup utility.  This is designed to be packageable with your
games, and lets the user choose some settings (or autodetect
them) and try them out.  It then saves the settings to a config
file ready for your program to read.

The simplest way to distribute this, then, is to put the
`setup.exe' file in the same directory as your program's
executable, so that the output from the setup program is right
where your program expects to see it.  There are many things
about the setup program that you can customise; or you can just
leave it alone.  See `setup.txt' for full information (it's in
the same directory as the rest of the setup program).

8.2 Digital sound
=================

8.2.1 Loading sound files
-------------------------

Allegro can read digital samples from WAV and VOC files.  Both
types of file must be mono.  WAV files can be 8 or 16 bit; VOC
files must be 8 bit.

Loading a sample couldn't be easier -- you pass the filename of
the WAV or VOC file (it must have the right extension) to the
`load_sample' function, and it returns a `SAMPLE *' which you
can use to refer to the sample, or NULL if it could not load
the sample (e.g. it didn't recognise the extension, the file
was not found, or the format of the file was incorrect or not
supported).

You can also call `load_voc' or `load_wav' directly, in the
same way.  The benefit of doing this is that if the file does
not have a .WAV or .VOC extension it will still be processed.

8.2.2 Playing samples
---------------------

Allegro's digital sound player can manipulate samples in several
ways whilst playing them.  The parameters you can set at the
basic level are the volume, pan and frequency.  You can also
tell the sound player whether or not to loop back to the
beginning of the sample when it reaches the end.

To start a sample playing, call the play_sample function.  You
pass the following parameters:

   * the sample to play (a `SAMPLE *')

   * the volume of the sample, from 0 (min) to 255 (max)

   * the pan position of the sample, from 0 (left) to 255
     (right)

   * the frequency of the sample relative to its original
     frequency -- 1000 would play it at the original frequency,
     2000 would double that frequency (raise the pitch by one
     octave, musically speaking) and 500 would halve the
     frequency (lower the pitch by one octave)

   * a loop flag; 1 = loop, 0 = don't loop

Note that offsetting a sample's frequency can introduce
distortion of the sample -- Allegro is a game programming
library, not a sophisticated audio suite.  Also, playing sounds
at generally low volumes but with your stereo system's volume
knob turned right up will also introduce distortion, not to
mention noise ;).  Try to use the full range of volume values,
and also use samples which internally use the full range of
values, if possible.

A typical call to play_sample, then, would be:

     play_sample (gun_sound, 255, 128, 1000, 0);

which plays `gun_sound' (previously loaded as above) at full
volume, centre pan, and its original frequency, without looping
it.

     play_sample (some_sound, 192, 96, 1200, 1);

would play `some_sound' at 3/4 volume, panned slightly left, a
little above its normal pitch, and set it to loop back to the
start each time it reached the end.

To stop a sample playing, use the `stop_sample' function:

     stop_sample (gun_sound);

This is especially useful on looped samples.

8.2.3 Adjusting a playing sample's parameters
---------------------------------------------

You can also adjust these parameters while a sound is playing.
To do this, you call `adjust_sample'.  It takes the same
parameters as `play_sample', and searches through the list of
playing samples for the one you pass.  So if `some_sound' is
still playing from above, we could make it stop looping like
this:

     adjust_sample (some_sound, 192, 96, 1200, 0);

We could also have changed some of the other parameters, of
course.  If you want to adjust samples while they're playing,
avoid playing more than one copy of the sample at a time --
`adjust_sample' will only change the first sample it finds, so
the others will carry on the way they were.

For a more sophisticated way to play and control samples, which
does not suffer from the above problem, see Voice functions.

8.2.4 Unloading samples
-----------------------

When you have finished with a sample you can unload it from
memory using the `destroy_sample' function like this:

     destroy_sample (some_sound);

If the sample is playing at the time, it will automatically be
stopped.

8.2.5 Voice functions
---------------------

This section has not yet been written.  It will contain
information on using the voice functions directly to gain more
control over sounds.

There is an example program though: `examples/chap_08/ex_2_5'

8.3 MIDI music
==============

8.3.1 Loading MIDI music
------------------------

At present Allegro supports only MIDI music, which it can load
from type 0 or type 1 (i.e. most) .MID files.

To load MIDI files you pass the filename to the `load_midi'
function, which returns a `MIDI *', or NULL if it's not
successful.

8.3.2 Playing MIDI music
------------------------

To start a MIDI object playing you simply call `play_midi':

     play_midi (title_theme, 0);

The second parameter is a loop flag; 0 means no looping,
anything else causes the file to loop back to the start when it
ends.  If you want your file to loop at other positions (for
example, if it has an introduction you might want it to skip
that when it loops) you can call:

     play_looped_midi (background_music, loop_start, loop_end);

When position `loop_end' is reached the player will jump back
to `loop_start'.  If `loop_end' is -1 the end loop point is the
very end of the music.  The units for `loop_start' and
`loop_end' are beats, as measured by the `midi_pos' variable
mentioned below.

In either case you can stop the music by calling `stop_midi':

     stop_midi();

Since Allegro can only play one piece of music at a time this
function needs no parameters.  Starting a piece of music while
other music is already playing will stop the first piece
immediately.  Calling the `stop_midi' function has the same
effect as calling `play_midi' with a NULL first parameter.

8.3.3 Controlling MIDI music
----------------------------

While a MIDI file is playing, Allegro increases the global
variable `midi_pos' once per beat.  If there is no MIDI file
playing (or a non-looped file has finished) it will be set to
-1.

Note that it won't necessarily increase on every beat -- if the
music doesn't play a note on the beat, it won't be updated until
the next note is played.  If you want to synchronise events with
this you need to make sure there's a note on the beat; you could
put in a zero volume note, for instance, just to trigger the
event.

You can pause and resume playback using the `midi_pause' and
`midi_resume' functions.  You can jump to a certain position in
the file by passing the target `midi_pos' value to the
`midi_seek' function.  Be aware that seeking backwards involves
rewinding the file to the beginning, and then seeking forwards;
consequently doing a lot of small reverse seeks isn't a good
idea.

Lastly, if the file is looping you can change its loop points on
the fly.  The two variables are `midi_loop_start' and
`midi_loop_end', and are measured in `midi_pos' units.  A value
of -1 for `midi_loop_start' or `midi_loop_end' indicates the
start or end of the file, respectively.

I mentioned earlier that you might have some music with an
introduction that you don't want to loop every time, and the
`play_looped_midi' function can solve that problem; adjusting
the loop points can allow you to do a similar thing if the
piece has an ending that you don't want to play while it's
looping -- i.e. you want to play the introduction once, then
loop the main body of the music a few times, and finally play
the ending.

To do this you'd start the music using the `play_looped_midi'
function, passing the position of the start of the main part of
the music as the loop start parameter and the position of the
end of the main part as the loop end parameter.  Then you'd let
the music play; it will loop each time it reaches the loop end.
Later on you'd then set the loop end parameter to the end of
the music.

There are a few caveats though:

   * `midi_loop_start' must always be earlier in the file than
     `midi_loop_end'; if your new start value is greater than
     the old end value then you must alter the end value first,
     and if your new end value is less than the old start value
     then you should alter the start value first.

   * Excepting the above, it's generally better to change
     `midi_loop_end' before `midi_loop_start' if the end point
     is moving later in the file, and to change them the other
     way around if the end point is moving earlier in the file.
     This reduces the possibility of extra skipping during the
     change.

The chances of either of the above being a serious problem are
pretty small, but it's better to be safe than sorry.  The
second one is purely cosmetic.

8.3.4 Unloading MIDI music
--------------------------

To unload a MIDI file use the `destroy_midi' function:

     destroy_midi (background_music);

If it's playing at the time, the music will be stopped first.

9. Timers
*********

9.1 Uses of timers
==================

This is a list of some uses of timers.  Of course it's not
complete -- it's just meant to give you some idea of their most
common uses.  Some or all of these will appear as examples
later on.

   * Timing a game

     This is probably the most obvious use.  You can use a timer
     to count how long a player has been on a level, perhaps to
     give them a bonus later for completing it quickly, or to
     kill them for taking too long.

   * Counting a game's frame rate

     If you increase a global variable each time you draw a
     frame to the screen, you can set up a timer to copy this
     value elsewhere once per second.  The place to which it is
     copied will then show the number of frames drawn in the
     previous second -- in short, it's the FPS (frames per
     second) number, or frame rate, of the game.  This is very
     useful when you're finding out how well your game runs on
     other people's systems; if the number is high, they are
     getting smooth graphics; if not, the graphics are more
     jerky.

   * Regulating game speed

     Earlier you may remember that we briefly tried using a
     constant delay when moving a circle across the screen,
     then switched to using `vsync' to control the speed.

     The former system is fatally flawed in that the speed of
     the circle still depends on the speed of the computer --
     if we delay 10 ms between draws, and the draws take 5 ms,
     we'll have one draw every 15 ms; but if the draws take 10
     ms, we'll only have one every 20 ms.  So much for speed
     regulation.

     Using `vsync' is better; the vertical blanking intervals
     occur at regular intervals, so provided our drawing and
     movement always takes less time than a full retrace (or
     more accurately, always takes the same number of retraces
     to complete) we'll get a constant speed.  If we take a bit
     too long on the occasional frame, the game will seem to
     stop for a fraction of a second, because `vsync' will have
     missed one VBI and will have to wait for the next one.
     This actually happens quite a lot under some
     semi-multitasking operating systems when the OS takes
     control of the computer just before the VBI -- `vsync'
     then misses that VBI and, again, waits for the next one.
     The effect is pretty severe (the game seems to jerk a lot,
     and worst of all (IMHO) it loses time).

     The better system is to use a timer to keep the game
     running at a constant speed.  The video updates must still
     be controlled by `vsync', to reduce flicker, but our timer
     can effectively see exactly how long `vsync' had to wait,
     and we can make up for the delay by running through the
     game logic an appropriate number of times later on.

     We'll look at exactly how this is accomplished after
     seeing how timers themselves work.  Or you can skip
     straight to that section now -- it's up to you.  See
     Regulating game speed.

   * Getting input at regular intervals

     If we set up a timer running frequently we can get input at
     regular intervals.  So what?  Well, some game systems (such
     as the one described above) tend to run through the game
     loop several times in a row, then go into a long graphics
     updating routine.  They spend a great deal of their time
     updating graphics, and rush through a number of game
     updates very quickly when that's finished.  If we're
     reading the input state exactly when the game update is
     occuring, we'll get just about the same input state for
     all of the updates.

     As an extreme example, imagine that the graphics routine
     took a whole second to complete, and the game update
     routine was then executed say 10 times, to make up for it.
     If the user tapped a key during the graphics routine's
     execution, or even held it down for most of the period,
     the game update routine wouldn't notice, because it would
     only be checking for input at the end of the graphics
     routine.  But if the user just tapped the key at the end
     of the graphics routine, all 10 of the game's updates
     would see the key as being pressed, which is bad too.
     What we want is for each game update to see a different
     input state, taken from samples occuring at regular
     intervals.

9.2 Setting up timer callbacks
==============================

9.2.1 Initialising the timer system
-----------------------------------

Before you can use any of the timer functions, you must
initialise Allegro's timer system.  As noted earlier on, many
other parts of Allegro need this anyway, so perhaps you have
already initialised it.  These other components include the
mouse pointer updating code and the MIDI player.

To initialise the timer system, just call:

     install_timer();

After making this call, the libc `delay' function will no
longer work; you should use Allegro's `rest' function, which
operates in almost the same way.

9.2.2 Locking and volatility
----------------------------

Allegro's timer routines are driven by interrupts.  These are
generated on certain events, and "interrupt" the execution of
your program.  At this point, the CPU starts running the code of
an ISR (interrupt service routine).  Allegro hooks itself in
here in various ways so that it is informed whenever certain
interrupts occur -- in this case, the timer interrupt.

Allegro's timer interrupt handler calls various functions you
specify, called "callbacks", at certain intervals (which you
also specify).  The key point is that these callbacks are called
"inside" an interrupt.

For various technical reasons, it's a very bad idea to try to
page things to and from disk during an interrupt.  This means
that you must ensure that your callbacks are never paged out to
disk -- if they were, they'd need paging back in during the
interrupt.  You must also ensure that any data they touch --
global variables, etc -- is never paged out to disk.  You do
this by "locking" the memory in which they are located.  Some
functions are provided by djgpp to do this, and Allegro
provides some nicer wrappers for them in the form of the
following macros:

     END_OF_FUNCTION (function_name);
     LOCK_FUNCTION (function_name);
     LOCK_VARIABLE (variable_name);

`LOCK_VARIABLE' locks a static or global variable and
`LOCK_FUNCTION' locks a function.  `LOCK_VARIABLE' can work on
its own, but `LOCK_FUNCTION' needs you to mark the end of the
function in question using `END_OF_FUNCTION'.  If you forget
the `END_OF_FUNCTION' you'll get some odd-looking (but fairly
self-explanatory) compiler warnings and linker errors.

The other issue that comes up when dealing with interrupts is
volatility.  Any decent compiler will try to optimise the code
it generates.  In doing so, it will normally assume that if you
don't write to a variable then its value won't change.  Normally
this is true, but if there's an interrupt-called function that
modifies the variable then the variable's value might change
without the compiler noticing.  To solve this problem you must
mark all such variables as being "volatile".  `volatile' is a
keyword in the C language that directs compilers to make no
assumptions about the contents of the variable -- in particular,
it will never cache the variable's value in a register.

You don't want to make all of your variables volatile, of
course.  If you did this you'd be restricting the compiler's
ability to optimise your code, and would probably end up with
slower code.  Try to only make variables volatile when they're
written to or read from in an interrupt context (that is,
inside a timer routine or other interrupt callback).

9.2.3 Installing timer callbacks
--------------------------------

When you've initialised the timer system, locked your callback
and any data it touches, and marked any such data as
`volatile', you can at last tell Allegro to call it.

     install_int (callback, msecs);

Replace `callback' with the name of a function returning void
that takes no parameters (in C) or a variable number (in C++).
`msecs' is the time between calls to your function.

Here's an example function for C:

     volatile int counter = 0;      /* We'll increase this in the callback,
                                       so it must be volatile. */
     void my_callback_func()
     {
         counter++;                 /* Nice and simple */
     }
     END_OF_FUNCTION (my_callback_func);   /* Note the syntax here */

Note that the callback function must be very simple.  It must
not take a long time, it must not call any C library functions,
it must not do anything fancy like calling DOS routines.  If it
calls Allegro routines, they must be reentrant ones that obey
these same rules.

If we were using C++, we'd have to change the function
definition to:

     void my_callback_func(...)

otherwise we'd get an error.

Next, here's the code we'd use to lock the things mentioned
above:

     LOCK_FUNCTION (my_callback_func);    /* Lock the function */
     LOCK_VARIABLE (counter);             /* It touches this variable,
                                             so we lock it too. */

Finally, the following line asks Allegro to call our function
ten times per second (once per hundred milliseconds):

     install_int (my_callback_func, 100);

Note that even though `my_callback_func' is a function, we
don't write parentheses (`(' and `)') after its name -- if we
did, the function would be called and its (non-existant) return
value would be passed to `install_int'.  We're passing the
entry point of the function to `install_int', so we don't write
the parentheses.

Incidentally, you can call `install_int' again later on to
change the rate of calls to the function.

For more control over your callback functions, you can use the
`install_int_ex' function.  The parameter to this function is
given in hardware ticks, but you can use some macros to convert
to this format from more useful units -- seconds or
milliseconds per call, or calls per second or minute.  See the
Allegro documentation for this function for full details, and
more information on what timer callbacks should and should not
try to do.

9.2.4 Removing timer callbacks
------------------------------

Removing timer callbacks is simple -- just call this function:

     remove_int (my_callback_proc);

In theory, you could now unlock the memory of the function, but
in practice there's little point.

9.3 Limitations of timers
=========================

Listed here are some things you should and should not do when
writing and using timer callbacks (and interrupt callbacks in
general).

Do:

   + Do lock all memory your callbacks touch -- lock the
     callbacks themselves and also any variables they use.  If
     they call other functions, you must lock those too, as
     well as anything they touch; if those call other
     functions, you must lock them too, etc.

   + Do make used variables volatile.  If you don't do this,
     strange things will happen.  There won't be any
     compile-time warnings or errors, and there won't be any
     specific ones at run-time either, but you'll find that
     your program doesn't do what it should do.  A typical
     symptom of this is having a loop that waits for a variable
     to be changed by a timer, and seeing this loop never
     terminate.

Don't:

   - Don't call DOS functions inside your callbacks.  DOS is
     not in general reentrant, and this causes big problems
     under most circumstances.

   - Don't call C library functions -- unless you really know
     what you're doing.  C library functions might call DOS,
     and as mentioned above that's normally a very bad idea in
     an interrupt context.

   - Don't do anything too fancy.  Your callbacks should
     execute very quickly.  Just because they're executing out
     of the main flow of the program, it doesn't mean they
     aren't burdenning the CPU.  The longer your callback takes
     to run, the less CPU time is being spent on your
     mainstream code.  It's no coincidence that all the examples
     below just modify a few variables then quit -- that's the
     sort of level you should think on.  Set some variables,
     then let your mainstream code do the hard work.

   - Don't ask to have your callbacks called more frequently
     than you need.  Note that under Windows the time between
     calls must be a multiple of 5 milliseconds; consequently
     if you want your game to work reasonably well in a variety
     of operating systems you should definitely keep your times
     multiples of 5 milliseconds.

   - Don't install too many timer callbacks.  There are a
     limited number (16) and keep it in mind that Allegro needs
     some of these for itself.

9.4 Examples of timers
======================

9.4.1 Timing a game
-------------------

This one's fairly simple.  We set up a global variable to
contain the number of seconds elapsed.  We make our timer
callback, which increases that number.  We lock the counter and
the callback routine.  Then, when we want to start timing we
install the callback routine to be called once per second.
After that we can read from the (volatile!) counter variable to
find out how much time has elapsed.

When the period we're timing has ended, we can either take a
copy of the counter, or just remove the callback.  If we do
remove it, the counter won't be changed any more.

As a variation, we could implement a time limit.  In this case
we'd set the counter to the number of seconds allowed (for
example, to complete a level).  The callback would now be made
to decrement that value.  In the main game loop we'd check on
each cycle whether or not the counter is positive.  If it's
not, the player has run out of time.  At this stage we ought to
remove the callback routine, to stop the number decreasing
further.

See `examples/chap_09/ex_4_1'.

9.4.2 Measuring the frame rate
------------------------------

This, too, is pretty simple.

First of all, we make two volatile global variables -- one
called `last_fps' and the other `frame_counter'.  Then we make
a timer callback that simply copies `frame_counter' to
`last_fps' and then sets `frame_counter' to zero.  We now lock
both variables and the timer callback, then install the callback
to be executed once per second.

Now we can display the variable `last_fps' on the screen
somewhere, or log it, or do what we like with it.  At the
moment it will be zero.  All we need to do to make it count the
frames in each second is to make our graphics routines
increment the `frame_counter' variable once per frame.

This works because the callback routine is called every second,
and it copies the value into `last_fps', zeroing
`frame_counter'.  Next we draw some frames, and as we do so the
`frame_counter' variable increases.  One second after its
previous call, the callback is called again, and it copies the
number of frames drawn in that second from `frame_counter' to
`last_fps'.

See `examples/chap_09/ex_4_2'.

9.4.3 Regulating game speed
---------------------------

This topic is my nomination for FAQ of the year on the Allegro
mailing list.  It's very important.  Games that do not run at
the same speed on different computers or under different
circumstances annoy me.  I don't mean that the frame rate should
be the same on all computers -- that's not possible, of course.
I'm referring to the actual game speed -- the rate of movement
of the game characters, for instance.

To make this happen, you want ideally to move the characters at
regular intervals.  Inside a timer callback?  No way.  That's
far too complicated; remember, timer callbacks must be simple.
Besides, think how much of a problem it would be to try to lock
everything touched by such a callback!

The best thing we can do realistically is to make a timer
increment a variable, which holds the number of game cycles
which _should_ have elapsed by now.  Then we can make the game
loop compare this to the number of game cycles which really
have elapsed.  If we're behind target, we need to call the game
logic function one or more times, until we're back on target.
If not, we don't need to do any more game cycles at the moment.

If we are up-to-date then we can go off and do other things,
like display a frame of graphics.  Displaying graphics is often
a slow process, partly because it's just a slow thing to do and
partly because it often involves waiting around for the VBI,
using `vsync'.  While we're drawing graphics, and waiting for
the VBI, our timer callback will still be called at the right
intervals.  We won't be dealing with that immediately, of
course; it will have to wait until after we've done the
graphics.  But when we have done the graphics, we know exactly
how many game updates we need to do to get back on target.

So, in summary, we set up two counters -- one being increased
at a constant rate (the target game cycle rate) by a timer
callback, and the other being increased once per actual game
cycle, by the function that performs a game cycle.  Initially
these counters start at zero.  On every pass through our main
game loop, we first draw a frame of graphics.  This will take a
relatively long time, in most games.  Then we test whether the
target game cycle is greater than the actual game cycle (it
probably is), and if so we keep doing game cycles until it is no
longer the case.  Then we loop again.

See `examples/chap_09/ex_4_3'.

10. Datafiles
*************

The file `grabber.txt' in the `tools' subdirectory of Allegro
gives a good description of almost every aspect of datafiles.
If any point mentioned here is unclear, or if you want more
information on something not covered fully here, that is the
place to look.

10.1 Concept
============

By now you can see that a game can require many different
files; there is the executable file the users run, then there
are the graphics, which could be in several large files with
many graphics on each, or could be each in its own file (I tend
to use the former approach).  We also have the sound effects
(one file for each) and the music (one file for each piece).

That's just the generic files that nearly all games need.  On
top of that, each game may have other files describing for
example level designs, enemy AI, or other data needed.  In
total there can be a large number of files.

Due to clustering arrangements under DOS, each file must be
stored in a number of blocks of a certain size.  On partitions
of just under 1Gb these "clusters" are about 16K each.  Most
files won't fully fill their last cluster, and so the remaining
space in it is wasted -- on average, assuming evenly
distributed file lengths, this would be 8K per file, but it's
probably more in practice.  This wasted space can mount up,
especially if you store many files which are much smaller than
even one cluster.  If you have Windows 95, try typing `dir
/s/v' in your `djgpp\zoneinfo' directory, and comparing `bytes'
to `bytes allocated'.  After doing this you might consider
deleting the contents of that directory, or at least zipping it
up -- you probably don't need it.

Having many files with `.PCX', `.WAV' or `.MID' extensions also
encourages people to `borrow' them for their own purposes, or
modify them, changing the game.  If you don't want them to do
this, it's wise not to leave those files lying around.

Quite apart from the above two reasons, it's just messy to have
all those files stored `loose', and your game will need to load
them all when it starts.  Datafiles provide a way of packaging
all or some of your files into one big datafile, which can be
loaded all at once, optionally compressing and encrypting the
data at the same time.

10.2 Creating a datafile
========================

Datafiles are created from files on disk.  There are two main
utilities provided with Allegro to handle them: the Grabber and
the DAT utility.  They are both well documented in the file
`grabber.txt', in the `tools' directory of Allegro, but I'll
give brief instructions here too.

10.2.1 The grabber
------------------

(not yet written)

10.2.2 The DAT utility
----------------------

(not yet written)

10.3 Using a datafile in your program
=====================================

There are a number of ways you can read back the data from a
datafile.  Firstly, you can read in the whole datafile, all at
once.  Secondly you might want to read one component of the
datafile on its own.  Lastly, you can open a component of the
datafile as if it were a normal file.

10.3.1 Loading an entire datafile
---------------------------------

This is the obvious way to do things.  With this system, you
issue just one function call and Allegro loads in all the
objects you put in the datafile.  The function to call for this
is `load_datafile':

     DATAFILE *load_datafile (char *filename);

You pass it the filename of your datafile, and it returns a
pointer an array of DATAFILE structs, one for each object.  So
if `data' is a `DATAFILE *' and you write:

     data = load_datafile ("datafile.dat");

then `data[0]' will be the first object in the datafile,
`data[1]' the second, etc.

The most important field in the DATAFILE struct is the `dat'
field.  It is a pointer which points to the actual data for the
object.  If the object was a bitmap, then this field will point
to a BITMAP struct -- so you could write:

     blit (data[0].dat, screen, ...);

If the object is a sound sample then this is a SAMPLE struct:

     play_sample (data[1].dat, 255, 128, 1000, 0);

The same is true for MIDI files, palettes, animations and a few
other things.  In the grabber or dat utility you can see what
type of data each object is just to the left of the object name
in the list (type `dat -l <filename>', or look at the left side
of the grabber screen).

You can also tell what type of data each object holds by its
`type' field.  This will be set to a constant like
`DAT_BITMAP', `DAT_SAMPLE' or `DAT_MIDI'.  If the data isn't in
a special format, this will be `DAT_DATA' -- this indicates
that `dat' just points to a block of data.  You can get the
size of this block from the `size' field of the DATAFILE struct:

     load_map_data (data[2].dat, data[2].size);

would pass the pointer to the binary block and its size to the
`load_map_data' function (which would be one you'd write
yourself).

Now, how do you know which object number in the datafile
corresponds to which object you put into the file?  There are
three ways you can do this, and as always which way you choose
is entirely up to you -- depending on the circumstances you
might want to mix together all three methods.

The first way is to use the header file optionally created by
the grabber or dat utility.  This file will contain one macro
for each object, #defining the name of the object to its index
in the datafile.  So instead of using what I wrote above you
can say:

     blit (data[MY_BITMAP].dat, screen, ...);
     play_sample (data[MY_SAMPLE].dat, 255, 128, 1000, 0);
     load_map_data (data[MY_MAP].dat, data[MY_MAP].size);

This way, if you add other objects to the datafile and they get
put before the old objects you won't have to change all the
indices in your code.

The text of each #define is exactly what you entered in the
grabber as the object's name.  If you used the dat utility to
create the object its name will probably be its original
filename in upper case, with the `.' replaced by `_'.  This
replacement is done so that the resulting object name is a
valid thing to #define in C -- dots aren't allowed.

Along the same lines, when you're making your object names you
should bear in mind that they'll be used as #defines in your
program -- don't pick anything you might want to use for
something else (e.g. `main', `BITMAP', etc).  You can use the
`Prefix' option of the grabber or dat utility to prefix all the
#defines in the header file with something, e.g. `DATAFILE' --
then you'd have:

     blit (data[DATAFILE_BITMAP].dat, screen, ...);

if the object's name was `BITMAP'.

The second way of knowing where an object is in the datafile is
by relying on the fact that they are stored in alphabetical
order.  According to the author, this is true now and always
will be.  I don't recommend overusing this feature, but it can
be useful if, for example, you have a number of bitmaps (all
frames of the same sprite, perhaps) called `ENEMY_000',
`ENEMY_001', `ENEMY_002', etc.  You can use the #defines to
refer to these, of course, but it's more convenient to be able
to pick one of these bitmaps by number based on a variable.

Because of the way preprocessing works (`pre' = before, i.e.
before compilation) it isn't possible to change `ENEMY_000' to
`ENEMY_xxx' at run-time.  But, since the objects are in
alphabetical order you know that `ENEMY_000' will be stored
first in the file, and `ENEMY_001' will be immediately after it
-- i.e. the nth enemy bitmap will be object number `ENEMY_000 +
n' if, as all sane programmers do, you start counting from 0
(so `ENEMY_000' is the 0th object).  Then the following will
work:

     void draw_nth_enemy (int n, BITMAP *where, int x, int y)
     {
         draw_sprite (where, data[ENEMY_000 + n], x, y);
     }

The third way of finding an object in the datafile involves
searching through the array for an object with the right name.
The object names are stored as "properties" of the objects.
For full details on properties, see the `grabber.txt' file.
Briefly, though, to get the name of an object you write:

     name = get_datafile_property (&dat[obj_number],
                                   DAT_ID ('N','A','M','E'));

Note the `&' -- you pass a pointer to the object in the array.
If the string you are returned is empty (i.e.  name[0] == '\0',
_not_ name == NULL) then the object doesn't have a `NAME'
property.  This probably means you stripped the properties from
the datafile; in this case you'll have to use one of the first
two methods to find your objects.

A couple more things are worth mentioning here.  Firstly, if
you're using C++ then the compiler won't like you passing the
`dat' field (a void pointer) to functions which expect some
other type of pointer, so you have to explicitly cast it to
whatever type the function wants:

     play_midi ( (MIDI *) data[MUSIC].dat, 0);

Secondly (and somewhat linked to the above) it is often
convenient to alias all the objects in the datafile, by
creating global variables or arrays, something like this:

     BITMAP *enemy_bitmap;
     MIDI *background_music;
     SAMPLE *crash_sound;

then setting them to point to bits of the datafile:

     data = load_datafile ("DATAFILE.DAT");
     if (!data) barf();  /* loading failed */

     enemy_bitmap = (BITMAP *) data[ENEMY_BITMAP];
     background_music = (MIDI *) data[MUSIC];
     crash_sound = (SAMPLE *) data[CRASH_SOUND];

and finally using them in the game:

     draw_sprite (screen, enemy_bitmap, x, y);
     play_midi (background_music, 1);
     play_sample (crash_sound, 255, 128, 1000, 0);

The advantages of this are that it gets rid of the annoying
casts needed for C++, it makes the later code neater and
slightly faster, and it also makes it easier to change the code
from being datafile-based to being file-based and vice versa.

Thirdly, the datafile array is terminated by an object of type
`DAT_END'.  You may or may not find this very useful; it's
semi-redundant information, a bit like the fact that
`argv[argc]' is NULL.  If you want to search the whole datafile
for something (perhaps an object with a certain property) you
could use this fact to know where to stop.

Finally, when you've finished with the datafile you can unload
it using the `unload_datafile' function:

     unload_datafile (data);

Needless to say, after doing this you must not use the data
array any more, and if you have any aliases to objects in the
array (as above) you must not use them either.

See the example: `examples/chap_10/ex_3_1'

10.3.2 Individually loading datafile components
-----------------------------------------------

You can load an individual datafile object on its own provided
the name information is still in the datafile (i.e. you didn't
strip all the properties in the grabber, or apply `-s2' in the
dat utility).  The function to do this is
`load_datafile_object' and it is used like this:

     data_object = load_datafile_object ("datafile.dat", "object_name");

`data_object' should be a `DATAFILE *', just as if you were
loading a whole datafile.  To access the object you just
dereference this pointer, e.g.:

     music_object = load_datafile_object ("datafile.dat", "MUSIC");
     play_midi (music_object->dat);      /* or music_object[0].dat */

Since this loads only one object, it returns a pointer to a
single DATAFILE struct, not an array of them.  So you don't use
the object's index from the header file, and also there is no
`DAT_END' object after the returned object.

To unload an object loaded in this way use
`unload_datafile_object':

     unload_datafile_object (data_object);

See the example: `examples/chap_10/ex_3_2'

10.3.3 Reading a datafile component as a normal packfile
--------------------------------------------------------

A handy feature of Allegro's packfile routines is the ability
to read a datafile object as if it were a file on disk.  To do
this you simply use the encoded filename format
`datafile_filename#object_name', for example:

     fp = pack_fopen ("datafile.dat#MUSIC", F_READ);

Then if `fp' is not NULL you can read from it as you would read
from a normal packfile.  You can't write to the file.  To close
it you use `fclose' as normal.

See the example: `examples/chap_10/ex_3_3'

Index
*****

This section is generated automatically, but I haven't bothered
to mark any index entries yet, so it's empty at the moment.