Using Allegro

  • allegro_error
  • allegro_exit
  • allegro_id
  • allegro_init
  • allegro_message
  • check_cpu
  • cpu_capabilities
  • cpu_family
  • cpu_model
  • cpu_vendor
  • desktop_color_depth
  • END_OF_MAIN
  • get_desktop_resolution
  • install_allegro
  • os_multitasking
  • os_revision
  • os_type
  • os_version
  • set_window_close_button
  • set_window_close_hook
  • set_window_title
  • yield_timeslice

See readme.txt for a general introduction, copyright details, and information about how to install Allegro and link your program with it.

int install_allegro(int system_id, int *errno_ptr, int (*atexit_ptr)());
Initialises the Allegro library. You must call either this or allegro_init() before doing anything other than using the Unicode routines. If you want to use a text mode other than UTF-8, you can set it with set_uformat() before you call this. The available system ID codes will vary from one platform to another, but you will almost always want to pass SYSTEM_AUTODETECT. Alternatively, SYSTEM_NONE installs a stripped down version of Allegro that won't even try to touch your hardware or do anything platform specific: this can be useful for situations where you only want to manipulate memory bitmaps, such as the text mode datafile tools or the Windows GDI interfacing functions. The errno_ptr and atexit_ptr parameters should point to the errno variable and atexit function from your libc: these are required because when Allegro is linked as a DLL, it doesn't have direct access to your local libc data. atexit_ptr may be NULL, in which case it is your responsibility to call allegro_exit manually. Currently this function always returns zero. If no system driver can be used, the program will abort.

int allegro_init();
Macro which initialises the Allegro library. This is the same thing as calling install_allegro(SYSTEM_AUTODETECT, &errno, atexit).

void allegro_exit();
Closes down the Allegro system. This includes returning the system to text mode and removing whatever mouse, keyboard, and timer routines have been installed. You don't normally need to bother making an explicit call to this function, because allegro_init() installs it as an atexit() routine so it will be called automatically when your program exits.

Macro END_OF_MAIN()
In order to maintain cross-platform compatibility, you have to put this macro at the very end of your main function. This macro uses some `magic' to mangle your main procedure on platforms that need it like Windows or Linux. On the other platforms this macro compiles to nothing, so you don't have to #ifdef around it. Example:

      int main(void)
      {
         allegro_init();
         /* more stuff goes here */
         ...
         return 0;
      }
      END_OF_MAIN()

extern char allegro_id[];
Text string containing a date and version number for the library, in case you want to display these somewhere.

extern char allegro_error[ALLEGRO_ERROR_SIZE];
Text string used by set_gfx_mode() and install_sound() to report error messages. If they fail and you want to tell the user why, this is the place to look for a description of the problem.

extern int os_type;
Set by allegro_init() to one of the values:

      OSTYPE_UNKNOWN    - unknown, or regular MSDOS
      OSTYPE_WIN3       - Windows 3.1 or earlier
      OSTYPE_WIN95      - Windows 95
      OSTYPE_WIN98      - Windows 98
      OSTYPE_WINME      - Windows ME
      OSTYPE_WINNT      - Windows NT
      OSTYPE_WIN2000    - Windows 2000
      OSTYPE_WINXP      - Windows XP
      OSTYPE_OS2        - OS/2
      OSTYPE_WARP       - OS/2 Warp 3
      OSTYPE_DOSEMU     - Linux DOSEMU
      OSTYPE_OPENDOS    - Caldera OpenDOS
      OSTYPE_LINUX      - Linux
      OSTYPE_SUNOS      - SunOS/Solaris
      OSTYPE_FREEBSD    - FreeBSD
      OSTYPE_NETBSD     - NetBSD
      OSTYPE_IRIX       - IRIX
      OSTYPE_QNX        - QNX
      OSTYPE_UNIX       - Unknown Unix variant
      OSTYPE_BEOS       - BeOS
      OSTYPE_MACOS      - MacOS
extern int os_version;
extern int os_revision;
The major and minor version of the Operating System currently running. Set by allegro_init(). If Allegro for some reason was not able to retrieve the version of the Operating System, os_version and os_revision will be set to -1. For example: Under Win98 SE (v4.10.2222) os_version will be set to 4 and os_revision to 10.

extern int os_multitasking;
Set by allegro_init() to either TRUE or FALSE depending on whether your Operating System is multitasking or not.

void allegro_message(const char *msg, ...);
Outputs a message, using a printf() format string. This function must only be used when you aren't in graphics mode, eg. before calling set_gfx_mode(), or after a set_gfx_mode(GFX_TEXT). On platforms that have a text console (DOS and Unix) it will print the string to that console, attempting to work around codepage differences by reducing any accented characters to 7 bit ASCII approximations, and on platforms featuring a windowing system it will bring up a GUI message box.

void set_window_title(const char *name);
On platforms that are capable of it, this routine alters the window title for your Allegro program. Note that Allegro cannot set the window title when running in a DOS box under Windows.

int set_window_close_button(int enable);
On platforms that are capable of it, this routine disables or enables the window close button for your Allegro program. You can call it before the window is created if you wish. If the close button is successfully disabled, this function returns zero.

On platforms where the close button either does not exist or cannot be disabled, this function returns -1. If this happens, you may wish to use set_window_close_hook() to handle the close event yourself.

When enabling the close button, the function will return the same value for your platform as when disabling. That means it will return non-zero if the button cannot be disabled, even though you are not trying to disable it.

Note that Allegro cannot manipulate the close button of a DOS box in Windows.

void set_window_close_hook(void (*proc)());
On platforms that have a close button, this routine installs a hook function to handle the close event. In other words, when the user clicks the close button on your program's window, the function you specify here will be called.

This function should not generally attempt to exit the program or save any data itself. The function could be called at any time, and there is usually a risk of conflict with the main thread of the program. Instead, you should set a flag during this function, and test it on a regular basis in the main loop of the program.

Pass NULL to this function to restore the close button's default functionality. On Windows and BeOS, the following message will appear:

Warning: forcing program shutdown may lead to data loss and unexpected results. It is preferable to use the exit command inside the window.

Proceed anyway?

[Yes] [No]

This message will be translated into your selected language if a translation is available in language.dat (see get_config_text()).

If the user clicks [Yes], the program will exit immediately in the same style as Ctrl+Alt+End (see three_finger_flag).

In other operating systems, the program will exit immediately without prompting the user.

Note that Allegro cannot intercept the close button of a DOS box in Windows.

int desktop_color_depth();
On platforms that can run Allegro programs in a window on an existing desktop, returns the currently selected desktop color depth (your program is likely to run faster if it uses this same depth). On platforms where this information is not available or does not apply, returns zero.

int get_desktop_resolution(int *width, int *height);
On platforms that can run Allegro programs in a window on an existing desktop, this retrieves the current desktop resolution (e.g. you may want to call this function before creating a large window because, with some windowed drivers, a window cannot be created if it is larger than the desktop). Returns zero on success, or a negative number if this information is not available or does not apply, in which case the values stored in width and height are unspecified.

void yield_timeslice();
On systems that support this, gives up the rest of the current scheduler timeslice. Also known as the "play nice with multitasking" option.

void check_cpu();
Detects the CPU type, setting the following global variables. You don't normally need to call this, because allegro_init() will do it for you.

extern char cpu_vendor[];
Contains the CPU vendor name, if known (empty string on non-Intel platforms).

extern int cpu_family;
Contains the Intel CPU type, where applicable: 3=386, 4=486, 5=Pentium, 6=PPro, etc.

extern int cpu_model;
Contains the Intel CPU submodel, where applicable. On a 486 (cpu_family=4), zero or one indicates a DX chip, 2 an SX, 3 a 487 (SX) or 486 DX, 4 an SL, 5 an SX2, 7 a DX2 write-back enhanced, 8 a DX4 or DX4 overdrive, 14 a Cyrix, and 15 is unknown. On a Pentium chip (cpu_family=5), 1 indicates a Pentium (510\66, 567\66), 2 is a Pentium P54C, 3 is a Pentium overdrive processor, 5 is a Pentium overdrive for IntelDX4, 14 is a Cyrix, and 15 is unknown.

extern int cpu_capabilities;
Contains CPU flags indicating what features are available on the current CPU. The flags can be any combination of these:

   CPU_ID       - Indicates that the "cpuid" instruction is available. If this
                  is set, then all Allegro CPU variables are 100% reliable,
                  otherwise there may be some mistakes.
   CPU_FPU      - An x87 FPU is available.
   CPU_MMX      - Intel MMX  instruction set is available.
   CPU_MMXPLUS  - Intel MMX+ instruction set is available.
   CPU_SSE      - Intel SSE  instruction set is available.
   CPU_SSE2     - Intel SSE2 instruction set is available.
   CPU_3DNOW    - AMD 3DNow! instruction set is available.
   CPU_ENH3DNOW - AMD Enhanced 3DNow! instruction set is available.
   CPU_CMOV     - Pentium Pro "cmov" instruction is available.

You can check for multiple features by OR-ing the flags together. For example, to check if the CPU has an FPU and MMX instructions available, you'd do:

   if ((cpu_capabilities & (CPU_FPU | CPU_MMX)) == (CPU_FPU | CPU_MMX))
      printf("CPU has both an FPU and MMX instructions!\n");

Back to Contents


Unicode routines

  • _ustrdup
  • do_uconvert
  • empty_string
  • get_uformat
  • need_uconvert
  • register_uformat
  • set_ucodepage
  • set_uformat
  • uatof
  • uconvert
  • uconvert_ascii
  • uconvert_size
  • uconvert_toascii
  • ucwidth
  • ugetat
  • ugetc
  • ugetx
  • ugetxc
  • uinsert
  • uisdigit
  • uisok
  • uisspace
  • uoffset
  • uremove
  • usetat
  • usetc
  • usprintf
  • ustrcat
  • ustrchr
  • ustrcmp
  • ustrcpy
  • ustrdup
  • ustrerror
  • ustricmp
  • ustrlen
  • ustrlwr
  • ustrncat
  • ustrncmp
  • ustrncpy
  • ustrpbrk
  • ustrrchr
  • ustrsize
  • ustrsizez
  • ustrstr
  • ustrtod
  • ustrtok
  • ustrtok_r
  • ustrtol
  • ustrupr
  • ustrzcat
  • ustrzcpy
  • ustrzncat
  • ustrzncpy
  • uszprintf
  • utolower
  • utoupper
  • uvsprintf
  • uvszprintf
  • uwidth
  • uwidth_max

Allegro can manipulate and display text using any character values from 0 right up to 2^32-1 (although the current implementation of the grabber can only create fonts using characters up to 2^16-1). You can choose between a number of different text encoding formats, which controls how strings are stored and how Allegro interprets strings that you pass to it. This setting affects all aspects of the system: whenever you see a function that returns a char * type, or that takes a char * as an argument, that text will be in whatever format you have told Allegro to use.

By default, Allegro uses UTF-8 encoded text (U_UTF8). This is a variable-width format, where characters can occupy anywhere from one to six bytes. The nice thing about it is that characters ranging from 0-127 are encoded directly as themselves, so UTF-8 is upwardly compatible with 7 bit ASCII ("Hello, World!" means the same thing regardless of whether you interpret it as ASCII or UTF-8 data). Any character values above 128, such as accented vowels, the UK currency symbol, and Arabic or Chinese characters, will be encoded as a sequence of two or more bytes, each in the range 128-255. This means you will never get what looks like a 7 bit ASCII character as part of the encoding of a different character value, which makes it very easy to manipulate UTF-8 strings.

There are a few editing programs that understand UTF-8 format text files. Alternatively, you can write your strings in plain ASCII or 16 bit Unicode formats, and then use the Allegro textconv program to convert them into UTF-8.

If you prefer to use some other text format, you can set Allegro to work with normal 8 bit ASCII (U_ASCII), or 16 bit Unicode (U_UNICODE) instead, or you can provide some handler functions to make it support whatever other text encoding you like (for example it would be easy to add support for 32 bit UCS-4 characters, or the Chinese GB-code format).

There is some limited support for alternative 8 bit codepages, via the U_ASCII_CP mode. This is very slow, so you shouldn't use it for serious work, but it can be handy as an easy way to convert text between different codepages. By default the U_ASCII_CP mode is set up to reduce text to a clean 7 bit ASCII format, trying to replace any accented vowels with their simpler equivalents (this is used by the allegro_message() function when it needs to print an error report onto a text mode DOS screen). If you want to work with other codepages, you can do this by passing a character mapping table to the set_ucodepage() function.

Note that you can use the Unicode routines before you call install_allegro() or allegro_init(). If you want to work in a text mode other than UTF-8, it is best to set it with set_uformat() just before you call these.

void set_uformat(int type);
Sets the current text encoding format. This will affect all parts of Allegro, wherever you see a function that returns a char *, or takes a char * as a parameter. The type should be one of the values:

      U_ASCII     - fixed size, 8 bit ASCII characters
      U_ASCII_CP  - alternative 8 bit codepage (see set_ucodepage())
      U_UNICODE   - fixed size, 16 bit Unicode characters
      U_UTF8      - variable size, UTF-8 format Unicode characters
Although you can change the text format on the fly, this is not a good idea. Many strings, for example the names of your hardware drivers and any language translations, are loaded when you call allegro_init(), so if you change the encoding format after this, they will be in the wrong format, and things will not work properly. Generally you should only call set_uformat() once, before allegro_init(), and then leave it on the same setting for the duration of your program.

int get_uformat(void);
Returns the currently selected text encoding format.

void register_uformat(int type, int (*u_getc)(const char *s), int (*u_getx)(char **s), int (*u_setc)(char *s, int c), int (*u_width)(const char *s), int (*u_cwidth)(int c), int (*u_isok)(int c));
Installs a set of custom handler functions for a new text encoding format. The type is the ID code for your new format, which should be a 4-character string as produced by the AL_ID() macro, and which can later be passed to functions like set_uformat() and uconvert(). The function parameters are handlers that implement the character access for your new type: see below for details of these.

void set_ucodepage(const unsigned short *table, const unsigned short *extras);
When you select the U_ASCII_CP encoding mode, a set of tables are used to convert between 8 bit characters and their Unicode equivalents. You can use this function to specify a custom set of mapping tables, which allows you to support different 8 bit codepages. The table parameter points to an array of 256 shorts, which contain the Unicode value for each character in your codepage. The extras parameter, if not NULL, points to a list of mapping pairs, which will be used when reducing Unicode data to your codepage. Each pair consists of a Unicode value, followed by the way it should be represented in your codepage. The table is terminated by a zero Unicode value. This allows you to create a many->one mapping, where many different Unicode characters can be represented by a single codepage value (eg. for reducing accented vowels to 7 bit ASCII).

int need_uconvert(const char *s, int type, int newtype);
Given a pointer to a string, a description of the type of the string, and the type that you would like this string to be converted into, this function tells you whether any conversion is required. No conversion will be needed if type and newtype are the same, or if one type is ASCII, the other is UTF-8, and the string contains only character values less than 128. As a convenience shortcut, you can pass the value U_CURRENT as either of the type parameters, to represent whatever text format is currently selected.

int uconvert_size(const char *s, int type, int newtype);
Returns the number of bytes that will be required to store the specified string after a conversion from type to newtype, including the zero terminator. The type parameters can use the value U_CURRENT as a shortcut to represent the currently selected encoding format.

void do_uconvert(const char *s, int type, char *buf, int newtype, int size);
Converts the specified string from type to newtype, storing at most size bytes into the output buf. The type parameters can use the value U_CURRENT as a shortcut to represent the currently selected encoding format.

char *uconvert(const char *s, int type, char *buf, int newtype, int size);
Higher level function running on top of do_uconvert(). This function converts the specified string from type to newtype, storing at most size bytes into the output buf, but it checks before doing the conversion, and doesn't bother if the string formats are already the same (either both types are equal, or one is ASCII, the other is UTF-8, and the string contains only 7 bit ASCII characters). If a conversion was performed it returns a pointer to buf, otherwise it returns a copy of s, so you must use the return value rather than assuming that the string will always be moved to buf. As a convenience, if buf is NULL it will convert the string into an internal static buffer. You should be wary of using this feature, though, because that buffer will be overwritten the next time this routine is called, so don't expect the data to persist across any other library calls.

char *uconvert_ascii(const char *s, char buf[]);
Helper macro for converting strings from ASCII into the current encoding format. Expands to uconvert(s, U_ASCII, buf, U_CURRENT, sizeof(buf)).

char *uconvert_toascii(const char *s, char buf[]);
Helper macro for converting strings from the current encoding format into ASCII. Expands to uconvert(s, U_CURRENT, buf, U_ASCII, sizeof(buf)).

extern char empty_string[];
You can't just rely on "" to be a valid empty string in any encoding format. This global buffer contains a number of consecutive zeros, so it will be a valid empty string no matter whether the program is running in ASCII, Unicode, or UTF-8 mode.

int ugetc(const char *s);
Low level helper function for reading Unicode text data. Given a pointer to a string in the current encoding format, it returns the next character from the string.

int ugetx(char **s);
int ugetxc(const char **s);
Low level helper function for reading Unicode text data. Given the address of a pointer to a string in the current encoding format, it returns the next character from the string, and advances the pointer to the character after the one just read.

ugetxc is provided for working with pointer-to-pointer-to-const char data.

int usetc(char *s, int c);
Low level helper function for writing Unicode text data. It writes the specified character to the given address in the current encoding format, and returns the number of bytes written.

int uwidth(const char *s);
Low level helper function for testing Unicode text data. It returns the number of bytes occupied by the first character of the specified string, in the current encoding format.

int ucwidth(int c);
Low level helper function for testing Unicode text data. It returns the number of bytes that would be occupied by the specified character value, when encoded in the current format.

int uisok(int c);
Low level helper function for testing Unicode text data. Tests whether the specified value can be correctly encoded in the current format.

int uoffset(const char *s, int index);
Returns the offset in bytes from the start of the string to the character at the specified index. If the index is negative, it counts backward from the end of the string, so an index of -1 will return an offset to the last character.

int ugetat(const char *s, int index);
Returns the character value at the specified index within the string. A zero index parameter will return the first character of the string. If the index is negative, it counts backward from the end of the string, so an index of -1 will return the last character of the string.

int usetat(char *s, int index, int c);
Replaces the character at the specified index within the string with value c, handling any adjustments for variable width data (ie. if c encodes to a different width than the previous value at that location). Returns the number of bytes by which the trailing part of the string was moved. If the index is negative, it counts backward from the end of the string.

int uinsert(char *s, int index, int c);
Inserts the character c at the specified index within the string, sliding the rest of the data along to make room. Returns the number of bytes by which the trailing part of the string was moved. If the index is negative, it counts backward from the end of the string.

int uremove(char *s, int index);
Removes the character at the specified index within the string, sliding the rest of the data back to fill the gap. Returns the number of bytes by which the trailing part of the string was moved. If the index is negative, it counts backward from the end of the string.

int ustrsize(const char *s);
Returns the size of the specified string in bytes, not including the trailing zero.

int ustrsizez(const char *s);
Returns the size of the specified string in bytes, including the trailing zero.

int uwidth_max(int type);
Low level helper function for working with Unicode text data. Returns the largest number of bytes that one character can occupy in the given encoding format. Pass U_CURRENT to represent the current format.

int utolower(int c);
This function returns c, converting it to lower case if it is upper case.

int utoupper(int c);
This function returns c, converting it to upper case if it is lower case.

int uisspace(int c);
Returns nonzero if c is whitespace, that is, carriage return, newline, form feed, tab, vertical tab, or space.

int uisdigit(int c);
Returns nonzero if c is a digit.

char *ustrdup(const char *src)
This functions copies the NULL-terminated string src into a newly allocated area of memory. The memory returned by this call must be freed by the caller. Returns NULL if it cannot allocate space for the duplicated string.

char *_ustrdup(const char *src, void* (*malloc_func) (size_t))
Does the same as ustrdup(), but allows the user to specify his own memory allocater function.

char *ustrcpy(char *dest, const char *src);
This function copies src (including the terminating NULL character) into dest. The return value is the value of dest.

char *ustrzcpy(char *dest, int size, const char *src);
This function copies src (including the terminating NULL character) into dest, whose length in bytes is specified by size and which is guaranteed to be NULL-terminated. The return value is the value of dest.

char *ustrcat(char *dest, const char *src);
This function concatenates src to the end of dest. The return value is the value of dest.

char *ustrzcat(char *dest, int size, const char *src);
This function concatenates src to the end of dest, whose length in bytes is specified by size and which is guaranteed to be NULL-terminated. The return value is the value of dest.

int ustrlen(const char *s);
This function returns the number of characters in s. Note that this doesn't have to equal the string's size in bytes.

int ustrcmp(const char *s1, const char *s2);
This function compares s1 and s2. Returns zero if the strings are equal, a positive number if s1 comes after s2 in the ASCII collating sequence, else a negative number.

char *ustrncpy(char *dest, const char *src, int n);
This function is like ustrcpy() except that no more than n characters from src are copied into dest. If src is shorter than n characters, NULL characters are appended to dest as padding until n characters have been written. Note that if src is longer than n characters, dest will not be NULL-terminated. The return value is the value of dest.

char *ustrzncpy(char *dest, int size, const char *src, int n);
This function is like ustrzcpy() except that no more than n characters from src are copied into dest. If src is shorter than n characters, NULL characters are appended to dest as padding until n characters have been written. Note that dest is guaranteed to be NULL-terminated. The return value is the value of dest.

char *ustrncat(char *dest, const char *src, int n);
This function is like ustrcat() except that no more than n characters from src are appended to the end of dest. If the terminating NULL character in src is reached before n characters have been written, the NULL character is copied, but no other characters are written. If n characters are written before a terminating NULL is encountered, the function appends its own NULL character to dest, so that n+1 characters are written. The return value is the value of dest.

char *ustrzncat(char *dest, int size, const char *src, int n);
This function is like ustrzcat() except that no more than n characters from src are appended to the end of dest. If the terminating NULL character in src is reached before n characters have been written, the NULL character is copied, but no other characters are written. Note that dest is guaranteed to be NULL-terminated. The return value is the value of dest.

int ustrncmp(const char *s1, const char *s2, int n);
This function compares up to n characters of s1 and s2. Returns zero if the substrings are equal, a positive number if s1 comes after s2 in the ASCII collating sequence, else a negative number.

int ustricmp(const char *s1, const char *s2);
This function compares s1 and s2, ignoring case.

char *ustrlwr(char *s);
This function replaces all upper case letters in s with lower case letters.

char *ustrupr(char *s);
This function replaces all lower case letters in s with upper case letters.

char *ustrchr(const char *s, int c);
This function returns a pointer to the first occurrence of c in s, or NULL if no match was found. Note that if c is NULL, this will return a pointer to the end of the string.

char *ustrrchr(const char *s, int c);
This function returns a pointer to the last occurrence of c in s, or NULL if no match was found.

char *ustrstr(const char *s1, const char *s2);
This function finds the first occurence of s2 in s1. Returns a pointer within s1, or NULL if s2 wasn't found.

char *ustrpbrk(const char *s, const char *set);
This function finds the first character in s that matches any character in set. Returns a pointer to the first match, or NULL if none are found.

char *ustrtok(char *s, const char *set);
This function retrieves tokens from s which are delimited by characters from set. To initiate the search, pass the string to be searched as s. For the remaining tokens, pass NULL instead. Returns a pointer to the token, or NULL if no more are found. Warning: Since ustrtok alters the string it is parsing, you should always copy the string to a temporary buffer before parsing it. Also, this function is not reentrant (ie. you cannot parse two strings at the same time).

char *ustrtok_r(char *s, const char *set, char **last);
Reentrant version of ustrtok. The last parameter is used to keep track of where the parsing is up to and must be a pointer to a char * variable allocated by the user that remains the same while parsing the same string.

double uatof(const char *s);
Convert as much of the string as possible to an equivalent double precision real number. This function is almost like `ustrtod(s, NULL)'. Returns the equivalent value, or zero if the string does not represent a number.

long ustrtol(const char *s, char **endp, int base);
This function converts the initial part of s to a signed integer, which is returned as a value of type `long int', setting *endp to point to the first unused character, if endp is not a NULL pointer. The base argument indicates what base the digits (or letters) should be treated as. If base is zero, the base is determined by looking for `0x', `0X', or `0' as the first part of the string, and sets the base used to 16, 16, or 8 if it finds one. The default base is 10 if none of those prefixes are found.

double ustrtod(const char *s, char **endp);
This function converts as many characters of s that look like a floating point number into one, and sets *endp to point to the first unused character, if endp is not a NULL pointer.

const char *ustrerror(int err);
This function returns a string that describes the error code `err', which normally comes from the variable `errno'. Returns a pointer to a static string that should not be modified or free'd. If you make subsequent calls to ustrerror, the string might be overwritten.

int usprintf(char *buf, const char *format, ...);
This function writes formatted data into the output buffer. A NULL character is written to mark the end of the string. Returns the number of characters written, not including the terminating NULL character.

int uszprintf(char *buf, int size, const char *format, ...);
This function writes formatted data into the output buffer, whose length in bytes is specified by size and which is guaranteed to be NULL terminated. Returns the number of characters that would have been written without eventual truncation (like with usprintf), not including the terminating NULL character.

int uvsprintf(char *buf, const char *format, va_list args);
This is like usprintf(), but you pass the variable argument list directly, instead of the arguments themselves.

int uvszprintf(char *buf, int size, const char *format, va_list args);
This is like uszprintf(), but you pass the variable argument list directly, instead of the arguments themselves.


Configuration routines

  • config_is_hooked
  • flush_config_file
  • get_config_argv
  • get_config_float
  • get_config_hex
  • get_config_id
  • get_config_int
  • get_config_string
  • get_config_text
  • hook_config_section
  • override_config_data
  • override_config_file
  • pop_config_state
  • push_config_state
  • reload_config_texts
  • set_config_data
  • set_config_file
  • set_config_float
  • set_config_hex
  • set_config_id
  • set_config_int
  • set_config_string

Various parts of Allegro, such as the sound routines and the load_joystick_data() function, require some configuration information. This data is stored in text files as a collection of "variable=value" lines, along with comments that begin with a '#' character and continue to the end of the line. The configuration file may optionally be divided into sections, which begin with a "[sectionname]" line. Each section has a unique namespace, to prevent variable name conflicts, but any variables that aren't in a section are considered to belong to all the sections simultaneously.

By default the configuration data is read from a file called allegro.cfg, which can be located either in the same directory as the program executable, or the directory pointed to by the ALLEGRO environment variable. Under Unix, it also checks for ~/allegro.cfg, ~/.allegrorc, /etc/allegro.cfg, and /etc/allegrorc, in that order; under BeOS only the last two are also checked. If you don't like this approach, you can specify any filename you like, or use a block of binary configuration data provided by your program (which could for example be loaded from a datafile).

You can store whatever custom information you like in the config file, along with the standard variables that are used by Allegro (see below).

void set_config_file(const char *filename);
Sets the configuration file to be used by all subsequent config functions. If you don't call this function, Allegro will use the default allegro.cfg file, looking first in the same directory as your program and then in the directory pointed to by the ALLEGRO environment variable.

All pointers returned by previous calls to get_config_string() and other related functions are invalidated when you call this function!

void set_config_data(const char *data, int length);
Specifies a block of data to be used by all subsequent config functions, which you have already loaded from disk (eg. as part of some more complicated format of your own, or in a grabber datafile). This routine makes a copy of the information, so you can safely free the data after calling it.

void override_config_file(const char *filename);
Specifies a file containing config overrides. These settings will be used in addition to the parameters in the main config file, and where a variable is present in both files this version will take priority. This can be used by application programmers to override some of the config settings from their code, while still leaving the main config file free for the end user to customise. For example, you could specify a particular sample frequency and IBK instrument file, but the user could still use an allegro.cfg file to specify the port settings and irq numbers.

void override_config_data(const char *data, int length);
Version of override_config_file() which uses a block of data that has already been read into memory.

void push_config_state();
Pushes the current configuration state (filename, variable values, etc). onto an internal stack, allowing you to select some other config source and later restore the current settings by calling pop_config_state(). This function is mostly intended for internal use by other library functions, for example when you specify a config filename to the save_joystick_data() function, it pushes the config state before switching to the file you specified.

void pop_config_state();
Pops a configuration state previously stored by push_config_state(), replacing the current config source with it.

void flush_config_file();
Writes the current config file to disk if the contents have changed since it was loaded or since the latest call to the function.

void reload_config_texts(const char *new_language);
Reloads the translated strings returned by get_config_text. This is useful to switch to another language in your program at runtime. If you want to modify the [system] language configuration variable yourself, or you have switched configuration files, you will want to pass NULL to just reload whatever language is currently selected. Or you can pass a string containing the two letter code of the language you desire to switch to, and the function will modify the language variable. After you call this function, the previously returned pointers of get_config_text will be invalid.

void hook_config_section(const char *section, int (*intgetter)(const char *name, int def), const char *(*stringgetter)(const char *name, const char *def), void (*stringsetter)(const char *name, const char *value));
Takes control of the specified config file section, so that your hook functions will be used to manipulate it instead of the normal disk file access. If both the getter and setter functions are NULL, a currently present hook will be unhooked. Hooked functions have the highest priority. If a section is hooked, the hook will always be called, so you can also hook a '#' section: even override_config_file() cannot override a hooked section.

int config_is_hooked(const char *section);
Returns TRUE if the specified config section has been hooked.

const char *get_config_string(const char *section, const char *name, const char *def);
Retrieves a string variable from the current config file. If the named variable cannot be found, or its entry in the config file is empty, the value of def is returned. The section name may be set to NULL to read variables from the root of the file, or used to control which set of parameters (eg. sound or joystick) you are interested in reading.

int get_config_int(const char *section, const char *name, int def);
Reads an integer variable from the current config file. See the comments about get_config_string().

int get_config_hex(const char *section, const char *name, int def);
Reads an integer variable from the current config file, in hexadecimal format. See the comments about get_config_string().

float get_config_float(const char *section, const char *name, float def);
Reads a floating point variable from the current config file. See the comments about get_config_string().

int get_config_id(const char *section, const char *name, int def);
Reads a 4-letter driver ID variable from the current config file. See the comments about get_config_string().

char **get_config_argv(const char *section, const char *name, int *argc);
Reads a token list (words separated by spaces) from the current config file, returning a an argv style argument list, and setting argc to the number of tokens (unlike argc/argv, this list is zero based). Returns NULL and sets argc to zero if the variable is not present. The token list is stored in a temporary buffer that will be clobbered by the next call to get_config_argv(), so the data should not be expected to persist.

const char *get_config_text(const char *msg);
This function is primarily intended for use by internal library code, but it may perhaps be helpful to application programmers as well. It uses the language.dat or XXtext.cfg files (where XX is a language code) to look up a translated version of the parameter in the currently selected language, returning a suitable translation if one can be found or a copy of the parameter if nothing else is available. This is basically the same thing as calling get_config_string() with [language] as the section, msg as the variable name, and msg as the default value, but it contains some special code to handle Unicode format conversions. The msg parameter is always given in ASCII format, but the returned string will be converted into the current text encoding, with memory being allocated as required, so you can assume that this pointer will persist without having to manually allocate storage space for each string.

void set_config_string(const char *section, const char *name, const char *val);
Writes a string variable to the current config file, replacing any existing value it may have, or removes the variable if val is NULL. The section name may be set to NULL to write the variable to the root of the file, or used to control which section the variable is inserted into. The altered file will be cached in memory, and not actually written to disk until you call allegro_exit(). Note that you can only write to files in this way, so the function will have no effect if the current config source was specified with set_config_data() rather than set_config_file().

As a special case, variable or section names that begin with a '#' character are treated specially and will not be read from or written to the disk. Addon packages can use this to store version info or other status information into the config module, from where it can be read with the get_config_string() function.

void set_config_int(const char *section, const char *name, int val);
Writes an integer variable to the current config file. See the comments about set_config_string().

void set_config_hex(const char *section, const char *name, int val);
Writes an integer variable to the current config file, in hexadecimal format. See the comments about set_config_string().

void set_config_float(const char *section, const char *name, float val);
Writes a floating point variable to the current config file. See the comments about set_config_string().

void set_config_id(const char *section, const char *name, int val);
Writes a 4-letter driver ID variable to the current config file. See the comments about set_config_string().

Allegro uses these standard variables from the configuration file:

  • [system]
    Section containing general purpose variables:

    • system = x
      Specifies which system driver to use. This is currently only useful on Linux, for choosing between the XWindows ("XWIN") or console ("LNXC") modes.

    • keyboard = x
      Specifies which keyboard layout to use. The parameter is the name of a keyboard mapping file produced by the keyconf utility, and can either be a fully qualified file path or a basename like "us" or "uk". If the latter, Allegro will look first for a separate config file with that name (eg. "uk.cfg") and then for an object with that name in the keyboard.dat file (eg. "UK_CFG"). The config file or keyboard.dat file can be stored in the same directory as the program, or in the location pointed to by the ALLEGRO environment variable. Look in the keyboard.dat file to see what mappings are currently available.

    • language = x
      Specifies which language file to use for error messages and other bits of system text. The parameter is the name of a translation file, and can either be a fully qualified file path or a basename like "en" or "sp". If the latter, Allegro will look first for a separate config file with a name in the form "entext.cfg", and then for an object with that name in the language.dat file (eg. "ENTEXT_CFG"). The config file or language.dat file can be stored in the same directory as the program, or in the location pointed to by the ALLEGRO environment variable. Look in the language.dat file to see which mappings are currently available.

    • menu_opening_delay = x
      Sets how long the menus take to auto-open. The time is given in milliseconds (default is 300). Specifying -1 will disable the auto-opening feature.

    • dga_mouse = x
      X only: disable to work around a bug in some X servers' DGA modes, concerning the mouse. Default is on; enable the workaround by setting the variable to "0".

    • dga_centre = x
      X only: instructs the DGA driver to centre the Allegro screen if the actual screen resolution is higher than Allegro's. Default is on; disable this feature by setting the variable to "0".

    • dga_clear = x
      X only: instructs the DGA driver to clear visible video memory on startup. Default is on; disable this feature by setting the variable to "0".

  • [graphics]
    Section containing graphics configuration information, using the variables:

    • gfx_card = x
      Specifies which graphics driver to use when the program requests GFX_AUTODETECT. Multiple possible drivers can be suggested with extra lines in the form "gfx_card1 = x", "gfx_card2 = x", etc, or you can specify different drivers for each mode and color depth with variables in the form "gfx_card_24bpp = x", "gfx_card_640x480x16 = x", etc.

    • gfx_cardw = x
      Specifies which graphics driver to use when the program requests GFX_AUTODETECT_WINDOWED. This variable functions exactly like gfx_card in all other respects. If it is not set, Allegro will look for the gfx_card variable.

    • vbeaf_driver = x
      DOS and Linux only: specifies where to look for the VBE/AF driver (vbeaf.drv). If this variable is not set, Allegro will look in the same directory as the program, and then fall back on the standard locations (c:\ for DOS, /usr/local/lib, /usr/lib, /lib, and / for Linux, or the directory specified with the VBEAF_PATH environment variable).

    • framebuffer = x
      Linux only: specifies what device file to use for the fbcon driver. If this variable is not set, Allegro checks the FRAMEBUFFER environment variable, and then defaults to /dev/fb0.

    • force_centering = x
      Unix/X11 only: specifies whether to force window centering in fullscreen mode when the XWFS driver is used (yes or no). Enabling this setting may cause some artifacts to appear on KDE desktops.

    • disable_direct_updating = x
      Windows only: specifies whether to disable direct updating when the GFX_DIRECTX_WIN driver is used in color conversion mode (yes or no). Direct updating can cause artifacts to be left on the desktop when the window is moved or minimized; disabling it results in a significant performance loss.

  • [mouse]
    Section containing mouse configuration information, using the variables:

    • mouse = x
      Mouse driver type. Available DOS drivers are:
            MICK - mickey mode driver (normally the best)
      I33  - int 0x33 callback driver
      POLL - timer polling (for use under NT)
      Linux console mouse drivers are:
            MS   - Microsoft serial mouse
      IMS  - Microsoft serial mouse with Intellimouse extension
      LPS2 - PS2 mouse
      LIPS - PS2 mouse with Intellimouse extension
      GPMD - GPM repeater data (Mouse Systems protocol)

    • num_buttons = x
      Sets the number of mouse buttons viewed by Allegro. You don't normally need to set this variable because Allegro will autodetect it. You can only use it to restrict the set of actual mouse buttons.

    • emulate_three = x
      Sets whether to emulate a third mouse button by detecting chords of the left and right buttons (yes or no). Defaults to yes if you have a two button mouse, no otherwise.

    • mouse_device = x
      Linux only: specifies the name of the mouse device file (eg. /dev/mouse).

    • mouse_accel_factor = x
      Windows only: specifies the mouse acceleration factor. Defaults to 1. Set it to 0 in order to disable mouse acceleration. 2 accelerates twice as much as 1.

  • [sound]
    Section containing sound configuration information, using the variables:

    • digi_card = x
      Sets the driver to use for playing digital samples.

    • midi_card = x
      Sets the driver to use for MIDI music.

    • digi_input_card = x
      Sets the driver to use for digital sample input.

    • midi_input_card = x
      Sets the driver to use for MIDI data input.

    • digi_voices = x
      Specifies the minimum number of voices to reserve for use by the digital sound driver. How many are possible depends on the driver.

    • midi_voices = x
      Specifies the minimum number of voices to reserve for use by the MIDI sound driver. How many are possible depends on the driver.

    • digi_volume = x
      Sets the volume for digital sample playback, from 0 to 255.

    • midi_volume = x
      Sets the volume for midi music playback, from 0 to 255.

    • quality = x
      Controls the sound quality vs. performance tradeoff for the sample mixing code. This can be set to any of the values:
            0 - fast mixing of 8 bit data into 16 bit buffers
      1 - true 16 bit mixing (requires a 16 bit stereo soundcard)
      2 - interpolated 16 bit mixing

    • flip_pan = x
      Toggling this between 0 and 1 reverses the left/right panning of samples, which might be needed because some SB cards (including mine :-) get the stereo image the wrong way round.

    • sound_freq = x
      DOS, Unix and BeOS: sets the sample frequency. With the SB driver, possible rates are 11906 (any), 16129 (any), 22727 (SB 2.0 and above), and 45454 (only on SB 2.0 or SB16, not the stereo SB Pro driver). On the ESS Audiodrive, possible rates are 11363, 17046, 22729, or 44194. On the Ensoniq Soundscape, possible rates are 11025, 16000, 22050, or 48000. On the Windows Sound System, possible rates are 11025, 22050, 44100, or 48000. Don't worry if you set some other number by mistake: Allegro will automatically round it to the closest supported frequency.

    • sound_bits = x
      Unix and BeOS: sets the preferred number of bits (8 or 16).

    • sound_stereo = x
      Unix and BeOS: selects mono or stereo output (0 or 1).

    • sound_port = x
      DOS only: sets the soundcard port address (this is usually 220).

    • sound_dma = x
      DOS only: sets the soundcard DMA channel (this is usually 1).

    • sound_irq = x
      DOS only: sets the soundcard IRQ number (this is usually 7).

    • fm_port = x
      DOS only: sets the port address of the OPL synth (this is usually 388).

    • mpu_port = x
      DOS only: sets the port address of the MPU-401 MIDI interface (this is usually 330).

    • mpu_irq = x
      DOS only: sets the IRQ for the MPU-401 (this is usually the same as sound_irq).

    • ibk_file = x
      DOS only: specifies the name of a .IBK file which will be used to replace the standard Adlib patch set.

    • ibk_drum_file = x
      DOS only: specifies the name of a .IBK file which will be used to replace the standard set of Adlib percussion patches.

    • oss_driver = x
      Unix only: sets the OSS device driver name. Usually /dev/dsp or /dev/audio, but could be a particular device (e.g. /dev/dsp2).

    • oss_numfrags = x
      oss_fragsize = x
      Unix only: sets number of OSS driver fragments (buffers) and size of each buffer in samples. Buffers are filled with data in the interrupts where interval between subsequent interrupts is not less than 10 ms. If hardware can play all information from buffers faster than 10 ms, then there will be clicks, when hardware have played all data and library has not prepared new data yet. On the other hand, if it takes too long for device driver to play data from all buffers, then there will be delays between action which triggers sound and sound itself.

    • oss_midi_driver = x
      Unix only: sets the OSS MIDI device name. Usually /dev/sequencer.

    • oss_mixer_driver = x
      Unix only: sets the OSS mixer device name. Usually /dev/mixer.

    • esd_server = x
      Unix only: where to find the ESD (Enlightened Sound Daemon) server.

    • alsa_card = x
      alsa_pcmdevice = x
      Unix only: paramaters for the ALSA sound driver system.

    • alsa_numfrags = x
      Unix only: number of ALSA driver fragments (buffers).

    • alsa_fragsize = x
      Unix only: size of each ALSA fragment, in samples.

    • alsa_rawmidi_card = x
      Unix only: ALSA card to use for midi output.

    • alsa_rawmidi_device = x
      Unix only: ALSA rawmidi device to use for output.

    • be_midi_quality = x
      BeOS only: system MIDI synthesizer instruments quality. 0 uses low quality 8-bit 11 kHz samples, 1 uses 16-bit 22 kHz samples.

    • be_midi_freq = x
      BeOS only: MIDI sample mixing frequency in Hz. Can be 11025, 22050 or 44100.

    • be_midi_interpolation = x
      BeOS only: specifies the MIDI samples interpolation method. 0 doesn't interpolate, it's fast but has the worst quality; 1 does a fast interpolation with better performances, but it's a bit slower than the previous method; 2 does a linear interpolation between samples, it is the slowest method but gives the best performances.

    • be_midi_reverb = x
      BeOS only: reverberation intensity, from 0 to 5. 0 disables it, 5 is the strongest one.

    • patches = x
      Specifies where to find the sample set for the DIGMID driver. This can either be a Gravis style directory containing a collection of .pat files and a default.cfg index, or an Allegro datafile produced by the pat2dat utility. If this variable is not set, Allegro will look either for a default.cfg or patches.dat file in the same directory as the program, the directory pointed to by the ALLEGRO environment variable, and the standard GUS directory pointed to by the ULTRASND environment variable.

  • [midimap]
    If you are using the SB MIDI output or MPU-401 drivers with an external synthesiser that is not General MIDI compatible, you can use the midimap section of the config file to specify a patch mapping table for converting GM patch numbers into whatever bank and program change messages will select the appropriate sound on your synth. This is a real piece of self-indulgence. I have a Yamaha TG500, which has some great sounds but no GM patch set, and I just had to make it work somehow...

    This section consists of a set of lines in the form:

    • p<n> = bank0 bank1 prog pitch
      With this statement, n is the GM program change number (1-128), bank0 and bank1 are the two bank change messages to send to your synth (on controllers #0 and #32), prog is the program change message to send to your synth, and pitch is the number of semitones to shift everything that is played with that sound. Setting the bank change numbers to -1 will prevent them from being sent.

      For example, the line:

      p36 = 0 34 9 12

      specifies that whenever GM program 36 (which happens to be a fretless bass) is selected, Allegro should send a bank change message #0 with a parameter of 0, a bank change message #32 with a parameter of 34, a program change with a parameter of 9, and then should shift everything up by an octave.

  • [joystick]
    Section containing joystick configuration information, using the variables:

    • joytype = x
      Specifies which joystick driver to use when the program requests JOY_TYPE_AUTODETECT.

    • joystick_device = x
      BeOS only: specifies the name of the joystick device to be used. First device found is used by default.

    • throttle_axis = x
      Linux only: sets which axis number the throttle is located at. This variable will be used for every detected joystick. If you want to specify the axis number for each joystick individually, use variables of the form throttle_axis_n, where n is the joystick number.


Mouse routines

  • freeze_mouse_flag
  • get_mouse_mickeys
  • install_mouse
  • mouse_b
  • mouse_callback
  • mouse_needs_poll
  • mouse_pos
  • mouse_sprite
  • mouse_x
  • mouse_x_focus
  • mouse_y
  • mouse_y_focus
  • mouse_z
  • poll_mouse
  • position_mouse
  • position_mouse_z
  • remove_mouse
  • scare_mouse
  • scare_mouse_area
  • set_mouse_range
  • set_mouse_speed
  • set_mouse_sprite
  • set_mouse_sprite_focus
  • show_mouse
  • unscare_mouse

int install_mouse();
Installs the Allegro mouse handler. You must do this before using any other mouse functions. Returns -1 on failure, otherwise the number of buttons on the mouse.

void remove_mouse();
Removes the mouse handler. You don't normally need to bother calling this, because allegro_exit() will do it for you.

int poll_mouse();
Wherever possible, Allegro will read the mouse input asynchronously (ie. from inside an interrupt handler), but on some platforms that may not be possible, in which case you must call this routine at regular intervals to update the mouse state variables. To help you test your mouse polling code even if you are programming on a platform that doesn't require it, after the first time that you call this function Allegro will switch into polling mode, so from that point onwards you will have to call this routine in order to get any mouse input at all, regardless of whether the current driver actually needs to be polled or not. Returns zero on success, or a negative number on failure (ie. no mouse driver installed).

int mouse_needs_poll();
Returns TRUE if the current mouse driver is operating in polling mode.

extern volatile int mouse_x;
extern volatile int mouse_y;
extern volatile int mouse_z;
extern volatile int mouse_b;
extern volatile int mouse_pos;
Global variables containing the current mouse position and button state. Wherever possible these values will be updated asynchronously, but if mouse_needs_poll() returns TRUE, you must manually call poll_mouse() to update them with the current input state. The mouse_x and mouse_y positions are integers ranging from zero to the bottom right corner of the screen. The mouse_z variable holds the current wheel position, when using an input driver that supports wheel mice. The mouse_b variable is a bitfield indicating the state of each button: bit 0 is the left button, bit 1 the right, and bit 2 the middle button. For example:

      if (mouse_b & 1)
         printf("Left button is pressed\n");

      if (!(mouse_b & 2))
         printf("Right button is not pressed\n");
The mouse_pos variable has the current X coordinate in the high word and the Y in the low word. This may be useful in tight polling loops where a mouse interrupt could occur between your reading of the two separate variables, since you can copy this value into a local variable with a single instruction and then split it up at your leisure.

extern BITMAP *mouse_sprite;
extern int mouse_x_focus;
extern int mouse_y_focus;
Global variables containing the current mouse sprite and the focus
   point.  These are read-only, and only to be modified using the
   set_mouse_sprite() and set_mouse_sprite_focus() functions.

void show_mouse(BITMAP *bmp);
Tells Allegro to display a mouse pointer on the screen. This will only work if the timer module has been installed. The mouse pointer will be drawn onto the specified bitmap, which should normally be 'screen' (see later for information about bitmaps). To hide the mouse pointer, call show_mouse(NULL). Warning: if you draw anything onto the screen while the pointer is visible, a mouse movement interrupt could occur in the middle of your drawing operation. If this happens the mouse buffering and SVGA bank switching code will get confused and will leave 'mouse droppings' all over the screen. To prevent this, you must make sure you turn off the mouse pointer whenever you draw onto the screen.

void scare_mouse();
Helper for hiding the mouse pointer prior to a drawing operation. This will temporarily get rid of the pointer, but only if that is really required (ie. the mouse is visible, and is displayed on the physical screen rather than some other memory surface, and it is not a hardware cursor). The previous mouse state is stored for subsequent calls to unscare_mouse().

void scare_mouse_area(int x, int y, int w, int h);
Like scare_mouse(), but will only hide the cursor if it is inside the specified rectangle. Otherwise the cursor will simply be frozen in place until you call unscare_mouse(), so it cannot interfere with your drawing.

void unscare_mouse();
Undoes the effect of a previous call to scare_mouse() or scare_mouse_area(), restoring the original pointer state.

extern volatile int freeze_mouse_flag;
If this flag is set, the mouse pointer won't be redrawn when the mouse moves. This can avoid the need to hide the pointer every time you draw to the screen, as long as you make sure your drawing doesn't overlap with the current pointer position.

void position_mouse(int x, int y);
Moves the mouse to the specified screen position. It is safe to call even when a mouse pointer is being displayed.

void position_mouse_z(int z);
Sets the mouse wheel position variable to the specified value.

void set_mouse_range(int x1, int y1, int x2, int y2);
Sets the area of the screen within which the mouse can move. Pass the top left corner and the bottom right corner (inclusive). If you don't call this function the range defaults to (0, 0, SCREEN_W-1, SCREEN_H-1).

void set_mouse_speed(int xspeed, int yspeed);
Sets the mouse speed. Larger values of xspeed and yspeed represent slower mouse movement: the default for both is 2.

void set_mouse_sprite(BITMAP *sprite);
You don't like my mouse pointer? No problem. Use this function to supply an alternative of your own. If you change the pointer and then want to get my lovely arrow back again, call set_mouse_sprite(NULL).

As a bonus, set_mouse_sprite(NULL) uses the current palette in choosing colors for the arrow. So if your arrow mouse sprite looks ugly after changing the palette, call set_mouse_sprite(NULL).

void set_mouse_sprite_focus(int x, int y);
The mouse focus is the bit of the pointer that represents the actual mouse position, ie. the (mouse_x, mouse_y) position. By default this is the top left corner of the arrow, but if you are using a different mouse pointer you might need to alter it.

void get_mouse_mickeys(int *mickeyx, int *mickeyy);
Measures how far the mouse has moved since the last call to this function. The mouse will continue to generate movement mickeys even when it reaches the edge of the screen, so this form of input can be useful for games that require an infinite range of mouse movement.

extern void (*mouse_callback)(int flags);
Called by the interrupt handler whenever the mouse moves or one of the buttons changes state. This function must be in locked memory, and must execute _very_ quickly! It is passed the event flags that triggered the call, which is a bitmask containing any of the values MOUSE_FLAG_MOVE, MOUSE_FLAG_LEFT_DOWN, MOUSE_FLAG_LEFT_UP, MOUSE_FLAG_RIGHT_DOWN, MOUSE_FLAG_RIGHT_UP, MOUSE_FLAG_MIDDLE_DOWN, MOUSE_FLAG_MIDDLE_UP, and MOUSE_FLAG_MOVE_Z.


Timer routines

  • install_int
  • install_int_ex
  • install_param_int
  • install_param_int_ex
  • install_timer
  • remove_int
  • remove_param_int
  • remove_timer
  • rest
  • rest_callback
  • retrace_count
  • retrace_proc
  • timer_can_simulate_retrace
  • timer_is_using_retrace
  • timer_simulate_retrace

Allegro can set up several virtual timer functions, all going at different speeds.

Under DOS it will constantly reprogram the clock to make sure they are all called at the correct times. Because they alter the low level timer chip settings, these routines should not be used together with other DOS timer functions like the djgpp uclock() routine. Moreover, the FPU state is not preserved across Allegro interrupts so you ought not to use floating point or MMX code inside timer interrupt handlers.

Under other platforms, they are usually implemented using threads, which run parallel to the main thread. Therefore timer callbacks on such platforms will not block the main thread when called, so you may need to use appropriate synchronisation devices (eg. mutexes, semaphores, etc.) when accessing data that is shared by a callback and the main thread. (Currently Allegro does not provide such devices.)

int install_timer();
Installs the Allegro timer interrupt handler. You must do this before installing any user timer routines, and also before displaying a mouse pointer, playing FLI animations or MIDI music, and using any of the GUI routines. Returns zero on success, or a negative number on failure (but you may decide not to check the return value as this function is very unlikely to fail).

void remove_timer();
Removes the Allegro timer handler (and, under DOS, passes control of the clock back to the operating system). You don't normally need to bother calling this, because allegro_exit() will do it for you.

int install_int(void (*proc)(), int speed);
Installs a user timer handler, with the speed given as the number of milliseconds between ticks. This is the same thing as install_int_ex(proc, MSEC_TO_TIMER(speed)). If you call this routine without having first installed the timer module, install_timer() will be called automatically. If there is no room to add a new user timer, install_int() will return a negative number, otherwise it returns zero.

int install_int_ex(void (*proc)(), int speed);
Adds a function to the list of user timer handlers or, if it is already installed, retroactively adjusts its speed (i.e makes as though the speed change occured precisely at the last tick). The speed is given in hardware clock ticks, of which there are 1193181 a second. You can convert from other time formats to hardware clock ticks with the macros:

      SECS_TO_TIMER(secs)  - give the number of seconds between
                             each tick
      MSEC_TO_TIMER(msec)  - give the number of milliseconds
                             between ticks
      BPS_TO_TIMER(bps)    - give the number of ticks each second
      BPM_TO_TIMER(bpm)    - give the number of ticks per minute
If there is no room to add a new user timer, install_int_ex() will return a negative number, otherwise it returns zero. There can only be sixteen timers in use at a time, and some other parts of Allegro (the GUI code, the mouse pointer display routines, rest(), the FLI player, and the MIDI player) need to install handlers of their own, so you should avoid using too many at the same time. If you call this routine without having first installed the timer module, install_timer() will be called automatically.

Your function will be called by the Allegro interrupt handler and not directly by the processor, so it can be a normal C function and does not need a special wrapper. You should be aware, however, that it will be called in an interrupt context, which imposes a lot of restrictions on what you can do in it. It should not use large amounts of stack, it must not make any calls to the operating system, use C library functions, or contain any floating point code, and it must execute very quickly. Don't try to do lots of complicated code in a timer handler: as a general rule you should just set some flags and respond to these later in your main control loop.

In a DOS protected mode environment like djgpp, memory is virtualised and can be swapped to disk. Due to the non-reentrancy of DOS, if a disk swap occurs inside an interrupt handler the system will die a painful death, so you need to make sure you lock all the memory (both code and data) that is touched inside timer routines. Allegro will lock everything it uses, but you are responsible for locking your handler functions. The macros LOCK_VARIABLE (variable), END_OF_FUNCTION (function_name), END_OF_STATIC_FUNCTION (function_name), and LOCK_FUNCTION (function_name) can be used to simplify this task. For example, if you want an interrupt handler that increments a counter variable, you should write:

      volatile int counter;

      void my_timer_handler()
      {
         counter++;
      }

      END_OF_FUNCTION(my_timer_handler)
and in your initialisation code you should lock the memory:

      LOCK_VARIABLE(counter);
      LOCK_FUNCTION(my_timer_handler);
Obviously this can get awkward if you use complicated data structures and call other functions from within your handler, so you should try to keep your interrupt routines as simple as possible.

void remove_int(void (*proc)());
Removes a function from the list of user interrupt routines. At program termination, allegro_exit() does this automatically.

int install_param_int(void (*proc)(void *), void *param, int speed);
Like install_int(), but the callback routine will be passed a copy of the specified void pointer parameter. To disable the handler, use remove_param_int() instead of remove_int().

int install_param_int_ex(void (*proc)(void *), void *param, int speed);
Like install_int_ex(), but the callback routine will be passed a copy of the specified void pointer parameter. To disable the handler, use remove_param_int() instead of remove_int().

void remove_param_int(void (*proc)(void *), void *param);
Like remove_int(), but for use with timer callbacks that have parameter values. If there is more than one copy of the same callback active at a time, it identifies which one to remove by checking the parameter value (so you can't have more than one copy of a handler using an identical parameter).

int timer_can_simulate_retrace()
Checks whether it is possible to sync the timer module with the monitor retrace, given the current platform and environment (at the moment this is only possible when running in clean DOS mode in a VGA or mode-X resolution). Returns non-zero if simulation is possible.

void timer_simulate_retrace(int enable);
The DOS timer handler can be used to simulate vertical retrace interrupts. A retrace interrupt can be extremely useful for implementing smooth animation, but unfortunately the VGA hardware doesn't support it. The EGA did, and some SVGA chipsets do, but not enough, and not in a sufficiently standardised way, for it to be useful. Allegro works around this by programming the timer to generate an interrupt when it thinks a retrace is next likely to occur, and polling the VGA inside the interrupt handler to make sure it stays in sync with the monitor refresh. This works quite well in some situations, but there are a lot of caveats:

- You can't use the retrace simulator in SVGA modes. It will work with some chipsets, but not others, and it conflicts with most VESA implementations. Retrace simulation is only reliable in VGA mode 13h and mode-X.

- Retrace simulation doesn't work under win95, because win95 returns garbage when I try to read the elapsed time from the PIT. If anyone knows how I can make this work, please tell me!

- Retrace simulation involves a lot of waiting around in the timer handler with interrupts disabled. This will significantly slow down your entire system, and may also cause static when playing samples on SB 1.0 cards (because they don't support auto-initialised DMA: SB 2.0 and above will be fine).

Bearing all those problems in mind, I'd strongly advise against relying on the retrace simulator. If you are coding in mode-X, and don't care about your program working under win95, it is great, but it would be a good idea to give the user an option to disable it.

Retrace simulation must be enabled before you use the triple buffering functions in a mode-X resolution. It can also be useful for simple retrace detection, because the polling vsync() function can occasionally miss retraces if a soundcard or timer interrupt occurs at exactly the same time as the retrace. When retrace interrupt simulation is enabled, vsync() will check the retrace_count variable rather than polling the VGA, so it won't miss retraces even if they are masked by other interrupts.

int timer_is_using_retrace()
Checks whether the timer module is currently synced with the monitor retrace or not. Returns non-zero if it is.

extern volatile int retrace_count;
If the retrace simulator is installed, this is incremented on each vertical retrace, otherwise it is incremented 70 times a second (ignoring retraces). This provides a useful way of controlling the speed of your program without the hassle of installing user timer functions.

The speed of retraces varies depending on the graphics mode. In mode 13h and 200/400 line mode-X resolutions there are 70 retraces a second, and in 240/480 line modes there are 60. It can be as low as 50 (in 376x282 mode) or as high as 92 (in 400x300 mode).

extern void (*retrace_proc)();
If the retrace simulator is installed, this function is called during every vertical retrace, otherwise it is called 70 times a second (ignoring retraces). Set it to NULL to disable the callback. The function must obey the same rules as regular timer handlers (ie. it must be locked, and mustn't call OS or libc functions) but even more so: it must execute _very_ quickly, or it will mess up the timer synchronisation. The only use I can see for this function is for doing palette manipulations, because triple buffering can be done with the request_scroll() function, and the retrace_count variable can be used for timing your code. If you want to alter the palette in the retrace_proc you should use the inline _set_color() function rather than the regular set_color() or set_palette(), and you shouldn't try to alter more than two or three palette entries in a single retrace.

void rest(long time);
Once Allegro has taken over the timer the standard delay() function will no longer work, so you should use this routine instead. The time is given in milliseconds.

void rest_callback(long time, void (*callback)())
Like rest(), but continually calls the specified function while it is waiting for the required time to elapse.


Keyboard routines

  • clear_keybuf
  • install_keyboard
  • install_keyboard_hooks
  • key
  • key_led_flag
  • key_shifts
  • keyboard_callback
  • keyboard_lowlevel_callback
  • keyboard_needs_poll
  • keyboard_ucallback
  • keypressed
  • poll_keyboard
  • readkey
  • remove_keyboard
  • scancode_to_ascii
  • set_keyboard_rate
  • set_leds
  • simulate_keypress
  • simulate_ukeypress
  • three_finger_flag
  • ureadkey

The Allegro keyboard handler provides both buffered input and a set of flags storing the current state of each key. Note that it is not possible to correctly detect every combination of keys, due to the design of the PC keyboard. Up to two or three keys at a time will work fine, but if you press more than that the extras are likely to be ignored (exactly which combinations are possible seems to vary from one keyboard to another).

int install_keyboard();
Installs the Allegro keyboard interrupt handler. You must call this before using any of the keyboard input routines. Once you have set up the Allegro handler, you can no longer use operating system calls or C library functions to access the keyboard. Returns zero on success, or a negative number on failure (but you may decide not to check the return value as this function is very unlikely to fail). Note that on some platforms the keyboard won't work unless you have set a graphic mode, even if this function returns zero before calling set_gfx_mode.

void remove_keyboard();
Removes the keyboard handler, returning control to the operating system. You don't normally need to bother calling this, because allegro_exit() will do it for you.

void install_keyboard_hooks(int (*keypressed)(), int (*readkey)());
You should only use this function if you *aren't* using the rest of the keyboard handler. It should be called in the place of install_keyboard(), and lets you provide callback routines to detect and read keypresses, which will be used by the main keypressed() and readkey() functions. This can be useful if you want to use Allegro's GUI code with a custom keyboard handler, as it provides a way for the GUI to get keyboard input from your own code, bypassing the normal Allegro input system.

int poll_keyboard();
Wherever possible, Allegro will read the keyboard input asynchronously (ie. from inside an interrupt handler), but on some platforms that may not be possible, in which case you must call this routine at regular intervals to update the keyboard state variables. To help you test your keyboard polling code even if you are programming on a platform that doesn't require it, after the first time that you call this function Allegro will switch into polling mode, so from that point onwards you will have to call this routine in order to get any keyboard input at all, regardless of whether the current driver actually needs to be polled or not. The keypressed(), readkey(), and ureadkey() functions call poll_keyboard() automatically, so you only need to use this function when accessing the key[] array and key_shifts variable. Returns zero on success, or a negative number on failure (ie. no keyboard driver installed).

int keyboard_needs_poll();
Returns TRUE if the current keyboard driver is operating in polling mode.

extern volatile char key[KEY_MAX];
Array of flags indicating the state of each key, ordered by scancode. Wherever possible these values will be updated asynchronously, but if keyboard_needs_poll() returns TRUE, you must manually call poll_keyboard() to update them with the current input state. The scancodes are defined in allegro/keyboard.h as a series of KEY_* constants (and are also listed below). For example, you could write:

      if (key[KEY_SPACE])
         printf("Space is pressed\n");

Note that the array is supposed to represent which keys are physically held down and which keys are not, so it is semantically read-only.

These are the keyboard scancodes:

      KEY_A ... KEY_Z,
      KEY_0 ... KEY_9,
      KEY_0_PAD ... KEY_9_PAD,
      KEY_F1 ... KEY_F12,

      KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS,
      KEY_BACKSPACE, KEY_TAB, KEY_OPENBRACE, KEY_CLOSEBRACE,
      KEY_ENTER, KEY_COLON, KEY_QUOTE, KEY_BACKSLASH,
      KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH,
      KEY_SPACE,

      KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP,
      KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,

      KEY_SLASH_PAD, KEY_ASTERISK, KEY_MINUS_PAD,
      KEY_PLUS_PAD, KEY_DEL_PAD, KEY_ENTER_PAD,

      KEY_PRTSCR, KEY_PAUSE,

      KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT,
      KEY_AT, KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI,

      KEY_LSHIFT, KEY_RSHIFT,
      KEY_LCONTROL, KEY_RCONTROL,
      KEY_ALT, KEY_ALTGR,
      KEY_LWIN, KEY_RWIN, KEY_MENU,
      KEY_SCRLOCK, KEY_NUMLOCK, KEY_CAPSLOCK
extern volatile int key_shifts;
Bitmask containing the current state of shift/ctrl/alt, the special Windows keys, and the accent escape characters. Wherever possible this value will be updated asynchronously, but if keyboard_needs_poll() returns TRUE, you must manually call poll_keyboard() to update it with the current input state. This can contain any of the flags:

KB_SHIFT_FLAG
KB_CTRL_FLAG
KB_ALT_FLAG
KB_LWIN_FLAG
KB_RWIN_FLAG
KB_MENU_FLAG
KB_SCROLOCK_FLAG
KB_NUMLOCK_FLAG
KB_CAPSLOCK_FLAG
KB_INALTSEQ_FLAG
KB_ACCENT1_FLAG
KB_ACCENT2_FLAG
KB_ACCENT3_FLAG
KB_ACCENT4_FLAG

int keypressed();
Returns TRUE if there are keypresses waiting in the input buffer. This is equivalent to the libc kbhit() function.

int readkey();
Returns the next character from the keyboard buffer, in ASCII format. If the buffer is empty, it waits until a key is pressed. The low byte of the return value contains the ASCII code of the key, and the high byte the scancode. The scancode remains the same whatever the state of the shift, ctrl and alt keys, while the ASCII code is affected by shift and ctrl in the normal way (shift changes case, ctrl+letter gives the position of that letter in the alphabet, eg. ctrl+A = 1, ctrl+B = 2, etc). Pressing alt+key returns only the scancode, with a zero ASCII code in the low byte. For example:

      if ((readkey() & 0xff) == 'd')         // by ASCII code
         printf("You pressed 'd'\n");

      if ((readkey() >> 8) == KEY_SPACE)     // by scancode
         printf("You pressed Space\n");

      if ((readkey() & 0xff) == 3)           // ctrl+letter
         printf("You pressed Control+C\n");

      if (readkey() == (KEY_X << 8))         // alt+letter
         printf("You pressed Alt+X\n");
This function cannot return character values greater than 255. If you need to read Unicode input, use ureadkey() instead.

int ureadkey(int *scancode);
Returns the next character from the keyboard buffer, in Unicode format. If the buffer is empty, it waits until a key is pressed. The return value contains the Unicode value of the key, and if not NULL, the pointer argument will be set to the scancode. Unlike readkey(), this function is able to return character values greater than 255.

int scancode_to_ascii(int scancode);
Converts the given scancode to an ASCII character for that key, returning the unshifted uncapslocked result of pressing the key, or zero if the key isn't a character-generating key or the lookup can't be done.

void simulate_keypress(int key);
Stuffs a key into the keyboard buffer, just as if the user had pressed it. The parameter is in the same format returned by readkey().

void simulate_ukeypress(int key, int scancode);
Stuffs a key into the keyboard buffer, just as if the user had pressed it. The parameter is in the same format returned by ureadkey().

extern int (*keyboard_callback)(int key);
If set, this function is called by the keyboard handler in response to every keypress. It is passed a copy of the value that is about to be added into the input buffer, and can either return this value unchanged, return zero to cause the key to be ignored, or return a modified value to change what readkey() will later return. This routine executes in an interrupt context, so it must be in locked memory.

extern int (*keyboard_ucallback)(int key, int *scancode);
Unicode-aware version of keyboard_callback(). If set, this function is called by the keyboard handler in response to every keypress. It is passed the character value and scancode that are about to be added into the input buffer, can modify the scancode value, and returns a new or modified key code. If it both sets the scancode to zero and returns zero, the keypress will be ignored. This routine executes in an interrupt context, so it must be in locked memory.

extern void (*keyboard_lowlevel_callback)(int scancode);
If set, this function is called by the keyboard handler in response to every keyboard event, both presses and releases. It will be passed a raw keyboard scancode byte, with the top bit clear if the key has been pressed or set if it was released. This routine executes in an interrupt context, so it must be in locked memory.

void set_leds(int leds);
Overrides the state of the keyboard LED indicators. The parameter is a bitmask containing any of the values KB_SCROLOCK_FLAG, KB_NUMLOCK_FLAG, and KB_CAPSLOCK_FLAG, or -1 to restore the default behavior.

void set_keyboard_rate(int delay, int repeat);
Sets the keyboard repeat rate. Times are given in milliseconds. Passing zero times will disable the key repeat.

void clear_keybuf();
Empties the keyboard buffer.

extern int three_finger_flag;
The djgpp keyboard handler provides an 'emergency exit' sequence which you can use to kill off your program. If you are running under DOS this is the three finger salute, ctrl+alt+del. Most multitasking OS's will trap this combination before it reaches the Allegro handler, in which case you can use the alternative ctrl+alt+end. If you want to disable this behaviour in release versions of your program, set this flag to FALSE.

extern int key_led_flag;
By default, the capslock, numlock, and scroll-lock keys toggle the keyboard LED indicators when they are pressed. If you are using these keys for input in your game (eg. capslock to fire) this may not be desirable, so you can clear this flag to prevent the LED's being updated.


Joystick routines

  • calibrate_joystick
  • calibrate_joystick_name
  • initialise_joystick
  • install_joystick
  • joy
  • load_joystick_data
  • num_joysticks
  • poll_joystick
  • remove_joystick
  • save_joystick_data

int install_joystick(int type);
Initialises the joystick, and calibrates the centre position value. The type parameter should usually be JOY_TYPE_AUTODETECT, or see the platform specific documentation for a list of the available drivers. You must call this routine before using any other joystick functions, and you should make sure that the joystick is in the middle position at the time. Returns zero on success. As soon as you have installed the joystick module, you will be able to read the button state and digital (on/off toggle) direction information, which may be enough for some games. If you want to get full analogue input, though, you need to use the calibrate_joystick() functions to measure the exact range of the inputs: see below.

void remove_joystick();
Removes the joystick handler. You don't normally need to bother calling this, because allegro_exit() will do it for you.

int poll_joystick();
The joystick is not interrupt driven, so you need to call this function every now and again to update the global position values. Returns zero on success or a negative number on failure (usually because no joystick driver was installed).

extern int num_joysticks;
Global variable containing the number of active joystick devices. The current drivers support a maximum of four controllers.

extern JOYSTICK_INFO joy[n];
Global array of joystick state information, which is updated by the poll_joystick() function. Only the first num_joysticks elements will contain meaningful information. The JOYSTICK_INFO structure is defined as:

   typedef struct JOYSTICK_INFO
   {
      int flags;                       - status flags for this
                                         joystick
      int num_sticks;                  - how many stick inputs?
      int num_buttons;                 - how many buttons?
      JOYSTICK_STICK_INFO stick[n];    - stick state information
      JOYSTICK_BUTTON_INFO button[n];  - button state information
   } JOYSTICK_INFO;
The button status is stored in the structure:

   typedef struct JOYSTICK_BUTTON_INFO
   {
      int b;                           - boolean on/off flag
      char *name;                      - description of this
                                         button
   } JOYSTICK_BUTTON_INFO;
You may wish to display the button names as part of an input configuration screen to let the user choose what game function will be performed by each button, but in simpler situations you can safely assume that the first two elements in the button array will always be the main trigger controls.

Each joystick will provide one or more stick inputs, of varying types. These can be digital controls which snap to specific positions (eg. a gamepad controller, the coolie hat on a Flightstick Pro or Wingman Extreme, or a normal joystick which hasn't yet been calibrated), or they can be full analogue inputs with a smooth range of motion. Sticks may also have different numbers of axis, for example a normal directional control has two, but the Flightstick Pro throttle is only a single axis, and it is possible that the system could be extended in the future to support full 3d controllers. A stick input is described by the structure:

   typedef struct JOYSTICK_STICK_INFO
   {
      int flags;                       - status flags for this
                                         input
      int num_axis;                    - how many axis do we
                                         have?
      JOYSTICK_AXIS_INFO axis[n];      - axis state information
      char *name;                      - description of this
                                         input
   } JOYSTICK_STICK_INFO;
A single joystick may provide several different stick inputs, but you can safely assume that the first element in the stick array will always be the main directional controller.

Information about each of the stick axis is stored in the substructure:

   typedef struct JOYSTICK_AXIS_INFO
   {
      int pos;                         - analogue axis position
      int d1, d2;                      - digital axis position
      char *name;                      - description of this axis
   } JOYSTICK_AXIS_INFO;
This provides both analogue input in the pos field (ranging from -128 to 128 or from 0 to 255, depending on the type of the control), and digital values in the d1 and d2 fields. For example, when describing the X-axis position, the pos field will hold the horizontal position of the joystick, d1 will be set if it is moved left, and d2 will be set if it is moved right. Allegro will fill in all these values regardless of whether it is using a digital or analogue joystick, emulating the pos field for digital inputs by snapping it to the min, middle, and maximum positions, and emulating the d1 and d2 values for an analogue stick by comparing the current position with the centre point.

The joystick flags field may contain any combination of the bit flags:

JOYFLAG_DIGITAL
This control is currently providing digital input.

JOYFLAG_ANALOGUE
This control is currently providing analogue input.

JOYFLAG_CALIB_DIGITAL
This control will be capable of providing digital input once it has been calibrated, but is not doing this at the moment.

JOYFLAG_CALIB_ANALOGUE
This control will be capable of providing analogue input once it has been calibrated, but is not doing this at the moment.

JOYFLAG_CALIBRATE
Indicates that this control needs to be calibrated. Many devices require multiple calibration steps, so you should call the calibrate_joystick() function from a loop until this flag is cleared.

JOYFLAG_SIGNED
Indicates that the analogue axis position is in signed format, ranging from -128 to 128. This is the case for all 2d directional controls.

JOYFLAG_UNSIGNED
Indicates that the analogue axis position is in unsigned format, ranging from 0 to 255. This is the case for all 1d throttle controls.

Note for people who spell funny: in case you don't like having to type "analogue", there are some #define aliases in allegro/joystick.h that will allow you to write "analog" instead.

const char *calibrate_joystick_name(int n);
Returns a text description for the next type of calibration that will be done on the specified joystick, or NULL if no more calibration is required.

int calibrate_joystick(int n);
Most joysticks need to be calibrated before they can provide full analogue input. This function performs the next operation in the calibration series for the specified stick, assuming that the joystick has been positioned in the manner described by a previous call to calibrate_joystick_name(), returning zero on success. For example, a simple routine to fully calibrate all the joysticks might look like:

      int i;

      for (i=0; i<;num_joysticks; i++) {
         while (joy[i].flags & JOYFLAG_CALIBRATE) {
            char *msg = calibrate_joystick_name(i);
            printf("%s, and press a key\n", msg);
            readkey();
            if (calibrate_joystick(i) != 0) {
               printf("oops!\n");
               exit(1);
            }
         }
      }
int save_joystick_data(const char *filename);
After all the headache of calibrating the joystick, you may not want to make your poor users repeat the process every time they run your program. Call this function to save the joystick calibration data into the specified configuration file, from which it can later be read by load_joystick_data(). Pass a NULL filename to write the data to the currently selected configuration file. Returns zero on success.

int load_joystick_data(const char *filename);
Restores calibration data previously stored by save_joystick_data() or the setup utility. This sets up all aspects of the joystick code: you don't even need to call install_joystick() if you are using this function. Pass a NULL filename to read the data from the currently selected configuration file. Returns zero on success: if it fails the joystick state is undefined and you must reinitialise it from scratch.

int initialise_joystick();
Deprecated. Use install_joystick() instead.


Graphics modes

  • destroy_gfx_mode_list
  • enable_triple_buffer
  • get_display_switch_mode
  • get_gfx_mode_list
  • get_refresh_rate
  • gfx_capabilities
  • poll_scroll
  • remove_display_switch_callback
  • request_refresh_rate
  • request_scroll
  • request_video_bitmap
  • scroll_screen
  • set_color_depth
  • set_display_switch_callback
  • set_display_switch_mode
  • set_gfx_mode
  • show_video_bitmap

void set_color_depth(int depth);
Sets the pixel format to be used by subsequent calls to set_gfx_mode() and create_bitmap(). Valid depths are 8 (the default), 15, 16, 24, and 32 bits. Note that you can retrieve the pixel format currently in use by calling bitmap_color_depth() on the 'screen' bitmap, once a graphics mode has been set.

void request_refresh_rate(int rate);
Requests that the next call to set_gfx_mode() try to use the specified refresh rate, if possible. Not all drivers are able to control this at all, and even when they can, not all rates will be possible on all hardware, so the actual settings may differ from what you requested. After you call set_gfx_mode(), you can use get_refresh_rate() to find out what was actually selected. At the moment only the DOS VESA 3.0, X DGA 2.0 and some Windows DirectX drivers support this function. The speed is specified in Hz, eg. 60, 70. To return to the normal default selection, pass a rate value of zero.

int get_refresh_rate(void);
Returns the current refresh rate, if known (not all drivers are able to report this information). Returns zero if the actual rate is unknown.

GFX_MODE_LIST *get_gfx_mode_list(int card);
Attempts to create a list of all the supported video modes for a certain graphics driver. This function returns a pointer to a list structure of the type GFX_MODE_LIST which has the following definition:

   typedef struct GFX_MODE_LIST {
      int num_modes;
      GFX_MODE *mode;
   } GFX_MODE_LIST;
If this function returns NULL, it means the call failed. The mode entry points to the actual list of video modes.

   typedef struct GFX_MODE {
      int width, height, bpp;
   } GFX_MODE;
This list is terminated with an { 0, 0, 0 } entry.

Note that the card parameter must refer to a _real_ driver. This function fails if you pass GFX_SAFE, GFX_AUTODETECT, or any other "magic" driver.

void destroy_gfx_mode_list(GFX_MODE_LIST *mode_list);
Removes the mode list created by get_gfx_mode_list() from memory.

int set_gfx_mode(int card, int w, int h, int v_w, int v_h);
Switches into graphics mode. The card parameter should usually be GFX_AUTODETECT, GFX_AUTODETECT_FULLSCREEN or GFX_AUTODETECT_WINDOWED, or see the platform specific documentation for a list of the available drivers. The w and h parameters specify what screen resolution you want.

The v_w and v_h parameters specify the minimum virtual screen size, in case you need a large virtual screen for hardware scrolling or page flipping. You should set them to zero if you don't care about the virtual screen size. Virtual screens can cause a lot of confusion, but they are really quite simple. Warning: patronising explanation coming up, so you may wish to skip the rest of this paragraph :-) Think of video memory as a rectangular piece of paper which is being viewed through a small hole (your monitor) in a bit of cardboard. Since the paper is bigger than the hole you can only see part of it at any one time, but by sliding the cardboard around you can alter which portion of the image is visible. You could just leave the hole in one position and ignore the parts of video memory that aren't visible, but you can get all sorts of useful effects by sliding the screen window around, or by drawing images in a hidden part of video memory and then flipping across to display them.

For example, you could select a 640x480 mode in which the monitor acts as a window onto a 1024x1024 virtual screen, and then move the visible screen around in this larger area. Initially, with the visible screen positioned at the top left corner of video memory, this setup would look like:

      (0,0)------------(640,0)----(1024,0)
        |                  |           |
        |  visible screen  |           |
        |                  |           |
      (0,480)----------(640,480)       |
        |                              |
        |   the rest of video memory   |
        |                              |
      (0,1024)--------------------(1024,1024)
What's that? You are viewing this with a proportional font? Hehehe.

When you call set_gfx_mode(), the v_w and v_h parameters represent the minimum size of virtual screen that is acceptable for your program. The range of possible sizes is usually very restricted, and Allegro is likely to end up creating a virtual screen much larger than the one you request. On an SVGA card with one megabyte of vram you can count on getting a 1024x1024 virtual screen (256 colors) or 1024x512 (15 or 16 bpp), and with 512k vram you can get 1024x512 (256 color). Other sizes may or may not be possible: don't assume that they will work. In mode-X the virtual width can be any multiple of eight greater than or equal to the physical screen width, and the virtual height will be set accordingly (the VGA has 256k of vram, so the virtual height will be 256*1024/virtual_width).

After you select a graphics mode, the physical and virtual screen sizes can be checked with the macros SCREEN_W, SCREEN_H, VIRTUAL_W, and VIRTUAL_H.

If Allegro is unable to select an appropriate mode, set_gfx_mode() returns a negative number and stores a description of the problem in allegro_error. Otherwise it returns zero.

As a special case, if you use the magic driver code GFX_SAFE, Allegro will guarantee that the mode will always be set correctly. It will try to select the resolution that you request, and if that fails, it will fall back upon whatever mode is known to be reliable on the current platform (this is 320x200 VGA mode under DOS, a 640x480 resolution under Windows, the actual framebuffer's resolution under Linux if it's supported, etc). If it absolutely cannot set any graphics mode at all, it will return negative as usual, meaning that there's no possible video output on the machine, and that you should abort your program immediately, possibly after notifying this to the user with allegro_message. This fake driver is useful for situations where you just want to get into some kind of workable display mode, and can't be bothered with trying multiple different resolutions and doing all the error checking yourself. Note however, that after a successful call to set_gfx_mode with this driver, you cannot make any assumptions about the width, height or color depth of the screen: your code will have to deal with this little detail.

Finally, GFX_TEXT is another magic driver which usually closes any previously opened graphic mode, making you unable to use the global variable screen, and in those environments that have text modes, sets one previously used or the closest match to that (usually 80x25). With this driver the size parameters of set_gfx_mode don't mean anything, so you can leave them all to zero or any other number you prefer.

int set_display_switch_mode(int mode);
Sets how the program should handle being switched into the background, if the user tabs away from it. Not all of the possible modes will be supported by every graphics driver on every platform: you must call this routine after initializing the graphics driver and if you request a mode that isn't currently possible, it will return -1. The available modes are:

  • SWITCH_NONE
    Disables switching. This is the default in single-tasking systems like DOS. It may be supported on other platforms, but you should use it with caution, because your users won't be impressed if they want to tab away from your program, but you don't let them!

  • SWITCH_PAUSE
    Pauses the program whenever it is in the background. Execution will be resumed as soon as the user switches back to it. This is the default in most fullscreen multitasking environments, for example the Linux console, but not under Windows.

  • SWITCH_AMNESIA
    Like SWITCH_PAUSE, but this mode doesn't bother to remember the contents of video memory, so the screen, and any video bitmaps that you have created, will be erased after the user switches away and then back to your program. This is not a terribly useful mode to have, but it is the default for the fullscreen drivers under Windows because DirectDraw is too dumb to implement anything better.

  • SWITCH_BACKGROUND
    The program will carry on running in the background, with the screen bitmap temporarily being pointed at a memory buffer for the fullscreen drivers. You must take special care when using this mode, because bad things will happen if the screen bitmap gets changed around when your program isn't expecting it (see below).

  • SWITCH_BACKAMNESIA
    Like SWITCH_BACKGROUND, but this mode doesn't bother to remember the contents of video memory (see SWITCH_AMNESIA). It is again the only mode supported by the fullscreen drivers under Windows that lets the program keep running in the background.

Note that you should be very careful when you are using graphics routines in the switching context: you must always call acquire_screen() before the start of any drawing code onto the screen and not release it until you are completely finished, because the automatic locking mechanism may not be good enough to work when the program runs in the background or has just been raised in the foreground.

int set_display_switch_callback(int dir, void (*cb)());
Installs a notification callback for the switching mode that was previously selected by calling set_display_switch_mode(). The direction parameter can either be SWITCH_IN or SWITCH_OUT, depending whether you want to be notified about switches away from your program or back to your program. You can sometimes install callbacks for both directions at the same time, but not every platform supports this, so this function may return -1 if your request is impossible. You can install several switch callbacks at the same time.

void remove_display_switch_callback(void (*cb)());
Removes a notification callback that was previously installed by calling set_display_switch_callback(). All the callbacks will automatically be removed when you call set_display_switch_mode().

int get_display_switch_mode();
Returns the current display switching mode, in the same format passed to set_display_switch_mode().

extern int gfx_capabilities;
Bitfield describing the capabilities of the current graphics driver and video hardware. This may contain combination any of the flags:

GFX_CAN_SCROLL:
Indicates that the scroll_screen() function may be used with this driver.

GFX_CAN_TRIPLE_BUFFER:
Indicates that the request_scroll() and poll_scroll() functions may be used with this driver. If this flag is not set, it is possible that the enable_triple_buffer() function may be able to activate it.

GFX_HW_CURSOR:
Indicates that a hardware mouse cursor is in use. When this flag is set, it is safe to draw onto the screen without hiding the mouse pointer first. Note that not every cursor graphic can be implemented in hardware: in particular VBE/AF only supports 2-color images up to 32x32 in size, where the second color is an exact inverse of the first. This means that Allegro may need to switch between hardware and software cursors at any point during the execution of your program, so you should not assume that this flag will remain constant for long periods of time. It only tells you whether a hardware cursor is in use at the current time, and may change whenever you hide/redisplay the pointer.

GFX_HW_HLINE:
Indicates that the normal opaque version of the hline() function is implemented using a hardware accelerator. This will improve the performance not only of hline() itself, but also of many other functions that use it as a workhorse, for example circlefill(), triangle(), and floodfill().

GFX_HW_HLINE_XOR:
Indicates that the XOR version of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator.

GFX_HW_HLINE_SOLID_PATTERN:
Indicates that the solid and masked pattern modes of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator (see note below).

GFX_HW_HLINE_COPY_PATTERN:
Indicates that the copy pattern mode of the hline() function, and any other functions that use it as a workhorse, are implemented using a hardware accelerator (see note below).

GFX_HW_FILL:
Indicates that the opaque version of the rectfill() function, the clear_bitmap() routine, and clear_to_color(), are implemented using a hardware accelerator.

GFX_HW_FILL_XOR:
Indicates that the XOR version of the rectfill() function is implemented using a hardware accelerator.

GFX_HW_FILL_SOLID_PATTERN:
Indicates that the solid and masked pattern modes of the rectfill() function are implemented using a hardware accelerator (see note below).

GFX_HW_FILL_COPY_PATTERN:
Indicates that the copy pattern mode of the rectfill() function is implemented using a hardware accelerator (see note below).

GFX_HW_LINE:
Indicates that the opaque mode line() and vline() functions are implemented using a hardware accelerator.

GFX_HW_LINE_XOR:
Indicates that the XOR version of the line() and vline() functions are implemented using a hardware accelerator.

GFX_HW_TRIANGLE:
Indicates that the opaque mode triangle() function is implemented using a hardware accelerator.

GFX_HW_TRIANGLE_XOR:
Indicates that the XOR version of the triangle() function is implemented using a hardware accelerator.

GFX_HW_GLYPH:
Indicates that monochrome character expansion (for text drawing) is implemented using a hardware accelerator.

GFX_HW_VRAM_BLIT:
Indicates that blitting from one part of the screen to another is implemented using a hardware accelerator. If this flag is set, blitting within the video memory will almost certainly be the fastest possible way to display an image, so it may be worth storing some of your more frequently used graphics in an offscreen portion of the video memory.

GFX_HW_VRAM_BLIT_MASKED:
Indicates that the masked_blit() routine is capable of a hardware accelerated copy from one part of video memory to another, and that draw_sprite() will use a hardware copy when given a sub-bitmap of the screen or a video memory bitmap as the source image. If this flag is set, copying within the video memory will almost certainly be the fastest possible way to display an image, so it may be worth storing some of your more frequently used sprites in an offscreen portion of the video memory.

Warning: if this flag is not set, masked_blit() and draw_sprite() will not work correctly when used with a video memory source image! You must only try to use these functions to copy within the video memory if they are supported in hardware.

GFX_HW_MEM_BLIT:
Indicates that blitting from a memory bitmap onto the screen is being accelerated in hardware.

GFX_HW_MEM_BLIT_MASKED:
Indicates that the masked_blit() and draw_sprite() functions are being accelerated in hardware when the source image is a memory bitmap and the destination is the physical screen.

GFX_HW_SYS_TO_VRAM_BLIT:
Indicates that blitting from a system bitmap onto the screen is being accelerated in hardware. Note that some acceleration may be present even if this flag is not set, because system bitmaps can benefit from normal memory to screen blitting as well. This flag will only be set if system bitmaps have further acceleration above and beyond what is provided by GFX_HW_MEM_BLIT.

GFX_HW_SYS_TO_VRAM_BLIT_MASKED:
Indicates that the masked_blit() and draw_sprite() functions are being accelerated in hardware when the source image is a system bitmap and the destination is the physical screen. Note that some acceleration may be present even if this flag is not set, because system bitmaps can benefit from normal memory to screen blitting as well. This flag will only be set if system bitmaps have further acceleration above and beyond what is provided by GFX_HW_MEM_BLIT_MASKED.

Note: even if the capabilities information says that patterned drawing is supported by the hardware, it will not be possible for every size of pattern. VBE/AF only supports patterns up to 8x8 in size, so Allegro will fall back on the original non-accelerated drawing routines whenever you use a pattern larger than this.

Note2: these hardware acceleration features will only take effect when you are drawing directly onto the screen bitmap, a video memory bitmap, or a sub-bitmap thereof. Accelerated hardware is most useful in a page flipping or triple buffering setup, and is unlikely to make any difference to the classic "draw onto a memory bitmap, then blit to the screen" system.

int enable_triple_buffer();
If the GFX_CAN_TRIPLE_BUFFER bit of the gfx_capabilities field is not set, you can attempt to enable it by calling this function. In particular if you are running in mode-X in a clean DOS environment, this routine will enable the timer retrace simulator, which will activate the triple buffering functions. Returns zero if triple buffering is enabled.

int scroll_screen(int x, int y);
Attempts to scroll the hardware screen to display a different part of the virtual screen (initially it will be positioned at 0, 0, which is the top left corner). Returns zero on success: it may fail if the graphics driver can't handle hardware scrolling or the virtual screen isn't large enough. You can use this to move the screen display around in a large virtual screen space, or to page flip back and forth between two non-overlapping areas of the virtual screen. Note that to draw outside the original position in the screen bitmap you will have to alter the clipping rectangle: see below.

Mode-X scrolling is reliable and will work on any card. Unfortunately most VESA implementations can only handle horizontal scrolling in four pixel increments, so smooth horizontal panning is impossible in SVGA modes. This is a shame, but I can't see any way round it. A significant number of VESA implementations seem to be very buggy when it comes to scrolling in truecolor video modes, so I suggest you don't depend on this routine working correctly in the truecolor resolutions unless you can be sure that SciTech Display Doctor is installed.

Allegro will handle any necessary vertical retrace synchronisation when scrolling the screen, so you don't need to call vsync() before it. This means that scroll_screen() has the same time delay effects as vsync().

int request_scroll(int x, int y);
This function is used for triple buffering. It requests a hardware scroll to the specified position, but returns immediately rather than waiting for a retrace. The scroll will then take place during the next vertical retrace, but you can carry on running other code in the meantime and use the poll_scroll() routine to detect when the flip has actually taken place (see examples/ex3buf.c). Triple buffering is only possible on certain hardware: it will work in any mode-X resolution if the timer retrace simulator is active (but this doesn't work correctly under win95), plus it is supported by the VBE 3.0 and VBE/AF drivers for a limited number of high-end graphics cards. You can look at the GFX_CAN_TRIPLE_BUFFER bit in the gfx_capabilities flag to see if it will work with the current driver. This function returns zero on success.

int poll_scroll();
This function is used for triple buffering. It checks the status of a hardware scroll previously initiated by the request_scroll() routine, returning non-zero if it is still waiting to take place, and zero if it has already happened.

int show_video_bitmap(BITMAP *bitmap);
Attempts to page flip the hardware screen to display the specified video bitmap object, which must be the same size as the physical screen, and should have been obtained by calling the create_video_bitmap() function. Returns zero on success and non-zero on failure.

Allegro will handle any necessary vertical retrace synchronisation when page flipping, so you don't need to call vsync() before it. This means that show_video_bitmap() has the same time delay effects as vsync().

int request_video_bitmap(BITMAP *bitmap);
This function is used for triple buffering. It requests a page flip to display the specified video bitmap object, but returns immediately rather than waiting for a retrace. The flip will then take place during the next vertical retrace, but you can carry on running other code in the meantime and use the poll_scroll() routine to detect when the flip has actually taken place. Triple buffering is only possible on certain hardware: see the comments about request_scroll(). Returns zero on success.


Bitmap objects

  • acquire_bitmap
  • acquire_screen
  • bitmap_color_depth
  • bitmap_mask_color
  • create_bitmap
  • create_bitmap_ex
  • create_sub_bitmap
  • create_system_bitmap
  • create_video_bitmap
  • destroy_bitmap
  • is_linear_bitmap
  • is_memory_bitmap
  • is_planar_bitmap
  • is_same_bitmap
  • is_screen_bitmap
  • is_sub_bitmap
  • is_system_bitmap
  • is_video_bitmap
  • lock_bitmap
  • release_bitmap
  • release_screen
  • screen
  • set_clip

Once you have selected a graphics mode, you can draw things onto the display via the 'screen' bitmap. All the Allegro graphics routines draw onto BITMAP structures, which are areas of memory containing rectangular images, stored as packed byte arrays (in 8 bit modes one byte per pixel, in 15 and 16 bit modes sizeof(short) bytes per pixel, in 24 bit modes 3 bytes per pixel and in 32 bit modes sizeof(long) bytes per pixel). You can create and manipulate bitmaps in system RAM, or you can write to the special 'screen' bitmap which represents the video memory in your graphics card.

For example, to draw a pixel onto the screen you would write:

   putpixel(screen, x, y, color);
Or to implement a double-buffered system:

   BITMAP *bmp = create_bitmap(320, 200);    // make a bitmap in system RAM
   clear_bitmap(bmp);                        // zero the memory bitmap
   putpixel(bmp, x, y, color);               // draw onto the memory bitmap
   blit(bmp, screen, 0, 0, 0, 0, 320, 200);  // copy it to the screen
See below for information on how to get direct access to the image memory in a bitmap.

Allegro supports several different types of bitmaps:

- The screen bitmap, which represents the hardware video memory. Ultimately you have to draw onto this in order for your image to be visible. It is destroyed by any subsequent calls to set_gfx_mode().

- Memory bitmaps, which are located in system RAM and can be used to store graphics or as temporary drawing spaces for double buffered systems. These can be obtained by calling create_bitmap(), load_pcx(), or by loading a grabber datafile.

- Sub-bitmaps. These share image memory with a parent bitmap (which can be the screen, a memory bitmap, or another sub-bitmap), so drawing onto them will also change their parent. They can be of any size and located anywhere within the parent bitmap, and can have their own clipping rectangles, so they are a useful way of dividing a bitmap into several smaller units, eg. splitting a large virtual screen into multiple sections (see examples/exscroll.c).

- Video memory bitmaps. These are created by the create_video_bitmap() function, and are usually implemented as sub-bitmaps of the screen object. They must be destroyed by destroy_bitmap() before any subsequent calls to set_gfx_mode().

- System bitmaps. These are created by the create_system_bitmap() function, and are a sort of halfway house between memory and video bitmaps. They live in system memory, so you aren't limited by the amount of video ram in your card, but they are stored in a platform-specific format that may enable better hardware acceleration than is possible with a normal memory bitmap (see the GFX_HW_SYS_TO_VRAM_BLIT and GFX_HW_SYS_TO_VRAM_BLIT_MASKED flags in gfx_capabilities). System bitmaps must be accessed in the same way as video bitmaps, using the bank switch functions and bmp_write*() macros. Not every platform implements this type of bitmap: if they aren't available, create_system_bitmap() will function identically to create_bitmap(). They must be destroyed by destroy_bitmap() before any subsequent calls to set_gfx_mode().

extern BITMAP *screen;
Global pointer to a bitmap, sized VIRTUAL_W x VIRTUAL_H. This is created by set_gfx_mode(), and represents the hardware video memory. Only a part of this bitmap will actually be visible, sized SCREEN_W x SCREEN_H. Normally this is the top left corner of the larger virtual screen, so you can ignore the extra invisible virtual size of the bitmap if you aren't interested in hardware scrolling or page flipping. To move the visible window to other parts of the screen bitmap, call scroll_screen(). Initially the clipping rectangle will be limited to the physical screen size, so if you want to draw onto a larger virtual screen space outside this rectangle, you will need to adjust the clipping.

BITMAP *create_bitmap(int width, int height);
Creates a memory bitmap sized width by height, and returns a pointer to it. The bitmap will have clipping turned on, and the clipping rectangle set to the full size of the bitmap. The image memory will not be cleared, so it will probably contain garbage: you should clear the bitmap before using it. This routine always uses the global pixel format, as specified by calling set_color_depth().

BITMAP *create_bitmap_ex(int color_depth, int width, int height);
Creates a bitmap in a specific color depth (8, 15, 16, 24 or 32 bits per pixel).

BITMAP *create_sub_bitmap(BITMAP *parent, int x, y, width, height);
Creates a sub-bitmap, ie. a bitmap sharing drawing memory with a pre-existing bitmap, but possibly with a different size and clipping settings. When creating a sub-bitmap of the mode-X screen, the x position must be a multiple of four. The sub-bitmap width and height can extend beyond the right and bottom edges of the parent (they will be clipped), but the origin point must lie within the parent region.

BITMAP *create_video_bitmap(int width, int height);
Allocates a video memory bitmap of the specified size, returning a pointer to it on success or NULL on failure (ie. if you have run out of vram). This can be used to allocate offscreen video memory for storing source graphics ready for a hardware accelerated blitting operation, or to create multiple video memory pages which can then be displayed by calling show_video_bitmap(). Video memory bitmaps are usually allocated from the same space as the screen bitmap, so they may overlap with it: it is not therefore a good idea to use the global screen at the same time as any surfaces returned by this function.

BITMAP *create_system_bitmap(int width, int height);
Allocates a system memory bitmap of the specified size, returning a pointer to it on success or NULL on failure.

void destroy_bitmap(BITMAP *bitmap);
Destroys a memory bitmap, sub-bitmap, video memory bitmap, or system bitmap when you are finished with it.

void lock_bitmap(BITMAP *bitmap);
Under DOS, locks all the memory used by a bitmap. You don't normally need to call this function unless you are doing very weird things in your program.

int bitmap_color_depth(BITMAP *bmp);
Returns the color depth of the specified bitmap (8, 15, 16, 24, or 32). Note that calling it on the 'screen' bitmap will return the pixel format currently in use, as specified by the latest call to set_color_depth(), once a graphics mode has been set.

int bitmap_mask_color(BITMAP *bmp);
Returns the mask color for the specified bitmap (the value which is skipped when drawing sprites). For 256 color bitmaps this is zero, and for truecolor bitmaps it is bright pink (maximum red and blue, zero green).

int is_same_bitmap(BITMAP *bmp1, BITMAP *bmp2);
Returns TRUE if the two bitmaps describe the same drawing surface, ie. the pointers are equal, one is a sub-bitmap of the other, or they are both sub-bitmaps of a common parent.

int is_linear_bitmap(BITMAP *bmp);
Returns TRUE if bmp is a linear bitmap, ie. a memory bitmap, mode 13h screen, or SVGA screen. Linear bitmaps can be used with the _putpixel(), _getpixel(), bmp_write_line(), and bmp_read_line() functions.

int is_planar_bitmap(BITMAP *bmp);
Returns TRUE if bmp is a planar (mode-X or Xtended mode) screen bitmap.

int is_memory_bitmap(BITMAP *bmp);
Returns TRUE if bmp is a memory bitmap, ie. it was created by calling create_bitmap() or loaded from a grabber datafile or image file. Memory bitmaps can be accessed directly via the line pointers in the bitmap structure, eg. bmp->line[y][x] = color.

int is_screen_bitmap(BITMAP *bmp);
Returns TRUE if bmp is the screen bitmap, or a sub-bitmap of the screen.

int is_video_bitmap(BITMAP *bmp);
Returns TRUE if bmp is the screen bitmap, a video memory bitmap, or a sub-bitmap of either.

int is_system_bitmap(BITMAP *bmp);
Returns TRUE if bmp is a system bitmap object, or a sub-bitmap of one.

int is_sub_bitmap(BITMAP *bmp);
Returns TRUE if bmp is a sub-bitmap.

void acquire_bitmap(BITMAP *bmp);
Locks the specified video memory bitmap prior to drawing onto it. This does not apply to memory bitmaps, and only affects some platforms (Windows needs it, DOS does not). These calls are not strictly required, because the drawing routines will automatically acquire the bitmap before accessing it, but locking a DirectDraw surface is very slow, so you will get much better performance if you acquire the screen just once at the start of your main redraw function, and only release it when the drawing is completely finished. Multiple acquire calls may be nested, and the bitmap will only be truly released when the lock count returns to zero. Be warned that DirectX programs activate a mutex lock whenever a surface is locked, which prevents them from getting any input messages, so you must be sure to release all your bitmaps before using any timer, keyboard, or other non-graphics routines!

void release_bitmap(BITMAP *bmp);
Releases a bitmap that was previously locked by calling acquire_bitmap(). If the bitmap was locked multiple times, you must release it the same number of times before it will truly be unlocked.

void acquire_screen();
Shortcut version of acquire_bitmap(screen);

void release_screen();
Shortcut version of release_bitmap(screen);

void set_clip(BITMAP *bitmap, int x1, int y1, int x2, int y2);
Each bitmap has an associated clipping rectangle, which is the area of the image that it is ok to draw on. Nothing will be drawn to positions outside this space. Pass the two opposite corners of the clipping rectangle: these are inclusive, eg. set_clip(bitmap, 16, 16, 32, 32) will allow drawing to (16, 16) and (32, 32), but not to (15, 15) and (33, 33). If x1, y1, x2, and y2 are all zero, clipping will be turned off, which may slightly speed up some drawing operations (usually a negligible difference, although every little helps) but will result in your program dying a horrible death if you try to draw beyond the edges of the bitmap.


Loading image files

  • load_bitmap
  • load_bmp
  • load_lbm
  • load_pcx
  • load_tga
  • register_bitmap_file_type
  • save_bitmap
  • save_bmp
  • save_pcx
  • save_tga
  • set_color_conversion

Warning: when using truecolor images, you should always set the graphics mode before loading any bitmap data! Otherwise the pixel format (RGB or BGR) will not be known, so the file may be converted wrongly.

BITMAP *load_bitmap(const char *filename, RGB *pal);
Loads a bitmap from a file, returning a pointer to a bitmap and storing the palette data in the specified location, which should be an array of 256 RGB structures. You are responsible for destroying the bitmap when you are finished with it. Returns NULL on error. At present this function supports BMP, LBM, PCX, and TGA files, determining the type from the file extension.

If the file contains a truecolor image, you must set the video mode or call set_color_conversion() before loading it. In this case, if the destination color depth is 8-bit, the palette will be generated by calling generate_optimized_palette() on the bitmap; otherwise, the returned palette will be generated by calling generate_332_palette().

The pal argument may be NULL. In this case, the palette data are simply not returned. Additionally, if the file is a truecolor image and the destination color depth is 8-bit, the color conversion process will use the current palette instead of generating an optimized one.

BITMAP *load_bmp(const char *filename, RGB *pal);
Loads a 256 color or 24 bit truecolor Windows or OS/2 BMP file.

BITMAP *load_lbm(const char *filename, RGB *pal);
Loads a 256 color IFF ILBM/PBM file.

BITMAP *load_pcx(const char *filename, RGB *pal);
Loads a 256 color or 24 bit truecolor PCX file.

BITMAP *load_tga(const char *filename, RGB *pal);
Loads a 256 color, 15 bit hicolor, 24 bit truecolor, or 32 bit truecolor+alpha TGA file.

int save_bitmap(const char *filename, BITMAP *bmp, const RGB *pal);
Writes a bitmap into a file, using the specified palette, which should be an array of 256 RGB structures. Returns non-zero on error. The output format is determined from the filename extension: at present this function supports BMP, PCX and TGA formats.

Two things to watch out for: on some video cards it may be faster to copy the screen to a memory bitmap and save the latter, and if you use this to dump the screen into a file you may end up with an image much larger than you were expecting, because Allegro often creates virtual screens larger than the visible screen. You can get around this by using a sub-bitmap to specify which part of the screen to save, eg:

      BITMAP *bmp;
      PALETTE pal;

      get_palette(pal);
      bmp = create_sub_bitmap(screen, 0, 0, SCREEN_W, SCREEN_H);
      save_bitmap("dump.pcx", bmp, pal);
      destroy_bitmap(bmp);
int save_bmp(const char *filename, BITMAP *bmp, const RGB *pal);
Writes a bitmap into a 256 color or 24 bit truecolor BMP file.

int save_pcx(const char *filename, BITMAP *bmp, const RGB *pal);
Writes a bitmap into a 256 color or 24 bit truecolor PCX file.

int save_tga (const char *filename, BITMAP *bmp, const RGB *pal);
Writes a bitmap into a 256 color, 15 bit hicolor, 24 bit truecolor, or 32 bit truecolor+alpha TGA file.

void register_bitmap_file_type(const char *ext, BITMAP *(*load)(const char *filename, RGB *pal), int (*save)(const char *filename, BITMAP *bmp, const RGB *pal));
Informs the load_bitmap() and save_bitmap() functions of a new file type, providing routines to read and write images in this format (either function may be NULL).

void set_color_conversion(int mode);
Specifies how to convert images between the various color depths when reading graphics from external bitmap files or datafiles. The mode is a bitmask specifying which types of conversion are allowed. If the appropriate bit is set, data will be converted into the current pixel format (selected by calling the set_color_depth() function), otherwise it will be left in the same format as the disk file, leaving you to convert it manually before the graphic can be displayed. The default mode is total conversion, so that all images will be loaded in the appropriate format for the current video mode. Valid bit flags are:

      COLORCONV_NONE                // disable all format
                                    // conversions
      COLORCONV_8_TO_15             // expand 8 bits to 15 bits
      COLORCONV_8_TO_16             // expand 8 bits to 16 bits
      COLORCONV_8_TO_24             // expand 8 bits to 24 bits
      COLORCONV_8_TO_32             // expand 8 bits to 32 bits
      COLORCONV_15_TO_8             // reduce 15 bits to 8 bits
      COLORCONV_15_TO_16            // expand 15 bits to 16 bits
      COLORCONV_15_TO_24            // expand 15 bits to 24 bits
      COLORCONV_15_TO_32            // expand 15 bits to 32 bits
      COLORCONV_16_TO_8             // reduce 16 bits to 8 bits
      COLORCONV_16_TO_15            // reduce 16 bits to 15 bits
      COLORCONV_16_TO_24            // expand 16 bits to 24 bits
      COLORCONV_16_TO_32            // expand 16 bits to 32 bits
      COLORCONV_24_TO_8             // reduce 24 bits to 8 bits
      COLORCONV_24_TO_15            // reduce 24 bits to 15 bits
      COLORCONV_24_TO_16            // reduce 24 bits to 16 bits
      COLORCONV_24_TO_32            // expand 24 bits to 32 bits
      COLORCONV_32_TO_8             // reduce 32 bit RGB to 8 bits
      COLORCONV_32_TO_15            // reduce 32 bit RGB to 15 bits
      COLORCONV_32_TO_16            // reduce 32 bit RGB to 16 bits
      COLORCONV_32_TO_24            // reduce 32 bit RGB to 24 bits
      COLORCONV_32A_TO_8            // reduce 32 bit RGBA to 8 bits
      COLORCONV_32A_TO_15           // reduce 32 bit RGBA to 15 bits
      COLORCONV_32A_TO_16           // reduce 32 bit RGBA to 16 bits
      COLORCONV_32A_TO_24           // reduce 32 bit RGBA to 24 bits
      COLORCONV_DITHER_PAL          // dither when reducing to 8 bit
      COLORCONV_DITHER_HI           // dither when reducing to
                                    // hicolor
      COLORCONV_KEEP_TRANS          // keep original transparency
For convenience, the following macros can be used to select common combinations of these flags:

      COLORCONV_EXPAND_256          // expand 256 colors to
                                    // hi/truecolor
      COLORCONV_REDUCE_TO_256       // reduce hi/truecolor to 256
                                    // colors
      COLORCONV_EXPAND_15_TO_16     // expand 15 bit hicolor to
                                    // 16 bits
      COLORCONV_REDUCE_16_TO_15     // reduce 16 bit hicolor to
                                    // 15 bits
      COLORCONV_EXPAND_HI_TO_TRUE   // expand 15/16 bits to
                                    // 24/32 bits
      COLORCONV_REDUCE_TRUE_TO_HI   // reduce 24/32 bits to
                                    // 15/16 bits
      COLORCONV_24_EQUALS_32        // convert between 24 and
                                    // 32 bits
      COLORCONV_TOTAL               // everything to current format
      COLORCONV_PARTIAL             // convert 15 <-> 16 and
                                    // 24 <-> 32
      COLORCONV_MOST                // all but hi/truecolor <-> 256
      COLORCONV_DITHER              // dither during all color
                                    // reductions
If you enable the COLORCONV_DITHER flag, dithering will be performed whenever truecolor graphics are converted into a hicolor or paletted format, including by the blit() function, and any automatic conversions that take place while reading graphics from disk. This can produce much better looking results, but is obviously slower than a direct conversion.

If you intend using converted bitmaps with functions like masked_blit() or draw_sprite(), you should specify the COLORCONV_KEEP_TRANS flag. It will ensure that the masked areas in the bitmap before and after the conversion stay exactly the same, by mapping transparent colors to each other and adjusting colors which would be converted to the transparent color otherwise. It affects every blit() operation between distinct pixel formats and every automatic conversion.


Palette routines

  • _set_color
  • black_palette
  • default_palette
  • desktop_palette
  • fade_from
  • fade_from_range
  • fade_in
  • fade_in_range
  • fade_interpolate
  • fade_out
  • fade_out_range
  • generate_332_palette
  • generate_optimized_palette
  • get_color
  • get_palette
  • get_palette_range
  • select_palette
  • set_color
  • set_palette
  • set_palette_range
  • unselect_palette
  • vsync

All the Allegro drawing functions use integer parameters to represent colors. In truecolor resolutions these numbers encode the color directly as a collection of red, green, and blue bits, but in a regular 256 color mode the values are treated as indexes into the current palette, which is a table listing the red, green and blue intensities for each of the 256 possible colors.

Palette entries are stored in an RGB structure, which contains red, green and blue intensities in the VGA hardware format, ranging from 0-63, and is defined as:

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

   RGB black = { 0,  0,  0  };
   RGB white = { 63, 63, 63 };
   RGB green = { 0,  63, 0  };
   RGB grey  = { 32, 32, 32 };
The type PALETTE is defined to be an array of 256 RGB structures.

You may notice that a lot of the code in Allegro spells 'palette' as 'pallete'. This is because the headers from my old Mark Williams compiler on the Atari spelt it with two l's, so that is what I'm used to. Allegro will happily accept either spelling, due to some #defines in allegro/alcompat.h.

void vsync();
Waits for a vertical retrace to begin. The retrace happens when the electron beam in your monitor has reached the bottom of the screen and is moving back to the top ready for another scan. During this short period the graphics card isn't sending any data to the monitor, so you can do things to it that aren't possible at other times, such as altering the palette without causing flickering (snow). Allegro will automatically wait for a retrace before altering the palette or doing any hardware scrolling, though, so you don't normally need to bother with this function.

void set_color(int index, const RGB *p);
Sets the specified palette entry to the specified RGB triplet. Unlike the other palette functions this doesn't do any retrace synchronisation, so you should call vsync() before it to prevent snow problems.

void _set_color(int index, const RGB *p);
This is an inline version of set_color(), intended for use in the vertical retrace simulator callback function. It should only be used in VGA mode 13h and mode-X, because some of the more recent SVGA chipsets aren't VGA compatible (set_color() and set_palette() will use VESA calls on these cards, but _set_color() doesn't know about that).

void set_palette(const PALETTE p);
Sets the entire palette of 256 colors. You should provide an array of 256 RGB structures. Unlike set_color(), there is no need to call vsync() before this function.

void set_palette_range(const PALETTE p, int from, int to, int vsync);
Sets the palette entries between from and to (inclusive: pass 0 and 255 to set the entire palette). If vsync is set it waits for the vertical retrace, otherwise it sets the colors immediately.

void get_color(int index, RGB *p);
Retrieves the specified palette entry.

void get_palette(PALETTE p);
Retrieves the entire palette of 256 colors. You should provide an array of 256 RGB structures to store it in.

void get_palette_range(PALETTE p, int from, int to);
Retrieves the palette entries between from and to (inclusive: pass 0 and 255 to get the entire palette).

void fade_interpolate(const PALETTE source, const PALETTE dest, PALETTE output, int pos, int from, to);
Calculates a temporary palette part way between source and dest, returning it in the output parameter. The position between the two extremes is specified by the pos value: 0 returns an exact copy of source, 64 returns dest, 32 returns a palette half way between the two, etc. This routine only affects colors between from and to (inclusive: pass 0 and 255 to interpolate the entire palette).

void fade_from_range(const PALETTE source, const PALETTE dest, int speed, int from, to);
Gradually fades a part of the palette from the source palette to the dest palette. The speed is from 1 (the slowest) up to 64 (instantaneous). This routine only affects colors between from and to (inclusive: pass 0 and 255 to fade the entire palette).

void fade_in_range(const PALETTE p, int speed, int from, to);
Gradually fades a part of the palette from a black screen to the specified palette. The speed is from 1 (the slowest) up to 64 (instantaneous). This routine only affects colors between from and to (inclusive: pass 0 and 255 to fade the entire palette).

void fade_out_range(int speed, int from, to);
Gradually fades a part of the palette from the current palette to a black screen. The speed is from 1 (the slowest) up to 64 (instantaneous). This routine only affects colors between from and to (inclusive: pass 0 and 255 to fade the entire palette).

void fade_from(const PALETTE source, const PALETTE dest, int speed);
Fades gradually from the source palette to the dest palette. The speed is from 1 (the slowest) up to 64 (instantaneous).

void fade_in(const PALETTE p, int speed);
Fades gradually from a black screen to the specified palette. The speed is from 1 (the slowest) up to 64 (instantaneous).

void fade_out(int speed);
Fades gradually from the current palette to a black screen. The speed is from 1 (the slowest) up to 64 (instantaneous).

void select_palette(const PALETTE p);
Ugly hack for use in various dodgy situations where you need to convert between paletted and truecolor image formats. Sets the internal palette table in the same way as the set_palette() function, so the conversion will use the specified palette, but without affecting the display hardware in any way. The previous palette settings are stored in an internal buffer, and can be restored by calling unselect_palette().

void unselect_palette();
Restores the palette tables that were in use before the last call to select_palette().

void generate_332_palette(PALETTE pal);
Constructs a fake truecolor palette, using three bits for red and green and two for the blue. The load_bitmap() function returns this if the file does not contain a palette itself (ie. you are reading a truecolor bitmap).

int generate_optimized_palette(BITMAP *bmp, PALETTE pal, const char rsvd[256]);
Generates a 256 color palette suitable for making a reduced color version of the specified truecolor image. The rsvd parameter points to a table indicating which colors it is allowed to modify: zero for free colors which may be set to whatever the optimiser likes, negative values for reserved colors which cannot be used, and positive values for fixed palette entries that must not be changed, but can be used in the optimisation.

extern PALETTE default_palette;
The default IBM BIOS palette. This will be automatically selected whenever you set a new graphics mode.

extern PALETTE black_palette;
A palette containing solid black colors, used by the fade routines.

extern PALETTE desktop_palette;
The palette used by the Atari ST low resolution desktop. I'm not quite sure why this is still here, except that the grabber and test programs use it. It is probably the only Atari legacy code left in Allegro, and it would be a shame to remove it :-)


Truecolor pixel formats

  • geta
  • geta32
  • geta_depth
  • getb
  • getb15
  • getb16
  • getb24
  • getb32
  • getb8
  • getb_depth
  • getg
  • getg15
  • getg16
  • getg24
  • getg32
  • getg8
  • getg_depth
  • getr
  • getr15
  • getr16
  • getr24
  • getr32
  • getr8
  • getr_depth
  • makeacol
  • makeacol32
  • makeacol_depth
  • makecol
  • makecol15
  • makecol15_dither
  • makecol16
  • makecol16_dither
  • makecol24
  • makecol32
  • makecol8
  • makecol_depth
  • MASK_COLOR_15
  • MASK_COLOR_16
  • MASK_COLOR_24
  • MASK_COLOR_32
  • MASK_COLOR_8
  • palette_color

In a truecolor video mode the red, green, and blue components for each pixel are packed directly into the color value, rather than using a palette lookup table. In a 15 bit mode there are 5 bits for each color, in 16 bit modes there are 5 bits each of red and blue and six bits of green, and both 24 and 32 bit modes use 8 bits for each color (the 32 bit pixels simply have an extra padding byte to align the data nicely). The layout of these components can vary depending on your hardware, but will generally either be RGB or BGR. Since the layout is not known until you select the video mode you will be using, you must call set_gfx_mode() before using any of the following routines!

int makecol8(int r, int g, int b);
int makecol15(int r, int g, int b);
int makecol16(int r, int g, int b);
int makecol24(int r, int g, int b);
int makecol32(int r, int g, int b);
These functions convert colors from a hardware independent form (red, green, and blue values ranging 0-255) into various display dependent pixel formats. Converting to 15, 16, 24, or 32 bit formats only takes a few shifts, so it is fairly efficient. Converting to an 8 bit color involves searching the palette to find the closest match, which is quite slow unless you have set up an RGB mapping table (see below).

int makeacol32(int r, int g, int b, int a);
Converts an RGBA color into a 32 bit display pixel format, which includes an alpha (transparency) value. There are no versions of this routine for other color depths, because only the 32 bit format has enough room to store a proper alpha channel. You should only use RGBA format colors as the input to draw_trans_sprite() or draw_trans_rle_sprite() after calling set_alpha_blender(), rather than drawing them directly to the screen.

int makecol(int r, int g, int b);
Converts colors from a hardware independent format (red, green, and blue values ranging 0-255) to the pixel format required by the current video mode, calling the preceding 8, 15, 16, 24, or 32 bit makecol functions as appropriate.

int makecol_depth(int color_depth, int r, int g, int b);
Converts colors from a hardware independent format (red, green, and blue values ranging 0-255) to the pixel format required by the specified color depth.

int makeacol(int r, int g, int b, int a);
int makeacol_depth(int color_depth, int r, int g, int b, int a);
Convert RGBA colors into display dependent pixel formats. In anything less than a 32 bit mode, these are the same as calling makecol() or makecol_depth(), but by using these routines it is possible to create 32 bit color values that contain a true 8 bit alpha channel along with the red, green, and blue components. You should only use RGBA format colors as the input to draw_trans_sprite() or draw_trans_rle_sprite() after calling set_alpha_blender(), rather than drawing them directly to the screen.

int makecol15_dither(int r, int g, int b, int x, int y);
int makecol16_dither(int r, int g, int b, int x, int y);
Given both a color value and a pixel coordinate, calculate a dithered 15 or 16 bit RGB value. This can produce better results when reducing images from truecolor to hicolor. In addition to calling these functions directly, hicolor dithering can be automatically enabled when loading graphics by calling the set_color_conversion() function, for example set_color_conversion (COLORCONV_REDUCE_TRUE_TO_HI | COLORCONV_DITHER).

int getr8(int c);
int getg8(int c);
int getb8(int c);
int getr15(int c);
int getg15(int c);
int getb15(int c);
int getr16(int c);
int getg16(int c);
int getb16(int c);
int getr24(int c);
int getg24(int c);
int getb24(int c);
int getr32(int c);
int getg32(int c);
int getb32(int c);
Given a color in a display dependent format, these functions extract one
   of the red, green, or blue components (ranging 0-255).

int geta32(int c);
Given a color in a 32 bit pixel format, this function extracts the alpha component (ranging 0-255).

int getr(int c);
int getg(int c);
int getb(int c);
int geta(int c);
Given a color in the format being used by the current video mode, these functions extract one of the red, green, blue, or alpha components (ranging 0-255), calling the preceding 8, 15, 16, 24, or 32 bit get functions as appropriate. The alpha part is only meaningful for 32 bit pixels.

int getr_depth(int color_depth, int c);
int getg_depth(int color_depth, int c);
int getb_depth(int color_depth, int c);
int geta_depth(int color_depth, int c);
Given a color in the format being used by the specified color depth, these functions extract one of the red, green, blue, or alpha components (ranging 0-255). The alpha part is only meaningful for 32 bit pixels.

extern int palette_color[256];
Table mapping palette index colors (0-255) into whatever pixel format is being used by the current display mode. In a 256 color mode this just maps onto the array index. In truecolor modes it looks up the specified entry in the current palette, and converts that RGB value into the appropriate packed pixel format.

#define MASK_COLOR_8 0
#define MASK_COLOR_15 (5.5.5 pink)
#define MASK_COLOR_16 (5.6.5 pink)
#define MASK_COLOR_24 (8.8.8 pink)
#define MASK_COLOR_32 (8.8.8 pink)
Constants representing the colors used to mask transparent sprite pixels
   for each color depth. In 256 color resolutions this is zero, and in
   truecolor modes it is bright pink (maximum red and blue, zero green).


Drawing primitives

  • _getpixel
  • _getpixel15
  • _getpixel16
  • _getpixel24
  • _getpixel32
  • _putpixel
  • _putpixel15
  • _putpixel16
  • _putpixel24
  • _putpixel32
  • arc
  • calc_spline
  • circle
  • circlefill
  • do_arc
  • do_circle
  • do_ellipse
  • do_line
  • ellipse
  • ellipsefill
  • floodfill
  • getpixel
  • hline
  • line
  • polygon
  • putpixel
  • rect
  • rectfill
  • spline
  • triangle
  • vline

Except for _putpixel(), all these routines are affected by the current drawing mode and the clipping rectangle of the destination bitmap.

void putpixel(BITMAP *bmp, int x, int y, int color);
Writes a pixel to the specified position in the bitmap, using the current drawing mode and the bitmap's clipping rectangle.

void _putpixel(BITMAP *bmp, int x, int y, int color);
void _putpixel15(BITMAP *bmp, int x, int y, int color);
void _putpixel16(BITMAP *bmp, int x, int y, int color);
void _putpixel24(BITMAP *bmp, int x, int y, int color);
void _putpixel32(BITMAP *bmp, int x, int y, int color);
Like the regular putpixel(), but much faster because they are implemented as an inline assembler functions for specific color depths. These won't work in mode-X graphics modes, don't perform any clipping (they will crash if you try to draw outside the bitmap!), and ignore the drawing mode.

int getpixel(BITMAP *bmp, int x, int y);
Reads a pixel from point x, y in the bitmap. Returns -1 if the point lies outside the bitmap.

int _getpixel(BITMAP *bmp, int x, int y);
int _getpixel15(BITMAP *bmp, int x, int y);
int _getpixel16(BITMAP *bmp, int x, int y);
int _getpixel24(BITMAP *bmp, int x, int y);
int _getpixel32(BITMAP *bmp, int x, int y);
Faster inline versions of getpixel() for specific color depths. These
   won't work in mode-X, and don't do any clipping, so you must make sure
   the point lies inside the bitmap.

void vline(BITMAP *bmp, int x, int y1, int y2, int color);
Draws a vertical line onto the bitmap, from point (x, y1) to (x, y2).

void hline(BITMAP *bmp, int x1, int y, int x2, int color);
Draws a horizontal line onto the bitmap, from point (x1, y) to (x2, y).

void do_line(BITMAP *bmp, int x1, y1, x2, y2, int d, void (*proc)(BITMAP *bmp, int x, int y, int d));
Calculates all the points along a line from point (x1, y1) to (x2, y2), calling the supplied function for each one. This will be passed a copy of the bmp parameter, the x and y position, and a copy of the d parameter, so it is suitable for use with putpixel().

void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
Draws a line onto the bitmap, from point (x1, y1) to (x2, y2).

void triangle(BITMAP *bmp, int x1, y1, x2, y2, x3, y3, int color);
Draws a filled triangle between the three points.

void polygon(BITMAP *bmp, int vertices, const int *points, int color);
Draws a filled polygon with an arbitrary number of corners. Pass the number of vertices and an array containing a series of x, y points (a total of vertices*2 values).

void rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
Draws an outline rectangle with the two points as its opposite corners.

void rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
Draws a solid, filled rectangle with the two points as its opposite corners.

void do_circle(BITMAP *bmp, int x, int y, int radius, int d, void (*proc)(BITMAP *bmp, int x, int y, int d));
Calculates all the points in a circle around point (x, y) with radius r, calling the supplied function for each one. This will be passed a copy of the bmp parameter, the x and y position, and a copy of the d parameter, so it is suitable for use with putpixel().

void circle(BITMAP *bmp, int x, int y, int radius, int color);
Draws a circle with the specified centre and radius.

void circlefill(BITMAP *bmp, int x, int y, int radius, int color);
Draws a filled circle with the specified centre and radius.

void do_ellipse(BITMAP *bmp, int x, int y, int rx, ry, int d, void (*proc)(BITMAP *bmp, int x, int y, int d));
Calculates all the points in an ellipse around point (x, y) with radius rx and ry, calling the supplied function for each one. This will be passed a copy of the bmp parameter, the x and y position, and a copy of the d parameter, so it is suitable for use with putpixel().

void ellipse(BITMAP *bmp, int x, int y, int rx, int ry, int color);
Draws an ellipse with the specified centre and radius.

void ellipsefill(BITMAP *bmp, int x, int y, int rx, int ry, int color);
Draws a filled ellipse with the specified centre and radius.

void do_arc(BITMAP *bmp, int x, int y, fixed a1, fixed a2, int r, int d, void (*proc)(BITMAP *bmp, int x, int y, int d));
Calculates all the points in a circular arc around point (x, y) with radius r, calling the supplied function for each one. This will be passed a copy of the bmp parameter, the x and y position, and a copy of the d parameter, so it is suitable for use with putpixel(). The arc will be plotted in an anticlockwise direction starting from the angle a1 and ending when it reaches a2. These values are specified in 16.16 fixed point format, with 256 equal to a full circle, 64 a right angle, etc. Zero is to the right of the centre point, and larger values rotate anticlockwise from there.

void arc(BITMAP *bmp, int x, y, fixed ang1, ang2, int r, int color);
Draws a circular arc with centre x, y and radius r, in an anticlockwise direction starting from the angle a1 and ending when it reaches a2. These values are specified in 16.16 fixed point format, with 256 equal to a full circle, 64 a right angle, etc. Zero is to the right of the centre point, and larger values rotate anticlockwise from there.

void calc_spline(const int points[8], int npts, int *x, int *y);
Calculates a series of npts values along a bezier spline, storing them in the output x and y arrays. The bezier curve is specified by the four x/y control points in the points array: points[0] and points[1] contain the coordinates of the first control point, points[2] and points[3] are the second point, etc. Control points 0 and 3 are the ends of the spline, and points 1 and 2 are guides. The curve probably won't pass through points 1 and 2, but they affect the shape of the curve between points 0 and 3 (the lines p0-p1 and p2-p3 are tangents to the spline). The easiest way to think of it is that the curve starts at p0, heading in the direction of p1, but curves round so that it arrives at p3 from the direction of p2. In addition to their role as graphics primitives, spline curves can be useful for constructing smooth paths around a series of control points, as in exspline.c.

void spline(BITMAP *bmp, const int points[8], int color);
Draws a bezier spline using the four control points specified in the points array.

void floodfill(BITMAP *bmp, int x, int y, int color);
Floodfills an enclosed area, starting at point (x, y), with the specified color.


Blitting and sprites

  • blit
  • clear
  • clear_bitmap
  • clear_to_color
  • draw_character
  • draw_gouraud_sprite
  • draw_lit_sprite
  • draw_sprite
  • draw_sprite_h_flip
  • draw_sprite_v_flip
  • draw_sprite_vh_flip
  • draw_trans_sprite
  • masked_blit
  • masked_stretch_blit
  • pivot_scaled_sprite
  • pivot_scaled_sprite_v_flip
  • pivot_sprite
  • pivot_sprite_v_flip
  • rotate_scaled_sprite
  • rotate_scaled_sprite_v_flip
  • rotate_sprite
  • rotate_sprite_v_flip
  • stretch_blit
  • stretch_sprite

All these routines are affected by the clipping rectangle of the destination bitmap.

void clear_bitmap(BITMAP *bitmap);
Clears the bitmap to color 0.

void clear(BITMAP *bitmap);
An alias for clear_bitmap(), provided for backwards compatibility. It is implemented as a static inline function. The aliasing may be switched off by defining the preprocessor symbol ALLEGRO_NO_CLEAR_BITMAP_ALIAS before including Allegro headers, eg:

      #define ALLEGRO_NO_CLEAR_BITMAP_ALIAS
      #include <allegro.h>
void clear_to_color(BITMAP *bitmap, int color);
Clears the bitmap to the specified color.

void blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
Copies a rectangular area of the source bitmap to the destination bitmap. The source_x and source_y parameters are the top left corner of the area to copy from the source bitmap, and dest_x and dest_y are the corresponding position in the destination bitmap. This routine respects the destination clipping rectangle, and it will also clip if you try to blit from areas outside the source bitmap.

You can blit between any parts of any two bitmaps, even if the two memory areas overlap (ie. source and dest are the same, or one is sub-bitmap of the other). You should be aware, however, that a lot of SVGA cards don't provide separate read and write banks, which means that blitting from one part of the screen to another requires the use of a temporary bitmap in memory, and is therefore extremely slow. As a general rule you should avoid blitting from the screen onto itself in SVGA modes.

In mode-X, on the other hand, blitting from one part of the screen to another can be significantly faster than blitting from memory onto the screen, as long as the source and destination are correctly aligned with each other. Copying between overlapping screen rectangles is slow, but if the areas don't overlap, and if they have the same plane alignment (ie. (source_x%4) == (dest_x%4)), the VGA latch registers can be used for a very fast data transfer. To take advantage of this, in mode-X it is often worth storing tile graphics in a hidden area of video memory (using a large virtual screen), and blitting them from there onto the visible part of the screen.

If the GFX_HW_VRAM_BLIT bit in the gfx_capabilities flag is set, the current driver supports hardware accelerated blits from one part of the screen onto another. This is extremely fast, so when this flag is set it may be worth storing some of your more frequently used graphics in an offscreen portion of the video memory.

Unlike most of the graphics routines, blit() allows the source and destination bitmaps to be of different color depths, so it can be used to convert images from one pixel format to another.

void stretch_blit(BITMAP *source, BITMAP *dest, int source_x, source_y, source_width, source_height, int dest_x, dest_y, dest_width, dest_height);
Like blit(), except it can scale images (so the source and destination rectangles don't need to be the same size) and requires the source and destination bitmaps to be of the same color depth. This routine doesn't do as much safety checking as the regular blit(): in particular you must take care not to copy from areas outside the source bitmap, and you cannot blit between overlapping regions, ie. you must use different bitmaps for the source and the destination. Moreover, the source must be a memory bitmap.

void masked_blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
Like blit(), but skips transparent pixels, which are marked by a zero in 256 color modes or bright pink for truecolor data (maximum red and blue, zero green), and requires the source and destination bitmaps to be of the same color depth. The source and destination regions must not overlap.

If the GFX_HW_VRAM_BLIT_MASKED bit in the gfx_capabilities flag is set, the current driver supports hardware accelerated masked blits from one part of the screen onto another. This is extremely fast, so when this flag is set it may be worth storing some of your more frequently used sprites in an offscreen portion of the video memory.

Warning: if the hardware acceleration flag is not set, masked_blit() will not work correctly when used with a source image in system or video memory so the latter must be a memory bitmap.

void masked_stretch_blit(BITMAP *source, BITMAP *dest, int source_x, source_y, source_w, source_h, int dest_x, dest_y, dest_w, dest_h);
Like masked_blit(), except it can scale images (so the source and destination rectangles don't need to be the same size). This routine doesn't do as much safety checking as the regular masked_blit(): in particular you must take care not to copy from areas outside the source bitmap. Moreover, the source must be a memory bitmap.

void draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y);
Draws a copy of the sprite bitmap onto the destination bitmap at the specified position. This is almost the same as blit(sprite, bmp, 0, 0, x, y, sprite->w, sprite->h), but it uses a masked drawing mode where transparent pixels are skipped, so the background image will show through the masked parts of the sprite. Transparent pixels are marked by a zero in 256 color modes or bright pink for truecolor data (maximum red and blue, zero green).

If the GFX_HW_VRAM_BLIT_MASKED bit in the gfx_capabilities flag is set, the current driver supports hardware accelerated sprite drawing when the source image is a video memory bitmap or a sub-bitmap of the screen. This is extremely fast, so when this flag is set it may be worth storing some of your more frequently used sprites in an offscreen portion of the video memory.

Warning: if the hardware acceleration flag is not set, draw_sprite() will not work correctly when used with a sprite image in system or video memory so the latter must be a memory bitmap.

Although generally not supporting graphics of mixed color depths, as a special case this function can be used to draw 256 color source images onto truecolor destination bitmaps, so you can use palette effects on specific sprites within a truecolor program.

void stretch_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int w, int h);
Like draw_sprite(), except it can stretch the sprite image to the specified width and height and requires the sprite image and destination bitmap to be of the same color depth. Moreover, the sprite image must be a memory bitmap.

void draw_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
void draw_sprite_h_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
void draw_sprite_vh_flip(BITMAP *bmp, BITMAP *sprite, int x, int y);
These are like draw_sprite(), but they flip the image about the vertical, horizontal, or both, axes. This produces exact mirror images, which is not the same as rotating the sprite (and it is a lot faster than the rotation routine). The sprite must be a memory bitmap.

void draw_trans_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y);
Uses the global color_map table or truecolor blender functions to overlay the sprite on top of the existing image. This must only be used after you have set up the color mapping table (for 256 color modes) or blender functions (for truecolor modes). Because it involves reading as well as writing the bitmap memory, translucent drawing is very slow if you draw directly to video RAM, so wherever possible you should use a memory bitmap instead. The bitmap and sprite must normally be in the same color depth, but as a special case you can draw 32 bit RGBA format sprites onto any hicolor or truecolor bitmap, as long as you call set_alpha_blender() first, and you can draw 8 bit alpha images onto a 32 bit RGBA destination, as long as you call set_write_alpha_blender() first.

void draw_lit_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int color);
In 256 color modes, uses the global color_map table to tint the sprite image to the specified color or to light it to the level specified by 'color', depending on the function which was used to build the table (create_trans_table or create_light_table), and draws the resulting image to the destination bitmap. In truecolor modes, uses the blender functions to light the sprite image using the alpha level specified by 'color' (the alpha level which was passed to the blender functions is ignored) and draws the resulting image to the destination bitmap. The 'color' parameter must be in the range [0-255] whatever its actual meaning is. This must only be used after you have set up the color mapping table (for 256 color modes) or blender functions (for truecolor modes).

void draw_gouraud_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int c1, int c2, int c3, int c4);
More sophisticated version of draw_lit_sprite(): the 'color' parameter is not constant across the sprite image anymore but interpolated between the four specified corner colors, which have the same actual meaning as it.

void draw_character(BITMAP *bmp, BITMAP *sprite, int x, int y, int color);
Draws a copy of the sprite bitmap onto the destination bitmap at the specified position, drawing transparent pixels in the current text mode (skipping them if the text mode is -1, otherwise drawing them in the text background color), and setting all other pixels to the specified color. Transparent pixels are marked by a zero in 256 color modes or bright pink for truecolor data (maximum red and blue, zero green). The sprite must be an 8 bit image, even if the destination is a truecolor bitmap.

void rotate_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle);
Draws the sprite image onto the bitmap. It is placed with its top left corner at the specified position, then rotated by the specified angle around its centre. The angle is a fixed point 16.16 number in the same format used by the fixed point trig routines, with 256 equal to a full circle, 64 a right angle, etc. All rotation functions can draw between any two bitmaps, even screen bitmaps or bitmaps of different color depth.

void rotate_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle);
Like rotate_sprite, but also flips the image vertically. To flip horizontally, use this routine but add itofix(128) to the angle. To flip in both directions, use rotate_sprite() and add itofix(128) to its angle.

void rotate_scaled_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle, fixed scale);
Like rotate_sprite(), but stretches or shrinks the image at the same time as rotating it.

void rotate_scaled_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle, fixed scale)
Draws the sprite, similar to rotate_scaled_sprite() except that it flips the sprite vertically first.

void pivot_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle);
Like rotate_sprite(), but aligns the point in the sprite given by (cx, cy) to (x, y) in the bitmap, then rotates around this point.

void pivot_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle);
Like rotate_sprite_v_flip(), but aligns the point in the sprite given by (cx, cy) to (x, y) in the bitmap, then rotates around this point.

void pivot_scaled_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle, fixed scale));
Like rotate_scaled_sprite(), but aligns the point in the sprite given by (cx, cy) to (x, y) in the bitmap, then rotates and scales around this point.

void pivot_scaled_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle, fixed scale)
Like rotate_scaled_sprite_v_flip(), but aligns the point in the sprite given by (cx, cy) to (x, y) in the bitmap, then rotates and scales around this point.


RLE sprites

  • destroy_rle_sprite
  • draw_lit_rle_sprite
  • draw_rle_sprite
  • draw_trans_rle_sprite
  • get_rle_sprite

Because bitmaps can be used in so many different ways, the bitmap structure is quite complicated, and it contains a lot of data. In many situations, though, you will find yourself storing images that are only ever copied to the screen, rather than being drawn onto or used as filling patterns, etc. If this is the case you may be better off storing your images in RLE_SPRITE or COMPILED_SPRITE structures rather than regular bitmaps.

RLE sprites store the image in a simple run-length encoded format, where repeated zero pixels are replaced by a single length count, and strings of non-zero pixels are preceded by a counter giving the length of the solid run. RLE sprites are usually much smaller then normal bitmaps, both because of the run length compression, and because they avoid most of the overhead of the bitmap structure. They are often also faster than normal bitmaps, because rather than having to compare every single pixel with zero to determine whether it should be drawn, it is possible to skip over a whole run of zeros with a single add, or to copy a long run of non-zero pixels with fast string instructions.

Every silver lining has a cloud, though, and in the case of RLE sprites it is a lack of flexibility. You can't draw onto them, and you can't flip them, rotate them, or stretch them. In fact the only thing you can do with them is to blast them onto a bitmap with the draw_rle_sprite() function, which is equivalent to using draw_sprite() with a regular bitmap. You can convert bitmaps into RLE sprites at runtime, or you can create RLE sprite structures in grabber datafiles by making a new object of type 'RLE sprite'.

RLE_SPRITE *get_rle_sprite(BITMAP *bitmap);
Creates an RLE sprite based on the specified bitmap (which must be a memory bitmap).

void destroy_rle_sprite(RLE_SPRITE *sprite);
Destroys an RLE sprite structure previously returned by get_rle_sprite().

void draw_rle_sprite(BITMAP *bmp, const RLE_SPRITE *sprite, int x, int y);
Draws an RLE sprite onto a bitmap at the specified position.

void draw_trans_rle_sprite(BITMAP *bmp, const RLE_SPRITE *sprite, int x, int y);
Translucent version of draw_rle_sprite(). See the description of draw_trans_sprite(). This must only be used after you have set up the color mapping table (for 256 color modes) or blender functions (for truecolor modes). The bitmap and sprite must normally be in the same color depth, but as a special case you can draw 32 bit RGBA format sprites onto any hicolor or truecolor bitmap, as long as you call set_alpha_blender() first.

void draw_lit_rle_sprite(BITMAP *bmp, const RLE_SPRITE *sprite, int x, y, color);
Tinted version of draw_rle_sprite(). See the description of draw_lit_sprite(). This must only be used after you have set up the color mapping table (for 256 color modes) or blender functions (for truecolor modes).


Compiled sprites

  • destroy_compiled_sprite
  • draw_compiled_sprite
  • get_compiled_sprite

Compiled sprites are stored as actual machine code instructions that draw a specific image onto a bitmap, using mov instructions with immediate data values. This is the fastest way to draw a masked image: on my machine drawing compiled sprites is about five times as fast as using draw_sprite() with a regular bitmap. Compiled sprites are big, so if memory is tight you should use RLE sprites instead, and what you can do with them is even more restricted than with RLE sprites, because they don't support clipping. If you try to draw one off the edge of a bitmap, you will corrupt memory and probably crash the system. You can convert bitmaps into compiled sprites at runtime, or you can create compiled sprite structures in grabber datafiles by making a new object of type 'Compiled sprite' or 'Compiled x-sprite'.

COMPILED_SPRITE *get_compiled_sprite(BITMAP *bitmap, int planar);
Creates a compiled sprite based on the specified bitmap (which must be a memory bitmap). Compiled sprites are device-dependent, so you have to specify whether to compile it into a linear or planar format. Pass FALSE as the second parameter if you are going to be drawing it onto memory bitmaps or mode 13h and SVGA screen bitmaps, and pass TRUE if you are going to draw it onto mode-X or Xtended mode screen bitmaps.

void destroy_compiled_sprite(COMPILED_SPRITE *sprite);
Destroys a compiled sprite structure previously returned by get_compiled_sprite().

void draw_compiled_sprite(BITMAP *bmp, const COMPILED_SPRITE *sprite, int x, int y);
Draws a compiled sprite onto a bitmap at the specified position. The sprite must have been compiled for the correct type of bitmap (linear or planar). This function does not support clipping.

Hint: if not being able to clip compiled sprites is a problem, a neat trick is to set up a work surface (memory bitmap, mode-X virtual screen, or whatever) a bit bigger than you really need, and use the middle of it as your screen. That way you can draw slightly off the edge without any trouble...


Text output

  • allegro_404_char
  • destroy_font
  • font
  • text_height
  • text_length
  • text_mode
  • textout
  • textout_centre
  • textout_justify
  • textout_right
  • textprintf
  • textprintf_centre
  • textprintf_justify
  • textprintf_right

Allegro provides text output routines that work with both monochrome and color fonts, which can contain any number of Unicode character ranges. The grabber program can create fonts from sets of characters drawn in a bitmap file (see grabber.txt for more information), and can also import GRX or BIOS format font files. The font structure contains a number of hooks that can be used to extend it with your own custom drawing code: see the definition in allegro/text.h for details.

extern FONT *font;
A simple 8x8 fixed size font (the mode 13h BIOS default). If you want to alter the font used by the GUI routines, change this to point to one of your own fonts. This font contains the standard ASCII (U+20 to U+7F), Latin-1 (U+A1 to U+FF), and Latin Extended-A (U+0100 to U+017F) character ranges.

extern int allegro_404_char;
When Allegro cannot find a glyph it needs in a font, it will instead output the character given in allegro_404_char. By default, this is set to the caret symbol, '^'.

int text_mode(int mode);
Sets the mode in which text will be drawn. Returns previous mode. If mode is zero or positive, text output will be opaque and the background of the characters will be set to color #mode. If mode is negative, text will be drawn transparently (ie. the background of the characters will not be altered). The default is a mode of zero.

void textout(BITMAP *bmp, const FONT *f, const char *s, int x, y, int color);
Writes the string s onto the bitmap at position x, y, using the current text mode and the specified font and foreground color. If the color is -1 and a color font is in use, it will be drawn using the colors from the original font bitmap (the one you imported into the grabber program), which allows multicolored text output.

void textout_centre(BITMAP *bmp, const FONT *f, const char *s, int x, y, color);
Like textout(), but interprets the x coordinate as the centre rather than the left edge of the string.

void textout_right(BITMAP *bmp, const FONT *f, const char *s, int x, y, color);
Like textout(), but interprets the x coordinate as the right rather than the left edge of the string.

void textout_justify(BITMAP *bmp, const FONT *f, const char *s, int x1, int x2, int y, int diff, int color);
Draws justified text within the region x1-x2. If the amount of spare space is greater than the diff value, it will give up and draw regular left justified text instead.

void textprintf(BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...);
Formatted text output, using a printf() style format string.

void textprintf_centre(BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...);
Like textprintf(), but interprets the x coordinate as the centre rather than the left edge of the string.

void textprintf_right(BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...);
Like textprintf(), but interprets the x coordinate as the right rather than the left edge of the string.

void textprintf_justify(BITMAP *bmp, const FONT *f, int x1, int x2, int y, int diff, int color, const char *fmt, ...);
Like textout_justify, but using a printf() style format string.

int text_length(const FONT *f, const char *str);
Returns the length (in pixels) of a string in the specified font.

int text_height(const FONT *f)
Returns the height (in pixels) of the specified font.

void destroy_font(FONT *f);
Frees the memory being used by a font structure.


Polygon rendering

  • clear_scene
  • clear_zbuffer
  • clip3d
  • clip3d_f
  • create_scene
  • create_sub_zbuffer
  • create_zbuffer
  • destroy_scene
  • destroy_zbuffer
  • polygon3d
  • polygon3d_f
  • quad3d
  • quad3d_f
  • render_scene
  • scene_gap
  • scene_polygon3d
  • scene_polygon3d_f
  • set_zbuffer
  • triangle3d
  • triangle3d_f

void polygon3d(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D *vtx[]);
void polygon3d_f(BITMAP *bmp, int type, BITMAP *texture, int vc, V3D_f *vtx[]);
Draw 3d polygons onto the specified bitmap, using the specified rendering mode. Unlike the regular polygon() function, these routines don't support concave or self-intersecting shapes, and they can't draw onto mode-X screen bitmaps (if you want to write 3d code in mode-X, draw onto a memory bitmap and then blit to the screen). The width and height of the texture bitmap must be powers of two, but can be different, eg. a 64x16 texture is fine, but a 17x3 one is not. The vertex count parameter (vc) should be followed by an array containing the appropriate number of pointers to vertex structures: polygon3d() uses the fixed point V3D structure, while polygon3d_f() uses the floating point V3D_f structure. These are defined as:

   typedef struct V3D
   {
      fixed x, y, z;       - position
      fixed u, v;          - texture map coordinates
      int c;               - color
   } V3D;

   typedef struct V3D_f
   {
      float x, y, z;       - position
      float u, v;          - texture map coordinates
      int c;               - color
   } V3D_f;
How the vertex data is used depends on the rendering mode:

The x and y values specify the position of the vertex in 2d screen coordinates.

The z value is only required when doing perspective correct texture mapping, and specifies the depth of the point in 3d world coordinates.

The u and v coordinates are only required when doing texture mapping, and specify a point on the texture plane to be mapped on to this vertex. The texture plane is an infinite plane with the texture bitmap tiled across it. Each vertex in the polygon has a corresponding vertex on the texture plane, and the image of the resulting polygon in the texture plane will be mapped on to the polygon on the screen.

We refer to pixels in the texture plane as texels. Each texel is a block, not just a point, and whole numbers for u and v refer to the top-left corner of a texel. This has a few implications. If you want to draw a rectangular polygon and map a texture sized 32x32 on to it, you would use the texture coordinates (0,0), (0,32), (32,32) and (32,0), assuming the vertices are specified in anticlockwise order. The texture will then be mapped perfectly on to the polygon. However, note that when we set u=32, the last column of texels seen on the screen is the one at u=31, and the same goes for v. This is because the coordinates refer to the top-left corner of the texels. In effect, texture coordinates at the right and bottom on the texture plane are exclusive.

There is another interesting point here. If you have two polygons side by side sharing two vertices (like the two parts of folded piece of cardboard), and you want to map a texture across them seamlessly, the values of u and v on the vertices at the join will be the same for both polygons. For example, if they are both rectangular, one polygon may use (0,0), (0,32), (32,32) and (32,0), and the other may use (32,0), (32,32), (64,32), (64,0). This would create a seamless join.

Of course you can specify fractional numbers for u and v to indicate a point part-way across a texel. In addition, since the texture plane is infinite, you can specify larger values than the size of the texture. This can be used to tile the texture several times across the polygon.

The c value specifies the vertex color, and is interpreted differently by various rendering modes.

The type parameter specifies the polygon rendering mode, and can be any of the values:

POLYTYPE_FLAT:
A simple flat shaded polygon, taking the color from the c value of the first vertex. This polygon type is affected by the drawing_mode() function, so it can be used to render XOR or translucent polygons.

POLYTYPE_GCOL:
A single-color gouraud shaded polygon. The colors for each vertex are taken from the c value, and interpolated across the polygon. This is very fast, but will only work in 256 color modes if your palette contains a smooth gradient between the colors. In truecolor modes it interprets the color as a packed, display-format value as produced by the makecol() function.

POLYTYPE_GRGB:
A gouraud shaded polygon which interpolates RGB triplets rather than a single color. In 256 color modes this uses the global rgb_map table to convert the result to an 8 bit paletted color, so it must only be used after you have set up the RGB mapping table! The colors for each vertex are taken from the c value, which is interpreted as a 24 bit RGB triplet (0xFF0000 is red, 0x00FF00 is green, and 0x0000FF is blue).

POLYTYPE_ATEX:
An affine texture mapped polygon. This stretches the texture across the polygon with a simple 2d linear interpolation, which is fast but not mathematically correct. It can look ok if the polygon is fairly small or flat-on to the camera, but because it doesn't deal with perspective foreshortening, it can produce strange warping artifacts. To see what I mean, run test.exe and see what happens to the polygon3d() test when you zoom in very close to the cube.

POLYTYPE_PTEX:
A perspective-correct texture mapped polygon. This uses the z value from the vertex structure as well as the u/v coordinates, so textures are displayed correctly regardless of the angle they are viewed from. Because it involves division calculations in the inner texture mapping loop, this mode is a lot slower than POLYTYPE_ATEX, and it uses floating point so it will be very slow on anything less than a Pentium (even with an FPU, a 486 can't overlap floating point division with other integer operations like the Pentium can).

POLYTYPE_ATEX_MASK:
POLYTYPE_PTEX_MASK:
Like POLYTYPE_ATEX and POLYTYPE_PTEX, but zero texture map pixels are skipped, allowing parts of the texture map to be transparent.

POLYTYPE_ATEX_LIT:
POLYTYPE_PTEX_LIT:
Like POLYTYPE_ATEX and POLYTYPE_PTEX, but the global color_map table (for 256 color modes) or blender function (for non-MMX truecolor modes) is used to blend the texture with a light level taken from the c value in the vertex structure. This must only be used after you have set up the color mapping table or blender functions!

POLYTYPE_ATEX_MASK_LIT:
POLYTYPE_PTEX_MASK_LIT:
Like POLYTYPE_ATEX_LIT and POLYTYPE_PTEX_LIT, but zero texture map pixels are skipped, allowing parts of the texture map to be transparent.

POLYTYPE_ATEX_TRANS:
POLYTYPE_PTEX_TRANS:
Render translucent textures. All the general rules for drawing translucent things apply. However, these modes have a major limitation: they only work with memory bitmaps or linear frame buffers (not with banked frame buffers). Don't even try, they do not check and your program will die horribly (or at least draw wrong things).

POLYTYPE_ATEX_MASK_TRANS:
POLYTYPE_PTEX_MASK_TRANS:
Like POLYTYPE_ATEX_TRANS and POLYTYPE_PTEX_TRANS, but zero texture map pixels are skipped.

If the CPU_MMX flag of the cpu_capabilities global variable is set, the GRGB and truecolor *LIT routines will be optimised using MMX instructions. If the CPU_3DNOW flag is set, the truecolor PTEX*LIT routines will take advantage of the 3DNow! CPU extensions.

Using MMX for *LIT routines has a side effect: normally (without MMX), these routines use the blender functions used also for other lighting functions, set with set_trans_blender() or set_blender_mode(). The MMX versions only use the RGB value passed to set_trans_blender() and do the linear interpolation themselves. Therefore a new set of blender functions passed to set_blender_mode() is ignored.

void triangle3d(BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3);
void triangle3d_f(BITMAP *bmp, int type, BITMAP *tex, V3D_f *v1, *v2, *v3);
Draw 3d triangles, using either fixed or floating point vertex structures. Unlike quad3d[_f], triangle3d[_f] functions are not wrappers of polygon3d[_f]. The triangle3d[_f] functions use their own routines taking into account the constantness of the gradients. Therefore triangle3d[_f](bmp, type, tex, v1, v2, v3) is faster than polygon3d[_f](bmp, type, tex, 3, v[]).

void quad3d(BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3, *v4);
void quad3d_f(BITMAP *bmp, int type, BITMAP *tex, V3D_f *v1, *v2, *v3, *v4);
Draw 3d quads, using either fixed or floating point vertex structures. These are equivalent to calling polygon3d(bmp, type, tex, 4, v[]); or polygon3d_f(bmp, type, tex, 4, v[]);

int clip3d_f(int type, float min_z, float max_z, int vc, const V3D_f *vtx[], V3D_f *vout[], V3D_f *vtmp[], int out[]);
Clips the polygon given in vtx. The number of vertices is vc, the result goes in vout, and vtmp and out are needed for internal purposes. The pointers in vtx, vout and vtmp must point to valid V3D_f structures. As additional vertices may appear in the process of clipping, so the size of vout, vtmp and out should be at least vc * (1.5 ^ n), where n is the number of clipping planes (5 or 6), and '^' denotes "to the power of". The frustum (viewing volume) is defined by -z<x<z, -z<y<z, 0<min_z<z<max_z. If max_z<=min_z, the z<max_z clipping is not done. As you can see, clipping is done in the camera space, with perspective in mind, so this routine should be called after you apply the camera matrix, but before the perspective projection. The routine will correctly interpolate u, v, and c in the vertex structure. However, no provision is made for high/truecolor GCOL.

int clip3d(int type, fixed min_z, fixed max_z, int vc, const V3D *vtx[], V3D *vout[], V3D *vtmp[], int out[]);
Fixed point version of clip3d_f(). This function should be used with caution, due to the limited precision of fixed point arithmetic and high chance of rounding errors: the floating point code is better for most situations.

A Z-buffer stores the depth of each pixel that is drawn on a viewport. When a 3D object is rendered, the depth of each of its pixels is compared against the value stored into the Z-buffer: if the pixel is closer it is drawn, otherwise it is skipped.

No polygon sorting is needed. However, backface culling should be done because it prevents many invisible polygons being compared against the Z-buffer. Z-buffered rendering is the only algorithm supported by Allegro that directly solves penetrating shapes (see example exzbuf.c, for instance). The price to pay is more complex (and slower) routines.

Z-buffered polygons are designed as an extension of the normal POLYTYPE_* rendering styles. Just OR the POLYTYPE with the value POLYTYPE_ZBUF, and the normal polygon3d(), polygon3d_f(), quad3d(), etc. functions will render z-buffered polygons.

Example:

   polygon3d(bmp, POLYTYPE_ATEX | POLYTYPE_ZBUF, tex, vc, vtx);

Of course, the z coordinates have to be valid regardless of rendering style.

A Z-buffered rendering procedure looks like a double-buffered rendering procedure. You should follow four steps: create a Z-buffer at the beginning of the program and make the library use it by calling set_zbuffer(). Then, for each frame, clear the Z-buffer and draw polygons with POLYTYPE_* | POLYTYPE_ZBUF and finally destroy the Z-buffer when leaving the program.

Notes on Z-buffered renderers:

  • Unlike the normal POLYTYPE_FLAT renderers, the Z-buffered ones don't use the hline() routine. Therefore DRAW_MODE has no effect.

  • The *LIT* routines work the traditional way - through the set of blender routines.

  • All the Z-buffered routines are much slower than their normal counterparts (they all use the FPU to interpolate and test 1/z values).

ZBUFFER *create_zbuffer(BITMAP *bmp);
Creates a Z-buffer using the size of the BITMAP you are planning to draw on. Several Z-buffers can be defined but only one can be used at the same time, so you must call set_zbuffer() to make this Z-buffer active.

ZBUFFER *create_sub_zbuffer(ZBUFFER *parent, int x, int y, int width, int height);
Creates a sub-z-buffer, ie. a z-buffer sharing drawing memory with a pre-existing z-buffer, but possibly with a different size. The same rules as for sub-bitmaps apply: the sub-z-buffer width and height can extend beyond the right and bottom edges of the parent (they will be clipped), but the origin point must lie within the parent region.

When drawing z-buffered to a bitmap, the top left corner of the bitmap is always mapped to the top left corner of the current z-buffer. So this function is primarily useful if you want to draw to a sub-bitmap and use the corresponding sub-area of the z-buffer. In other cases, eg. if you just want to draw to a sub-bitmap of screen (and not to other parts of screen), then you would usually want to create a normal z-buffer (not sub-z-buffer) the size of the visible screen. You don't need to first create a z-buffer the size of the virtual screen and then a sub-z-buffer of that.

void set_zbuffer(ZBUFFER *zbuf);
Makes the given Z-buffer be the active one. This should have been previously created with create_zbuffer().

void clear_zbuffer(ZBUFFER *zbuf, float z);
Writes z into the given Z-buffer (0 means far away). This function should be used to initialize the Z-buffer before each frame. Actually, low-level routines compare depth of the current pixel with 1/z: for example, if you want to clip polygons farther than 10, you must call clear_zbuffer(zbuf, 0.1);

void destroy_zbuffer(ZBUFFER *zbuf);
Destroys the Z-buffer when you are finished with it.

Allegro provides two simple approaches to remove hidden surfaces:

  • Z-buffering - (see above)

  • Scan-line algorithms - along each scanline on your screen, you keep track of what polygons you are "in" and which is the nearest. This status changes only where the scanline crosses some polygon edge. So you have to juggle an edge list and a polygon list. And you have to sort the edges for each scanline (this can be countered by keeping the order of the previous scanline - it won't change much). The BIG advantage is that you write each pixel only once. If you have a lot of overlapping polygons you can get incredible speeds compared to any of the previous algorithms. This algorithm is covered by the *_scene routines.

The scene rendering has approximately the following steps:

  • Initialize the scene (set the clip area, clear the bitmap, blit a background, etc.)

  • Call clear_scene().

  • Transform all your points to camera space.

  • Clip polygons.

  • Project with persp_project() or persp_project_f().

  • "Draw" polygons with scene_polygon3d() and/or scene_polygon3d_f(). This doesn't do any actual drawing, only initializes tables.

  • Render all the polygons defined previously to the bitmap with render_scene().

  • Overlay some non-3D graphics.

  • Show the bitmap (blit it to screen, flip the page, etc).

For each horizontal line in the viewport an x-sorted edge list is used to keep track of what polygons are "in" and which is the nearest. Vertical coherency is used - the edge list for a scanline is sorted starting from the previous one - it won't change much. The scene rendering routines use the same low-level asm routines as normal polygon3d().

Notes on scene rendering:

  • Unlike polygon3d(), scene_polygon3d() requires valid z coordinates for all vertices, regardless of rendering style (unlike polygon3d(), which only uses z coordinate for *PTEX*).

  • All polygons passed to scene_polygon3d() have to be persp_project()'ed.

  • After render_scene() the mode is reset to SOLID.

Using a lot of *MASK* polygons drastically reduces performance, because when a MASKed polygon is the first in line of sight, the polygons underneath have to be drawn too. The same applies to FLAT polygons drawn with DRAW_MODE_TRANS.

Z-buffered rendering works also within the scene renderer. It may be helpful when you have a few intersecting polygons, but most of the polygons may be safely rendered by the normal scanline sorting algo. Same as before: just OR the POLYTYPE with POLYTYPE_ZBUF. Also, you have to clear the z-buffer at the start of the frame. Example:

   clear_scene(buffer);
   if (some_polys_are_zbuf) clear_zbuffer(0.);
   while (polygons) {
      ...
      if (this_poly_is_zbuf) type |= POLYTYPE_ZBUF;
      scene_polygon3d(type, tex, vc, vtx);
   }
   render_scene();

int create_scene(int nedge, int npoly);
Allocates memory for a scene, nedge and npoly are your estimates of how many edges and how many polygons you will render (you cannot get over the limit specified here). If you use same values in succesive calls, the space will be reused (no new malloc()).

The memory allocated is a little less than 150 * (nedge + npoly) bytes. Returns zero on success, or a negative number if allocations fail.

void clear_scene(BITMAP *bmp);
Initializes a scene. The bitmap is the bitmap you will eventually render on.

void destroy_scene();
Deallocate memory previously allocated by create_scene.

int scene_polygon3d(int type, BITMAP *texture, int vc, V3D *vtx[]);
int scene_polygon3d_f(int type, BITMAP *texture, int vc, V3D_f *vtx[]);
Puts a polygon in the rendering list. Nothing is really rendered at this moment. Should be called between clear_scene() and render_scene().

Arguments are the same as for polygon3d(), except the bitmap is missing. The one passed to clear_scene() will be used.

Unlike polygon3d(), the polygon may be concave or self-intersecting. Shapes that penetrate one another may look OK, but they are not really handled by this code.

Note that the texture is stored as a pointer only, and you should keep the actual bitmap around until render_scene(), where it is used.

Since the FLAT style is implemented with the low-level hline() funtion, the FLAT style is subject to DRAW_MODEs. All these modes are valid. Along with the polygon, this mode will be stored for the rendering moment, and also all the other related variables (color_map pointer, pattern pointer, anchor, blender values).

The settings of the CPU_MMX and CPU_3DNOW flags of the cpu_capabilities global variable on entry in this routine affect the choice of low-level asm routine that will be used by render_scene() for this polygon.

Returns zero on success, or a negative number if it won't be rendered for lack of a rendering routine.

void render_scene();
Renders all the specified scene_polygon3d()'s on the bitmap passed to clear_scene(). Rendering is done one scanline at a time, with no pixel being processed more than once.

Note that between clear_scene() and render_scene() you shouldn't change the clip rectangle of the destination bitmap. For speed reasons, you should set the clip rectangle to the minimum.

Note also that all the textures passed to scene_polygon3d() are stored as pointers only and actually used in render_scene().

extern float scene_gap;
This number (default value = 100.0) controls the behaviour of the z-sorting algorithm. When an edge is very close to another's polygon plane, there is an interval of uncertainty in which you cannot tell which object is visible (which z is smaller). This is due to cumulative numerical errors for edges that have undergone a lot of transformations and interpolations.

The default value means that if the 1/z values (in projected space) differ by only 1/100 (one percent), they are considered to be equal and the x-slopes of the planes are used to find out which plane is getting closer when we move to the right.

Larger values means narrower margins, and increasing the chance of missing true adjacent edges/planes. Smaller values means larger margins, and increasing the chance of mistaking close polygons for adjacent ones. The value of 100 is close to the optimum. However, the optimum shifts slightly with resolution, and may be application-dependent. It is here for you to fine-tune.


Transparency and patterned drawing

  • color_map
  • create_blender_table
  • create_color_table
  • create_light_table
  • create_trans_table
  • drawing_mode
  • set_add_blender
  • set_alpha_blender
  • set_blender_mode
  • set_blender_mode_ex
  • set_burn_blender
  • set_color_blender
  • set_difference_blender
  • set_dissolve_blender
  • set_dodge_blender
  • set_hue_blender
  • set_invert_blender
  • set_luminance_blender
  • set_multiply_blender
  • set_saturation_blender
  • set_screen_blender
  • set_trans_blender
  • set_write_alpha_blender
  • solid_mode
  • xor_mode

void drawing_mode(int mode, BITMAP *pattern, int x_anchor, int y_anchor);
Sets the graphics drawing mode. This only affects the geometric routines like putpixel, lines, rectangles, circles, polygons, floodfill, etc, not the text output, blitting, or sprite drawing functions. The mode should be one of the following constants:

      DRAW_MODE_SOLID               - the default, solid color
                                      drawing
      DRAW_MODE_XOR                 - exclusive-or drawing
      DRAW_MODE_COPY_PATTERN        - multicolored pattern fill
      DRAW_MODE_SOLID_PATTERN       - single color pattern fill
      DRAW_MODE_MASKED_PATTERN      - masked pattern fill
      DRAW_MODE_TRANS               - translucent color blending
In DRAW_MODE_SOLID, pixels of the bitmap being drawn onto are simply replaced by those produced by the drawing function.

In DRAW_MODE_XOR, pixels are written to the bitmap with an exclusive-or operation rather than a simple copy, so drawing the same shape twice will erase it. Because it involves reading as well as writing the bitmap memory, xor drawing is a lot slower than the normal replace mode.

With the patterned modes, you provide a pattern bitmap which is tiled across the surface of the shape. Allegro stores a pointer to this bitmap rather than copying it, so you must not destroy the bitmap while it is still selected as the pattern. The width and height of the pattern must be powers of two, but they can be different, eg. a 64x16 pattern is fine, but a 17x3 one is not. The pattern is tiled in a grid starting at point (x_anchor, y_anchor). Normally you should just pass zero for these values, which lets you draw several adjacent shapes and have the patterns meet up exactly along the shared edges. Zero alignment may look peculiar if you are moving a patterned shape around the screen, however, because the shape will move but the pattern alignment will not, so in some situations you may wish to alter the anchor position.

When you select DRAW_MODE_COPY_PATTERN, pixels are simply copied from the pattern bitmap onto the destination bitmap. This allows the use of multicolored patterns, and means that the color you pass to the drawing routine is ignored. This is the fastest of the patterned modes.

In DRAW_MODE_SOLID_PATTERN, each pixel in the pattern bitmap is compared with the mask color, which is zero in 256 color modes or bright pink for truecolor data (maximum red and blue, zero green). If the pattern pixel is solid, a pixel of the color you passed to the drawing routine is written to the destination bitmap, otherwise a zero is written. The pattern is thus treated as a monochrome bitmask, which lets you use the same pattern to draw different shapes in different colors, but prevents the use of multicolored patterns.

DRAW_MODE_MASKED_PATTERN is almost the same as DRAW_MODE_SOLID_PATTERN, but the masked pixels are skipped rather than being written as zeros, so the background shows through the gaps.

In DRAW_MODE_TRANS, the global color_map table or truecolor blender functions are used to overlay pixels on top of the existing image. This must only be used after you have set up the color mapping table (for 256 color modes) or blender functions (for truecolor modes). Because it involves reading as well as writing the bitmap memory, translucent drawing is very slow if you draw directly to video RAM, so wherever possible you should use a memory bitmap instead.

void xor_mode(int on);
This is a shortcut for toggling xor drawing mode on and off. Calling xor_mode(TRUE) is equivalent to drawing_mode (DRAW_MODE_XOR, NULL, 0, 0); Calling xor_mode(FALSE) is equivalent to drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);

void solid_mode();
This is a shortcut for selecting solid drawing mode. It is equivalent to calling drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);

In paletted video modes, translucency and lighting are implemented with a 64k lookup table, which contains the result of combining any two colors c1 and c2. You must set up this table before you use any of the translucency or lighting routines. Depending on how you construct the table, a range of different effects are possible. For example, translucency can be implemented by using a color halfway between c1 and c2 as the result of the combination. Lighting is achieved by treating one of the colors as a light level (0-255) rather than a color, and setting up the table appropriately. A range of specialised effects are possible, for instance replacing any color with any other color and making individual source or destination colors completely solid or invisible.

Color mapping tables can be precalculated with the colormap utility, or generated at runtime. The COLOR_MAP structure is defined as:

typedef struct {
   unsigned char data[PAL_SIZE][PAL_SIZE];
} COLOR_MAP;
extern COLOR_MAP *color_map;
Global pointer to the color mapping table. This must be set before using any translucent or lit drawing functions in a 256 color video mode!

void create_trans_table(COLOR_MAP *table, const PALETTE pal, int r, g, b, void (*callback)(int pos));
Fills the specified color mapping table with lookup data for doing translucency effects with the specified palette. When combining the colors c1 and c2 with this table, the result will be a color somewhere between the two. The r, g, and b parameters specify the solidity of each color component, ranging from 0 (totally transparent) to 255 (totally solid). For 50% solidity, pass 128. This function treats source color #0 as a special case, leaving the destination unchanged whenever a zero source pixel is encountered, so that masked sprites will draw correctly. If the callback function is not NULL, it will be called 256 times during the calculation, allowing you to display a progress indicator.

void create_light_table(COLOR_MAP *table, const PALETTE pal, int r, g, b, void (*callback)(int pos));
Fills the specified color mapping table with lookup data for doing lighting effects with the specified palette. When combining the colors c1 and c2 with this table, c1 is treated as a light level from 0-255. At light level 255 the table will output color c2 unchanged, at light level 0 it will output the r, g, b value you specify to this function, and at intermediate light levels it will output a color somewhere between the two extremes. The r, g, and b values are in the range 0-63. If the callback function is not NULL, it will be called 256 times during the calculation, allowing you to display a progress indicator.

void create_color_table(COLOR_MAP *table, const PALETTE pal, void (*blend)(PALETTE pal, int x, int y, RGB *rgb), void (*callback)(int pos));
Fills the specified color mapping table with lookup data for doing customised effects with the specified palette, calling the blend function to determine the results of each color combination. Your blend routine will be passed a pointer to the palette and the two colors which are to be combined, and should fill in the RGB structure with the desired result in 0-63 format. Allegro will then search the palette for the closest match to the RGB color that you requested, so it doesn't matter if the palette has no exact match for this color. If the callback function is not NULL, it will be called 256 times during the calculation, allowing you to display a progress indicator.

void create_blender_table(COLOR_MAP *table, const PALETTE pal, void (*callback)(int pos));
Fills the specified color mapping table with lookup data for doing a paletted equivalent of whatever truecolor blender mode is currently selected. After calling set_trans_blender(), set_blender_mode(), or any of the other truecolor blender mode routines, you can use this function to create an 8 bit mapping table that will have the same results as whatever 24 bit blending mode you have enabled.

In truecolor video modes, translucency and lighting are implemented by a blender function of the form:

unsigned long (*BLENDER_FUNC)(unsigned long x, y, n);

For each pixel to be drawn, this routine is passed two color parameters x and y, decomposes them into their red, green and blue components, combines them according to some mathematical transformation involving the interpolation factor n, and then merges the result back into a single return color value, which will be used to draw the pixel onto the destination bitmap.

The parameter x represents the blending modifier color and the parameter y represents the base color to be modified. The interpolation factor n is in the range [0-255] and controls the solidity of the blending.

When a translucent drawing function is used, x is the color of the source, y is the color of the bitmap begin drawn onto and n is the alpha level that was passed to the function that sets the blending mode (the RGB triplet that was passed to this function is not taken into account).

When a lit sprite drawing function is used, x is the color represented by the RGB triplet that was passed to the function that sets the blending mode (the alpha level that was passed to this function is not taken into account), y is the color of the sprite and n is the alpha level that was passed to the drawing function itself.

Since these routines may be used from various different color depths, there are three such callbacks, one for use with 15 bit 5.5.5 pixels, one for 16 bit 5.6.5 pixels, and one for 24 bit 8.8.8 pixels (this can be shared between the 24 and 32 bit code since the bit packing is the same).

void set_trans_blender(int r, int g, int b, int a);
Enables a linear interpolator blender mode for combining translucent or lit truecolor pixels.

void set_alpha_blender();
Enables the special alpha-channel blending mode, which is used for drawing 32 bit RGBA sprites. After calling this function, you can use draw_trans_sprite() or draw_trans_rle_sprite() to draw a 32 bit source image onto any hicolor or truecolor destination. The alpha values will be taken directly from the source graphic, so you can vary the solidity of each part of the image. You can't use any of the normal translucency functions while this mode is active, though, so you should reset to one of the normal blender modes (eg. set_trans_blender()) before drawing anything other than 32 bit RGBA sprites.

void set_write_alpha_blender();
Enables the special alpha-channel editing mode, which is used for drawing alpha channels over the top of an existing 32 bit RGB sprite, to turn it into an RGBA format image. After calling this function, you can set the drawing mode to DRAW_MODE_TRANS and then write draw color values (0-255) onto a 32 bit image. This will leave the color values unchanged, but alter the alpha to whatever values you are writing. After enabling this mode you can also use draw_trans_sprite() to superimpose an 8 bit alpha mask over the top of an existing 32 bit sprite.

void set_add_blender(int r, int g, int b, int a);
Enables an additive blender mode for combining translucent or lit truecolor pixels.

void set_burn_blender(int r, int g, int b, int a);
Enables a burn blender mode for combining translucent or lit truecolor pixels. Here the lightness values of the colours of the source image reduce the lightness of the destination image, darkening the image.

void set_color_blender(int r, int g, int b, int a);
Enables a color blender mode for combining translucent or lit truecolor pixels. Applies only the hue and saturation of the source image to the destination image. The luminance of the destination image is not affected.

void set_difference_blender(int r, int g, int b, int a);
Enables a difference blender mode for combining translucent or lit truecolor pixels. This makes an image which has colours calculated by the difference between the source and destination colours.

void set_dissolve_blender(int r, int g, int b, int a);
Enables a dissolve blender mode for combining translucent or lit truecolor pixels. Randomly replaces the colours of some pixels in the destination image with those of the source image. The number of pixels replaced depends on the alpha value (higher value, more pixels replaced; you get the idea :).

void set_dodge_blender(int r, int g, int b, int a);
Enables a dodge blender mode for combining translucent or lit truecolor pixels. The lightness of colours in the source lighten the colours of the destination. White has the most effect; black has none.

void set_hue_blender(int r, int g, int b, int a);
Enables a hue blender mode for combining translucent or lit truecolor pixels. This applies the hue of the source to the destination.

void set_invert_blender(int r, int g, int b, int a);
Enables an invert blender mode for combining translucent or lit truecolor pixels. Blends the inverse (or negative) colour of the source with the destination.

void set_luminance_blender(int r, int g, int b, int a);
Enables a luminance blender mode for combining translucent or lit truecolor pixels. Applies the luminance of the source to the destination. The colour of the destination is not affected.

void set_multiply_blender(int r, int g, int b, int a);
Enables a multiply blender mode for combining translucent or lit truecolor pixels. Combines the source and destination images, multiplying the colours to produce a darker colour. If a colour is multiplied by white it remains unchanged; when multiplied by black it also becomes black.

void set_saturation_blender(int r, int g, int b, int a);
Enables a saturation blender mode for combining translucent or lit truecolor pixels. Applies the saturation of the source to the destination image.

void set_screen_blender(int r, int g, int b, int a);
Enables a screen blender mode for combining translucent or lit truecolor pixels. This blender mode lightens the colour of the destination image by multiplying the inverse of the source and destination colours. Sort of like the opposite of the multiply blender mode.

void set_blender_mode(BLENDER_FUNC b15, b16, b24, int r, g, b, a);
Specifies a custom set of truecolor blender routines, which can be used to implement whatever special interpolation modes you need. This function shares a single blender between the 24 and 32 bit modes.

void set_blender_mode_ex(BLENDER_FUNC b15, b16, b24, b32, b15x, b16x, b24x, int r, g, b, a);
Like set_blender_mode(), but allows you to specify a more complete set of blender routines. The b15, b16, b24, and b32 routines are used when drawing pixels onto destinations of the same format, while b15x, b16x, and b24x are used by draw_trans_sprite() and draw_trans_rle_sprite() when drawing RGBA images onto destination bitmaps of another format. These blenders will be passed a 32 bit x parameter, along with a y value of a different color depth, and must try to do something sensible in response.


Converting between color formats

  • bestfit_color
  • create_rgb_table
  • hsv_to_rgb
  • rgb_map
  • rgb_to_hsv

In general, Allegro is designed to be used in only one color depth at a time, so you will call set_color_depth() once and then store all your bitmaps in the same format. If you want to mix several different pixel formats, you can use create_bitmap_ex() in place of create_bitmap(), and call bitmap_color_depth() to query the format of a specific image. Most of the graphics routines require all their input parameters to be in the same format (eg. you cannot stretch a 15 bit source bitmap onto a 24 bit destination), but there are some exceptions: blit() and the rotation routines can copy between bitmaps of any format, converting the data as required, draw_sprite() can draw 256 color source images onto destinations of any format, draw_character() _always_ uses a 256 color source bitmap, whatever the format of the destination, the draw_trans_sprite() and draw_trans_rle_sprite() functions are able to draw 32 bit RGBA images onto any hicolor or truecolor destination, as long as you call set_alpha_blender() first, and the draw_trans_sprite() function is able to draw an 8 bit alpha channel image over the top of an existing 32 bit image, as long as you call set_write_alpha_blender() first.

Expanding a 256 color source onto a truecolor destination is fairly fast (obviously you must set the correct palette before doing this conversion!). Converting between different truecolor formats is slightly slower, and reducing truecolor images to a 256 color destination is very slow (it can be sped up significantly if you set up the global rgb_map table before doing the conversion).

int bestfit_color(const PALETTE pal, int r, int g, int b);
Searches the specified palette for the closest match to the requested color, which are specified in the VGA hardware 0-63 format. Normally you should call makecol8() instead, but this lower level function may be useful if you need to use a palette other than the currently selected one, or specifically don't want to use the rgb_map lookup table.

extern RGB_MAP *rgb_map;
To speed up reducing RGB values to 8 bit paletted colors, Allegro uses a 32k lookup table (5 bits for each color component). You must set up this table before using the gouraud shading routines, and if present the table will also vastly accelerate the makecol8() function. RGB tables can be precalculated with the rgbmap utility, or generated at runtime. The RGB_MAP structure is defined as:

   typedef struct {
      unsigned char data[32][32][32];
   } RGB_MAP;
void create_rgb_table(RGB_MAP *table, const PALETTE pal, void (*callback)(int pos));
Fills the specified RGB mapping table with lookup data for the specified palette. If the callback function is not NULL, it will be called 256 times during the calculation, allowing you to display a progress indicator.

void hsv_to_rgb(float h, float s, float v, int *r, int *g, int *b);
void rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v);
Convert color values between the HSV and RGB colorspaces. The RGB values range from 0 to 255, hue is from 0 to 360, and saturation and value are from 0 to 1.


Direct access to video memory

The bitmap structure looks like:

typedef struct BITMAP
{
   int w, h;               - size of the bitmap in pixels
   int clip;               - non-zero if clipping is turned on
   int cl, cr, ct, cb;     - clip rectangle left, right, top, and bottom
   int seg;                - segment for use with the line pointers
   unsigned char *line[];  - pointers to the start of each line
} BITMAP;
There is some other stuff in the structure as well, but it is liable to change and you shouldn't use anything except the above. The clipping rectangle is inclusive on the left and top (0 allows drawing to position 0) but exclusive on the right and bottom (10 allows drawing to position 9, but not to 10). Note this is not the same format as you pass to set_clip(), which takes inclusive coordinates for all four corners.

There are several ways to get direct access to the image memory of a bitmap, varying in complexity depending on what sort of bitmap you are using.

The simplest approach will only work with memory bitmaps (obtained from create_bitmap(), grabber datafiles, and image files) and sub-bitmaps of memory bitmaps. This uses a table of char pointers, called 'line', which is a part of the bitmap structure and contains pointers to the start of each line of the image. For example, a simple memory bitmap putpixel function is:

   void memory_putpixel(BITMAP *bmp, int x, int y, int color)
   {
      bmp->line[y][x] = color;
   }

For truecolor modes you need to cast the line pointer to the appropriate type, for example:

   void memory_putpixel_15_or_16_bpp(BITMAP *bmp, int x, int y, int color)
   {
      ((short *)bmp->line[y])[x] = color;
   }

   void memory_putpixel_32(BITMAP *bmp, int x, int y, int color)
   {
      ((long *)bmp->line[y])[x] = color;
   }

If you want to write to the screen as well as to memory bitmaps, you need to use some helper macros, because the video memory may not be part of your normal address space. This simple routine will work for any linear screen, eg. a VESA linear framebuffers:

   void linear_screen_putpixel(BITMAP *bmp, int x, int y, int color)
   {
      bmp_select(bmp);
      bmp_write8((unsigned long)bmp->line[y]+x, color);
   }
For truecolor modes you should replace the bmp_write8() with bmp_write16(), bmp_write24(), or bmp_write32(), and multiply the x offset by the number of bytes per pixel. There are of course similar functions to read a pixel value from a bitmap, namely bmp_read8(), bmp_read16(), bmp_read24() and bmp_read32().

This still won't work in banked SVGA modes, however, or on platforms like Windows that do special processing inside the bank switching functions. For more flexible access to bitmap memory, you need to call the routines:

unsigned long bmp_write_line(BITMAP *bmp, int line);
Selects the line of a bitmap that you are going to draw onto.

unsigned long bmp_read_line(BITMAP *bmp, int line);
Selects the line of a bitmap that you are going to read from.

unsigned long bmp_unwrite_line(BITMAP *bmp);
Releases the bitmap memory after you are finished with it. You only need to call this once at the end of a drawing operation, even if you have called bmp_write_line() or bmp_read_line() several times before it.

These are implemented as inline assembler routines, so they are not as inefficient as they might seem. If the bitmap doesn't require bank switching (ie. it is a memory bitmap, mode 13h screen, etc), these functions just return bmp->line[line].

Although SVGA bitmaps are banked, Allegro provides linear access to the memory within each scanline, so you only need to pass a y coordinate to these functions. Various x positions can be obtained by simply adding the x coordinate to the returned address. The return value is an unsigned long rather than a char pointer because the bitmap memory may not be in your data segment, and you need to access it with far pointers. For example, a putpixel using the bank switching functions is:

   void banked_putpixel(BITMAP *bmp, int x, int y, int color)
   {
      unsigned long address = bmp_write_line(bmp, y);
      bmp_select(bmp);
      bmp_write8(address+x, color);
      bmp_unwrite_line(bmp);
   }
You will notice that Allegro provides separate functions for setting the read and write banks. It is important that you distinguish between these, because on some graphics cards the banks can be set individually, and on others the video memory is read and written at different addresses. Life is never quite as simple as we might wish it to be, though (this is true even when we _aren't_ talking about graphics coding :-) and so of course some cards only provide a single bank. On these the read and write bank functions will behave identically, so you shouldn't assume that you can read from one part of video memory and write to another at the same time. You can call bmp_read_line(), and read whatever you like from that line, and then call bmp_write_line() with the same or a different line number, and write whatever you like to this second line, but you mustn't call bmp_read_line() and bmp_write_line() together and expect to be able to read one line and write the other simultaneously. It would be nice if this was possible, but if you do it, your code won't work on single banked SVGA cards.

And then there's mode-X. If you've never done any mode-X graphics coding, you probably won't understand this, but for those of you who want to know how Allegro sets up the mode-X screen bitmaps, here goes...

The line pointers are still present, and they contain planar addresses, ie. the actual location at which you access the first pixel in the line. These addresses are guaranteed to be quad aligned, so you can just set the write plane, divide your x coordinate by four, and add it to the line pointer. For example, a mode-X putpixel is:

   void modex_putpixel(BITMAP *b, int x, int y, int color)
   {
      outportw(0x3C4, (0x100<<(x&3))|2);
      bmp_select(bmp);
      bmp_write8((unsigned long)bmp->line[y]+(x>>2), color);
   }

Oh yeah: the djgpp nearptr hack. Personally I don't like this very much because it disables memory protection and isn't portable to other platforms, but a lot of people swear by it because it can give you direct access to the screen memory via a normal C pointer. Warning: this method will only work with the djgpp library, when using VGA 13h or a linear framebuffer modes!

In your setup code:

   #include <sys/nearptr.h>

   unsigned char *screenmemory;
   unsigned long screen_base_addr;

   __djgpp_nearptr_enable();

   __dpmi_get_segment_base_address(screen->seg, &screen_base_addr);

   screenmemory = (unsigned char *)(screen_base_addr +
                                    screen->line[0] -
                                    __djgpp_base_address);
Then:

   void nearptr_putpixel(int x, int y, int color)
   {
      screenmemory[x + y*VIRTUAL_W] = color;
   }


FLIC routines

  • close_fli
  • fli_bitmap
  • fli_bmp_dirty_from
  • fli_bmp_dirty_to
  • fli_frame
  • fli_pal_dirty_from
  • fli_pal_dirty_to
  • fli_palette
  • fli_timer
  • next_fli_frame
  • open_fli
  • open_memory_fli
  • play_fli
  • play_memory_fli
  • reset_fli_variables

There are two high level functions for playing FLI/FLC animations: play_fli(), which reads the data directly from disk, and play_memory_fli(), which uses data that has already been loaded into RAM. Apart from the different sources of the data, these two functions behave identically. They draw the animation onto the specified bitmap, which should normally be the screen. Frames will be aligned with the top left corner of the bitmap: if you want to position them somewhere else you will need to create a sub-bitmap for the FLI player to draw onto. If loop is set the player will cycle when it reaches the end of the file, otherwise it will play through the animation once and then return. If the callback function is not NULL it will be called once for each frame, allowing you to perform background tasks of your own. This callback should normally return zero: if it returns non-zero the player will terminate (this is the only way to stop an animation that is playing in looped mode). The FLI player returns FLI_OK if it reached the end of the file, FLI_ERROR if something went wrong, and the value returned by the callback function if that was what stopped it. If you need to distinguish between different return values, your callback should return positive integers, since FLI_OK is zero and FLI_ERROR is negative. Note that the FLI player will only work when the timer module is installed, and that it will alter the palette according to whatever palette data is present in the animation file.

Occasionally you may need more detailed control over how an FLI is played, for example if you want to superimpose a text scroller on top of the animation, or to play it back at a different speed. You could do both of these with the lower level functions described below.

int play_fli(const char *filename, BITMAP *bmp, int loop, int (*callback)());
Plays an Autodesk Animator FLI or FLC animation file, reading the data from disk as it is required.

int play_memory_fli(const void *fli_data, BITMAP *bmp, int loop, int (*callback)());
Plays an Autodesk Animator FLI or FLC animation, reading the data from a copy of the file which is held in memory. You can obtain the fli_data pointer by mallocing a block of memory and reading an FLI file into it, or by importing an FLI into a grabber datafile. Playing animations from memory is obviously faster than cueing them directly from disk, and is particularly useful with short, looped FLI's. Animations can easily get very large, though, so in most cases you will probably be better just using play_fli().

int open_fli(const char *filename);
int open_memory_fli(const void *fli_data);
Open FLI files ready for playing, reading the data from disk or memory respectively. Return FLI_OK on success. Information about the current FLI is held in global variables, so you can only have one animation open at a time.

void close_fli();
Closes an FLI file when you have finished reading from it.

int next_fli_frame(int loop);
Reads the next frame of the current animation file. If loop is set the player will cycle when it reaches the end of the file, otherwise it will return FLI_EOF. Returns FLI_OK on success, FLI_ERROR or FLI_NOT_OPEN on error, and FLI_EOF on reaching the end of the file. The frame is read into the global variables fli_bitmap and fli_palette.

extern BITMAP *fli_bitmap;
Contains the current frame of the FLI/FLC animation.

extern PALETTE fli_palette;
Contains the current FLI palette.

extern int fli_bmp_dirty_from;
extern int fli_bmp_dirty_to;
These variables are set by next_fli_frame() to indicate which part of the fli_bitmap has changed since the last call to reset_fli_variables(). If fli_bmp_dirty_from is greater than fli_bmp_dirty_to, the bitmap has not changed, otherwise lines fli_bmp_dirty_from to fli_bmp_dirty_to (inclusive) have altered. You can use these when copying the fli_bitmap onto the screen, to avoid moving data unnecessarily.

extern int fli_pal_dirty_from;
extern int fli_pal_dirty_to;
These variables are set by next_fli_frame() to indicate which part of the fli_palette has changed since the last call to reset_fli_variables(). If fli_pal_dirty_from is greater than fli_pal_dirty_to, the palette has not changed, otherwise colors fli_pal_dirty_from to fli_pal_dirty_to (inclusive) have altered. You can use these when updating the hardware palette, to avoid unnecessary calls to set_palette().

void reset_fli_variables();
Once you have done whatever you are going to do with the fli_bitmap and fli_palette, call this function to reset the fli_bmp_dirty_* and fli_pal_dirty_* variables.

extern int fli_frame;
Global variable containing the current frame number in the FLI file. This is useful for synchronising other events with the animation, for instance you could check it in a play_fli() callback function and use it to trigger a sample at a particular point.

extern volatile int fli_timer;
Global variable for timing FLI playback. When you open an FLI file, a timer interrupt is installed which increments this variable every time a new frame should be displayed. Calling next_fli_frame() decrements it, so you can test it and know that it is time to display a new frame if it is greater than zero.


Sound init routines

  • detect_digi_driver
  • detect_midi_driver
  • install_sound
  • remove_sound
  • reserve_voices
  • set_volume
  • set_volume_per_voice

int detect_digi_driver(int driver_id);
Detects whether the specified digital sound device is available. Returns the maximum number of voices that the driver can provide, or zero if the hardware is not present. This function must be called _before_ install_sound().

int detect_midi_driver(int driver_id);
Detects whether the specified MIDI sound device is available. Returns the maximum number of voices that the driver can provide, or zero if the hardware is not present. There are two special-case return values that you should watch out for: if this function returns -1 it is a note-stealing driver (eg. DIGMID) that shares voices with the current digital sound driver, and if it returns 0xFFFF it is an external device like an MPU-401 where there is no way to determine how many voices are available. This function must be called _before_ install_sound().

void reserve_voices(int digi_voices, int midi_voices);
Call this function to specify the number of voices that are to be used by the digital and MIDI sound drivers respectively. This must be done _before_ calling install_sound(). If you reserve too many voices, subsequent calls to install_sound() will fail. How many voices are available depends on the driver, and in some cases you will actually get more than you reserve (eg. the FM synth drivers will always provide 9 voices on an OPL2 and 18 on an OPL3, and the SB digital driver will round the number of voices up to the nearest power of two). Pass negative values to restore the default settings. You should be aware that the sound quality is usually inversely related to how many voices you use, so don't reserve any more than you really need.

void set_volume_per_voice(int scale);
By default, when you reserve more voices for the digital sound driver, Allegro will reduce the volume of each voice to compensate. This is done to avoid too much distortion. The default volume per voice is such that, if you reserve n voices, you can play up to n/2 normalised samples with centre panning without risking distortion. The exception is when you have fewer than 8 voices, where the volume remains the same as for 8 voices.

If the resultant output is either too loud or too quiet, this function can be used to adjust the volume of each voice. You should first check that your speakers are at a reasonable volume, Allegro's global volume is at maximum (see set_volume() below), and any other mixers such as the Windows Volume Control are set reasonably.

Once you are sure that Allegro's output level is unsuitable for your application, use this function to adjust it. This must be done _before_ calling install_sound(). Note that this function is currently only relevant for drivers that use the Allegro mixer (which is most of them).

If you pass 0 to this function, each centred sample will play at the maximum volume possible without distortion, as will all samples played through a mono driver. Samples at the extreme left and right will distort if played at full volume. If you wish to play panned samples at full volume without distortion, you should pass 1 to this function. Note: this is different from the function's behaviour in WIPs 3.9.34, 3.9.35 and 3.9.36. If you used this function under one of these WIPs, you will have to increase your parameter by one to get the same volume.

Each time you increase the parameter by one, the volume of each voice will halve. For example, if you pass 4, you can play up to 16 centred samples at maximum volume without distortion.

Here are the default values, dependent on the number of voices:

   1-8 voices - set_volume_per_voice(2)
    16 voices - set_volume_per_voice(3)
    32 voices - set_volume_per_voice(4)
    64 voices - set_volume_per_voice(5)
Of course this function does not override the volume you specify with play_sample() or voice_set_volume(). It simply alters the overall output of the program. If you play samples at lower volumes, or if they are not normalised, then you can play more of them without distortion.

Warning: Allegro uses a clipping table to clip the waveform. The table is big enough to accommodate a total output of up to 4 times the maximum possible without distortion. If your output goes above this limit, the wave will 'wrap around' (peaks become troughs and vice versa), thus distorting much more. You should be careful that this does not happen.

It is recommended that you hard-code the parameter into your program, rather than offering it to the user. The user can alter the volume with the configuration file instead, or you can provide for this with set_volume().

To restore volume per voice to its default behaviour, pass -1.

int install_sound(int digi, int midi, const char *cfg_path);
Initialises the sound module. You should normally pass DIGI_AUTODETECT and MIDI_AUTODETECT as the driver parameters to this function, in which case Allegro will read hardware settings from the current configuration file. This allows the user to select different values with the setup utility: see the config section for details. Alternatively, see the platform specific documentation for a list of the available drivers. The cfg_path parameter is only present for compatibility with previous versions of Allegro, and has no effect on anything. Returns zero if the sound is successfully installed, and -1 on failure. If it fails it will store a description of the problem in allegro_error.

void remove_sound();
Cleans up after you are finished with the sound routines. You don't normally need to call this, because allegro_exit() will do it for you.

void set_volume(int digi_volume, int midi_volume);
Alters the global sound output volume. Specify volumes for both digital samples and MIDI playback, as integers from 0 to 255, or pass a negative value to leave one of the settings unchanged. If possible this routine will use a hardware mixer to control the volume, otherwise it will tell the sample and MIDI players to simulate a mixer in software.


Digital sample routines

  • adjust_sample
  • allocate_voice
  • create_sample
  • deallocate_voice
  • destroy_sample
  • load_sample
  • load_voc
  • load_wav
  • lock_sample
  • play_sample
  • reallocate_voice
  • release_voice
  • stop_sample
  • voice_check
  • voice_get_frequency
  • voice_get_pan
  • voice_get_position
  • voice_get_volume
  • voice_ramp_volume
  • voice_set_echo
  • voice_set_frequency
  • voice_set_pan
  • voice_set_playmode
  • voice_set_position
  • voice_set_priority
  • voice_set_tremolo
  • voice_set_vibrato
  • voice_set_volume
  • voice_start
  • voice_stop
  • voice_stop_frequency_sweep
  • voice_stop_pan_sweep
  • voice_stop_volumeramp
  • voice_sweep_frequency
  • voice_sweep_pan

SAMPLE *load_sample(const char *filename);
Loads a sample from a file, returning a pointer to it, or NULL on error. At present this function supports both mono and stereo WAV and mono VOC files, in 8 or 16 bit formats.

SAMPLE *load_wav(const char *filename);
Loads a sample from a RIFF WAV file.

SAMPLE *load_voc(const char *filename);
Loads a sample from a Creative Labs VOC file.

SAMPLE *create_sample(int bits, int stereo, int freq, int len);
Constructs a new sample structure of the specified type. The data field points to a block of waveform data: see the structure definition in allegro/digi.h for details.

void destroy_sample(SAMPLE *spl);
Destroys a sample structure when you are done with it. It is safe to call this even when the sample might be playing, because it checks and will kill it off if it is active.

void lock_sample(SAMPLE *spl);
Under DOS, locks all the memory used by a sample. You don't normally need to call this function because load_sample() and create_sample() do it for you.

int play_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop);
Triggers a sample at the specified volume, pan position, and frequency. The volume and pan range from 0 (min/left) to 255 (max/right). Frequency is relative rather than absolute: 1000 represents the frequency that the sample was recorded at, 2000 is twice this, etc. If the loop flag is set, the sample will repeat until you call stop_sample(), and can be manipulated while it is playing by calling adjust_sample(). Returns the voice number that was allocated for the sample (a non-negative number if successful).

void adjust_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop);
Alters the parameters of a sample while it is playing (useful for manipulating looped sounds). You can alter the volume, pan, and frequency, and can also clear the loop flag, which will stop the sample when it next reaches the end of its loop. If there are several copies of the same sample playing, this will adjust the first one it comes across. If the sample is not playing it has no effect.

void stop_sample(const SAMPLE *spl);
Kills off a sample, which is required if you have set a sample going in looped mode. If there are several copies of the sample playing, it will stop them all.

If you need more detailed control over how samples are played, you can use the lower level voice functions rather than just calling play_sample(). This is rather more work, because you have to explicitly allocate and free the voices rather than them being automatically released when they finish playing, but allows far more precise specification of exactly how you want everything to sound. You may also want to modify a couple of fields from the sample structure:

   int priority;
      Ranging 0-255 (default 128), this controls how voices are
      allocated if you attempt to play more than the driver can handle.
      This may be used to ensure that the less important sounds are
      cut off while the important ones are preserved.

   unsigned long loop_start;
   unsigned long loop_end;
      Loop position in sample units, by default set to the start and end of
      the sample.
int allocate_voice(const SAMPLE *spl);
Allocates a soundcard voice and prepares it for playing the specified sample, setting up sensible default parameters (maximum volume, centre pan, no change of pitch, no looping). When you are finished with the voice you must free it by calling deallocate_voice() or release_voice(). Returns the voice number, or -1 if no voices are available.

void deallocate_voice(int voice);
Frees a soundcard voice, stopping it from playing and releasing whatever resources it is using.

void reallocate_voice(int voice, const SAMPLE *spl);
Switches an already-allocated voice to use a different sample. Calling reallocate_voice(voice, sample) is equivalent to:

      deallocate_voice(voice);
      voice = allocate_voice(sample);
void release_voice(int voice);
Releases a soundcard voice, indicating that you are no longer interested in manipulating it. The sound will continue to play, and any resources that it is using will automatically be freed when it finishes. This is essentially the same as deallocate_voice(), but it waits for the sound to stop playing before taking effect.

void voice_start(int voice);
Activates a voice, using whatever parameters have been set for it.

void voice_stop(int voice);
Stops a voice, storing the current position and state so that it may later be resumed by calling voice_start().

void voice_set_priority(int voice, int priority);
Sets the priority of a voice (range 0-255). This is used to decide which voices should be chopped off, if you attempt to play more than the soundcard driver can handle.

SAMPLE *voice_check(int voice);
Checks whether a voice is currently allocated. It returns a copy of the sample that the voice is using, or NULL if the voice is inactive (ie. it has been deallocated, or the release_voice() function has been called and the sample has then finished playing).

int voice_get_position(int voice);
Returns the current position of a voice, in sample units, or -1 if it has finished playing.

void voice_set_position(int voice, int position);
Sets the position of a voice, in sample units.

void voice_set_playmode(int voice, int playmode);
Adjusts the loop status of the specified voice. This can be done while the voice is playing, so you can start a sample in looped mode (having set the loop start and end positions to the appropriate values), and then clear the loop flag when you want to end the sound, which will cause it to continue past the loop end, play the subsequent part of the sample, and finish in the normal way. The mode parameter is a bitfield containing the following values:

  • PLAYMODE_PLAY
    Plays the sample a single time. This is the default if you don't set the loop flag.

  • PLAYMODE_LOOP
    Loops repeatedly through the sample, jumping back to the loop start position upon reaching the loop end.

  • PLAYMODE_FORWARD
    Plays the sample from beginning to end. This is the default if you don't set the backward flag.

  • PLAYMODE_BACKWARD
    Reverses the direction of the sample. If you combine this with the loop flag, the sample jumps to the loop end position upon reaching the loop start (ie. you do not need to reverse the loop start and end values when you play the sample in reverse).

  • PLAYMODE_BIDIR
    When used in combination with the loop flag, causes the sample to change direction each time it reaches one of the loop points, so it alternates between playing forwards and in reverse.

int voice_get_volume(int voice);
Returns the current volume of the voice, range 0-255.

void voice_set_volume(int voice, int volume);
Sets the volume of the voice, range 0-255.

void voice_ramp_volume(int voice, int time, int endvol);
Starts a volume ramp (crescendo or diminuendo) from the current volume to the specified ending volume, lasting for time milliseconds.

void voice_stop_volumeramp(int voice);
Interrupts a volume ramp operation.

int voice_get_frequency(int voice);
Returns the current pitch of the voice, in Hz.

void voice_set_frequency(int voice, int frequency);
Sets the pitch of the voice, in Hz.

void voice_sweep_frequency(int voice, int time, int endfreq);
Starts a frequency sweep (glissando) from the current pitch to the specified ending pitch, lasting for time milliseconds.

void voice_stop_frequency_sweep(int voice);
Interrupts a frequency sweep operation.

int voice_get_pan(int voice);
Returns the current pan position, from 0 (left) to 255 (right).

void voice_set_pan(int voice, int pan);
Sets the pan position, ranging from 0 (left) to 255 (right).

void voice_sweep_pan(int voice, int time, int endpan);
Starts a pan sweep (left <-> right movement) from the current position to the specified ending position, lasting for time milliseconds.

void voice_stop_pan_sweep(int voice);
Interrupts a pan sweep operation.

void voice_set_echo(int voice, int strength, int delay);
Sets the echo parameters for a voice (not currently implemented).

void voice_set_tremolo(int voice, int rate, int depth);
Sets the tremolo parameters for a voice (not currently implemented).

void voice_set_vibrato(int voice, int rate, int depth);
Sets the vibrato parameters for a voice (not currently implemented).


MIDI music routines

  • destroy_midi
  • load_ibk
  • load_midi
  • load_midi_patches
  • lock_midi
  • midi_loop_end
  • midi_loop_start
  • midi_meta_callback
  • midi_msg_callback
  • midi_out
  • midi_pause
  • midi_pos
  • midi_resume
  • midi_seek
  • midi_sysex_callback
  • play_looped_midi
  • play_midi
  • stop_midi

MIDI *load_midi(const char *filename);
Loads a MIDI file (handles both format 0 and format 1), returning a pointer to a MIDI structure, or NULL on error.

void destroy_midi(MIDI *midi);
Destroys a MIDI structure when you are done with it. It is safe to call this even when the MIDI file might be playing, because it checks and will kill it off if it is active.

void lock_midi(MIDI *midi);
Under DOS, locks all the memory used by a MIDI file. You don't normally need to call this function because load_midi() does it for you.

int play_midi(MIDI *midi, int loop);
Starts playing the specified MIDI file, first stopping whatever music was previously playing. If the loop flag is set, the data will be repeated until replaced with something else, otherwise it will stop at the end of the file. Passing a NULL pointer will stop whatever music is currently playing. Returns non-zero if an error occurs (this may happen if a patch-caching wavetable driver is unable to load the required samples, or at least it might in the future when somebody writes some patch-caching wavetable drivers :-)

int play_looped_midi(MIDI *midi, int loop_start, int loop_end);
Starts playing a MIDI file with a user-defined loop position. When the player reaches the loop end position or the end of the file (loop_end may be -1 to only loop at EOF), it will wind back to the loop start point. Both positions are specified in the same beat number format as the midi_pos variable.

void stop_midi();
Stops whatever music is currently playing. This is the same thing as calling play_midi(NULL, FALSE).

void midi_pause();
Pauses the MIDI player.

void midi_resume();
Resumes playback of a paused MIDI file.

int midi_seek(int target);
Seeks to the given midi_pos in the current MIDI file. If the target is earlier in the file than the current midi_pos it seeks from the beginning; otherwise it seeks from the current position. Returns zero if it could successfully seek to the requested position. Otherwise, a return value of 1 means it stopped playing, and midi_pos is set to the negative length of the MIDI file (so you can use this function to determine the length of a MIDI file). A return value of 2 means the MIDI file looped back to the start.

void midi_out(unsigned char *data, int length);
Streams a block of MIDI commands into the player in realtime, allowing you to trigger notes, jingles, etc, over the top of whatever MIDI file is currently playing.

int load_midi_patches();
Forces the MIDI driver to load the entire set of patches ready for use. You will not normally need to call this, because Allegro automatically loads whatever data is required for the current MIDI file, but you must call it before sending any program change messages via the midi_out() command. Returns non-zero if an error occurred.

extern volatile long midi_pos;
Stores the current position (beat number) in the MIDI file, or contains a negative number if no music is currently playing. Useful for synchronising animations with the music, and for checking whether a MIDI file has finished playing.

extern long midi_loop_start;
extern long midi_loop_end;
The loop start and end points, set by the play_looped_midi() function. These may safely be altered while the music is playing, but you should be sure they are always set to sensible values (start < end). If you are changing them both at the same time, make sure to alter them in the right order in case a MIDI interrupt happens to occur in between your two writes! Setting these values to -1 represents the start and end of the file respectively.

extern void (*midi_msg_callback)(int msg, int byte1, int byte2);
extern void (*midi_meta_callback)(int type, const unsigned char *data, int length);
extern void (*midi_sysex_callback)(const unsigned char *data, int length);
Hook functions allowing you to intercept MIDI player events. If set to anything other than NULL, these routines will be called for each MIDI message, meta-event, and system exclusive data block respectively. They will execute in an interrupt handler context, so all the code and data they use should be locked, and they must not call any operating system functions. In general you just use these routines to set some flags and respond to them later in your mainline code.

int load_ibk(char *filename, int drums);
Reads in a .IBK patch definition file for use by the Adlib driver. If drums is set, it will load it as a percussion patch set, otherwise it will use it as a replacement set of General MIDI instruments. You may call this before or after initialising the sound code, or can simply set the ibk_file and ibk_drum_file variables in the configuration file to have the data loaded automatically. Note that this function has no effect on any drivers other than the Adlib one! Returns non-zero on error.


Audio stream routines

  • free_audio_stream_buffer
  • get_audio_stream_buffer
  • play_audio_stream
  • stop_audio_stream

The audio stream functions are for playing digital sounds that are too big to fit in a regular SAMPLE structure, either because they are huge files that you want to load in pieces as the data is required, or because you are doing something clever like generating the waveform on the fly.

AUDIOSTREAM *play_audio_stream(int len, bits, stereo, freq, vol, pan);
This function creates a new audio stream and starts it playing. The length is the size of each transfer buffer (in samples), which should normally (but doesn't have to) be a power of two somewhere around 1k in size. Larger buffers are more efficient and require fewer updates, but result in more latency between you providing the data and it actually being played. The bits parameter must be 8 or 16, freq is the sample rate of the data in Hertz. The vol and pan values use the same 0-255 ranges as the regular sample playing functions. The stereo parameter should be set to 1 for stereo streams, or 0 otherwise. If you want to adjust the pitch, volume, or panning of a stream once it is playing, you can use the regular voice_*() functions with stream->voice as a parameter. The sample data is always in unsigned format, with stereo waveforms consisting of alternating left/right samples, left sample first.

void stop_audio_stream(AUDIOSTREAM *stream);
Destroys an audio stream when it is no longer required.

void *get_audio_stream_buffer(AUDIOSTREAM *stream);
You must call this function at regular intervals while an audio stream is playing, to provide the next buffer of sample data (the smaller the stream buffer size, the more often it must be called). If it returns NULL, the stream is still playing the previous lot of data, so you don't need to do anything. If it returns a value, that is the location of the next buffer to be played, and you should load the appropriate number of samples (however many you specified when creating the stream) to that address, for example using an fread() from a disk file. After filling the buffer with data, call free_audio_stream_buffer() to indicate that the new data is now valid. Note that this function should not be called from a timer handler...

void free_audio_stream_buffer(AUDIOSTREAM *stream);
Call this function after get_audio_stream_buffer() returns a non-NULL address, to indicate that you have loaded a new block of samples to that location and the data is now ready to be played.


Recording routines

  • digi_recorder
  • get_sound_input_cap_bits
  • get_sound_input_cap_parm
  • get_sound_input_cap_rate
  • get_sound_input_cap_stereo
  • install_sound_input
  • midi_recorder
  • read_sound_input
  • remove_sound_input
  • set_sound_input_source
  • start_sound_input
  • stop_sound_input

int install_sound_input(int digi, int midi);
Initialises the sound recorder module, returning zero on success. You must install the normal sound playback system before calling this routine. The two card parameters should use the same constants as install_sound(), including DIGI_NONE and MIDI_NONE to disable parts of the module, or DIGI_AUTODETECT and MIDI_AUTODETECT to guess the hardware.

void remove_sound_input();
Cleans up after you are finished with the sound input routines. You don't normally need to call this, because remove_sound() and/or allegro_exit() will do it for you.

int get_sound_input_cap_bits();
Checks which sample formats are supported by the current audio input driver, returning one of the bitfield values:

0 = audio input not supported
8 = eight bit audio input is supported
16 = sixteen bit audio input is supported
24 = both eight and sixteen bit audio input are supported

int get_sound_input_cap_stereo();
Checks whether the current audio input driver is capable of stereo recording.

int get_sound_input_cap_rate(int bits, int stereo);
Returns the maximum possible sample frequency for recording in the specified format, or zero if these settings are not supported.

int get_sound_input_cap_parm(int rate, int bits, int stereo);
Checks whether the specified recording frequency, number of bits, and mono/stereo mode are supported by the current audio driver, returning one of the values:

0 = it is impossible to record in this format
1 = recording is possible, but audio output will be suspended
2 = recording is possible at the same time as playing other sounds
-n = sampling rate not supported, but rate 'n' would work instead

int set_sound_input_source(int source);
Selects the audio input source, returning zero on success or -1 if the hardware does not provide an input select register. The parameter should be one of the values:

SOUND_INPUT_MIC
SOUND_INPUT_LINE
SOUND_INPUT_CD

int start_sound_input(int rate, int bits, int stereo);
Starts recording in the specified format, suspending audio playback as necessary (this will always happen with the current drivers). Returns the buffer size in bytes if successful, or zero on error.

void stop_sound_input();
Stops audio recording, switching the card back into the normal playback mode.

int read_sound_input(void *buffer);
Retrieves the most recently recorded audio buffer into the specified location, returning non-zero if a buffer has been copied or zero if no new data is yet available. The buffer size can be obtained by checking the return value from start_sound_input(). You must be sure to call this function at regular intervals during the recording (typically around 100 times a second), or some data will be lost. If you are unable to do this often enough from the mainline code, use the digi_recorder() callback to store the waveform into a larger buffer of your own. Note: many cards produce a click or popping sound when switching between record and playback modes, so it is often a good idea to discard the first buffer after you start a recording. The waveform is always stored in unsigned format, with stereo data consisting of alternate left/right samples.

extern void (*digi_recorder)();
If set, this function is called by the input driver whenever a new sample buffer becomes available, at which point you can use read_sound_input() to copy the data into a more permenent location. This routine runs in an interrupt context, so it must execute very quickly, the code and all memory that it touches must be locked, and you cannot call any operating system routines or access disk files.

extern void (*midi_recorder)(unsigned char data);
If set, this function is called by the MIDI input driver whenever a new byte of MIDI data becomes available. It runs in an interrupt context, so it must execute very quickly and all the code/data must be locked.


File and compression routines

  • al_findclose
  • al_findfirst
  • al_findnext
  • append_filename
  • delete_file
  • exists
  • file_exists
  • file_size
  • file_time
  • find_allegro_resource
  • fix_filename_case
  • fix_filename_path
  • fix_filename_slashes
  • for_each_file
  • get_executable_name
  • get_extension
  • get_filename
  • pack_fclose
  • pack_fclose_chunk
  • pack_feof
  • pack_ferror
  • pack_fgets
  • pack_fopen
  • pack_fopen_chunk
  • pack_fputs
  • pack_fread
  • pack_fseek
  • pack_fwrite
  • pack_getc
  • pack_igetl
  • pack_igetw
  • pack_iputl
  • pack_iputw
  • pack_mgetl
  • pack_mgetw
  • pack_mputl
  • pack_mputw
  • pack_putc
  • packfile_password
  • put_backslash
  • replace_extension
  • replace_filename

The following routines implement a fast buffered file I/O system, which supports the reading and writing of compressed files using a ring buffer algorithm based on the LZSS compressor by Haruhiko Okumura. This does not achieve quite such good compression as programs like zip and lha, but unpacking is very fast and it does not require much memory. Packed files always begin with the 32 bit value F_PACK_MAGIC, and autodetect files with the value F_NOPACK_MAGIC.

The following FA_* flags are guaranteed to work: FA_RDONLY, FA_HIDDEN, FA_SYSTEM, FA_LABEL, FA_DIREC, FA_ARCH. Do not use any other flags from DOS/Windows or your code will not compile on another platform. Flags FA_SYSTEM, FA_LABEL and FA_ARCH are valuable only on DOS/Windows (entries with system flag, volume labels and archive flag). FA_RDONLY is for directory entries with read-only flag on DOS-like systems or unwritable by current user on Unix-like systems. FA_HIDDEN is for entries with hidden flag on DOS-like systems or starting with '.' on Unix (dotted files - excluding '.' and '..'). FA_DIREC represents directories. Flags can be combined using '|' (binary OR operator).

When passed to the functions as the 'attrib' parameter, these flags represent an upper set in which the actual flag set of a matching file must be included. That is, in order for a file to be matching, its attributes may contain any of the specified flags but must not contain any of the unspecified flags. Thus, if you pass 'FA_DIREC | FA_RDONLY', normal files and directories will be included as well as read-only files and directories, but not hidden files and directories. Similarly, if you pass 'FA_ARCH' then both archived and non-archived files will be included.

void get_executable_name(char *buf, int size);
Fills buf with the full path to the current executable, writing at most size bytes. This generally comes from argv[0], but on Unix systems if argv[0] does not specify the path, we search for our file in $PATH.

char *fix_filename_case(char *path);
Converts a filename to a standardised case. On DOS platforms, they will be entirely uppercase. Returns a copy of the path parameter.

char *fix_filename_slashes(char *path);
Converts all the directory separators in a filename to a standard character. On DOS platforms, this is a backslash. Returns a copy of the path parameter.

char *fix_filename_path(char *dest, const char *path, int size);
Converts a partial filename into a full path, storing at most size bytes into the dest buffer. Returns a copy of the dest parameter.

char *replace_filename(char *dest, const char *path, const char *filename, int size);
Replaces the specified path+filename with a new filename tail, storing at most size bytes into the dest buffer. Returns a copy of the dest parameter.

char *replace_extension(char *dest, const char *filename, const char *ext, int size);
Replaces the specified filename+extension with a new extension tail, storing at most size bytes into the dest buffer. Returns a copy of the dest parameter.

char *append_filename(char *dest, const char *path, const char *filename, int size);
Concatenates the specified filename onto the end of the specified path, storing at most size bytes into the dest buffer. Returns a copy of the dest parameter.

char *get_filename(const char *path);
When passed a completely specified file path, this returns a pointer to the filename portion. Both '\' and '/' are recognized as directory separators.

char *get_extension(const char *filename);
When passed a complete filename (with or without path information) this returns a pointer to the file extension.

void put_backslash(char *filename);
If the last character of the filename is not a '\', '/', '#' or a device separator (ie. ':' under DOS), this routine will concatenate either a '\' or '/' on to it (depending on the platform). Note: ignore the function name, it's out of date.

int file_exists(const char *filename, int attrib, int *aret);
Checks whether a file matching the given name and attributes (see above) exists, returning non-zero if it does. If aret is not NULL, it will be set to the attributes of the matching file. If an error occurs the system error code will be stored in errno.

int exists(const char *filename);
Shortcut version of file_exists(), which checks for normal files, which may have the archive or read-only bits set, but are not hidden, directories, system files, etc.

long file_size(const char *filename);
Returns the size of a file, in bytes. If the file does not exist or an error occurs, it will return zero and store the system error code in errno.

time_t file_time(const char *filename);
Returns the modification time (number of seconds since 00:00:00 GMT 1/1/1970) of a file. If the file does not exist or an error occurs, it will return zero and store the system error code in errno.

int delete_file(const char *filename);
Removes a file from the disk.

int for_each_file(const char *name, int attrib, void (*callback)(const char *filename, int attrib, int param), int param);
Finds all the files on the disk which match the given wildcard specification and file attributes (see above), and executes callback() once for each. callback() will be passed three arguments, the first a string which contains the completed filename, the second being the attributes of the file, and the third an int which is simply a copy of param (you can use this for whatever you like). If an error occurs an error code will be stored in errno, and callback() can cause for_each_file() to abort by setting errno itself. Returns the number of successful calls made to callback().

int al_findfirst(const char *pattern, struct al_ffblk *info, int attrib);
Low-level function for searching files. This function finds the first file which matches the given wildcard specification and file attributes (see above). The information about the file (if any) will be put in the al_ffblk structure which you have to provide. The function returns zero if a match is found, nonzero if none is found or if an error occured and, in the latter case, sets errno accordingly. The al_ffblk structure looks like:

  struct al_ffblk
  {
      int attrib;       - actual attributes of the file found
      time_t time;      - modification time of file
      long size;        - size of file
      char name[512];   - name of file
  };
There is some other stuff in the structure as well, but it is there for internal use only.

int al_findnext(struct al_ffblk *info);
This finds the next file in a search started by al_findfirst(). Returns zero if a match is found, nonzero if none is found or if an error occured and, in the latter case, sets errno accordingly.

void al_findclose(struct al_ffblk *info);
This closes a previously opened search with al_findfirst().

int find_allegro_resource(char *dest, const char *resource, const char *ext, const char *datafile, const char *objectname, const char *envvar, const char *subdir, int size);
Searches for a support file, eg. allegro.cfg or language.dat. Passed a resource string describing what you are looking for, along with extra optional information such as the default extension, what datafile to look inside, what the datafile object name is likely to be, any special environment variable to check, and any subdirectory that you would like to check as well as the default location, this function looks in a hell of a lot of different places :-) Returns zero on success, and stores a full path to the file (at most size bytes) into the dest buffer.

void packfile_password(const char *password);
Sets the encryption password to be used for all read/write operations on files opened in future using Allegro's packfile functions (whether they are compressed or not), including all the save, load and config routines. Files written with an encryption password cannot be read unless the same password is selected, so be careful: if you forget the key, I can't make your data come back again! Pass NULL or an empty string to return to the normal, non-encrypted mode. If you are using this function to prevent people getting access to your datafiles, be careful not to store an obvious copy of the password in your executable: if there are any strings like "I'm the password for the datafile", it would be fairly easy to get access to your data :-)

Note #1: when writing a packfile, you can change the password to whatever you want after opening the file, without affecting the write operation. On the contrary, when writing a sub-chunk of a packfile, you must make sure that the password that was active at the time the sub-chunk was opened is still active before closing the sub-chunk. This is guaranteed to be true if you didn't call the packfile_password() routine in the meantime. Read operations, either on packfiles or sub-chunks, have no such restriction.

Note #2: as explained above, the password is used for all read/write operations on files, including for several functions of the library that operate on files without explicitly using packfiles, e.g load_bitmap(). The unencrypted mode is mandatory in order for those functions to work. Therefore remember to call packfile_password(NULL) before using them if you previously changed the password. As a rule of thumb, always call packfile_password(NULL) when you are done with operations on packfiles.

PACKFILE *pack_fopen(const char *filename, const char *mode);
Opens a file according to mode, which may contain any of the flags:

  • 'r' - open file for reading.

  • 'w' - open file for writing, overwriting any existing data.

  • 'p' - open file in packed mode. Data will be compressed as it is written to the file, and automatically uncompressed during read operations. Files created in this mode will produce garbage if they are read without this flag being set.

  • '!' - open file for writing in normal, unpacked mode, but add the value F_NOPACK_MAGIC to the start of the file, so that it can later be opened in packed mode and Allegro will automatically detect that the data does not need to be decompressed.

Instead of these flags, one of the constants F_READ, F_WRITE, F_READ_PACKED, F_WRITE_PACKED or F_WRITE_NOPACK may be used as the mode parameter. On success, pack_fopen() returns a pointer to a file structure, and on error it returns NULL and stores an error code in errno. An attempt to read a normal file in packed mode will cause errno to be set to EDOM.

The packfile functions also understand several "magic" filenames that are used for special purposes. These are:

  • "#" - read data that has been appended to your executable file with the exedat utility, as if it was a regular independent disk file.

  • 'filename.dat#object_name' - open a specific object from a datafile, and read from it as if it was a regular file. You can treat nested datafiles exactly like a normal directory structure, for example you could open 'filename.dat#graphics/level1/mapdata'.

  • '#object_name' - combination of the above, reading an object from a datafile that has been appended onto your executable.

With these special filenames, the contents of a datafile object or appended file can be read in an identical way to a normal disk file, so any of the file access functions in Allegro (eg. load_pcx() and set_config_file()) can be used to read from them. Note that you can't write to these special files, though: the fake file is read only. Also, you must save your datafile uncompressed or with per-object compression if you are planning on loading individual objects from it (otherwise there will be an excessive amount of seeking when it is read). Finally, be aware that the special Allegro object types aren't the same format as the files you import the data from. When you import data like bitmaps or samples into the grabber, they are converted into a special Allegro-specific format, but the '#' marker file syntax reads the objects as raw binary chunks. This means that if, for example, you want to use load_pcx to read an image from a datafile, you should import it as a binary block rather than as a BITMAP object.

int pack_fclose(PACKFILE *f);
int pack_fseek(PACKFILE *f, int offset);
int pack_feof(PACKFILE *f);
int pack_ferror(PACKFILE *f);
int pack_getc(PACKFILE *f);
int pack_putc(int c, PACKFILE *f);
int pack_igetw(PACKFILE *f);
long pack_igetl(PACKFILE *f);
int pack_iputw(int w, PACKFILE *f);
long pack_iputl(long l, PACKFILE *f);
int pack_mgetw(PACKFILE *f);
long pack_mgetl(PACKFILE *f);
int pack_mputw(int w, PACKFILE *f);
long pack_mputl(long l, PACKFILE *f);
long pack_fread(void *p, long n, PACKFILE *f);
long pack_fwrite(const void *p, long n, PACKFILE *f);
char *pack_fgets(char *p, int max, PACKFILE *f);
int pack_fputs(const char *p, PACKFILE *f);

These work like the equivalent stdio functions. There are some differences, however:

  • Seeking only supports forward movement relative to the current position. Note that seeking is very slow when reading compressed files, and so should be avoided unless you are sure that the file is not compressed.

  • The pack_i* and pack_m* routines read and write 16 and 32 bit values using the Intel and Motorola byte ordering systems (endianness) respectively. Intel is least significant byte first (little-endian); Motorola is most significant byte first (big-endian).

  • pack_fread() and pack_fwrite() take a single size parameter instead of that silly size and num_elements system.

  • The pack_fgets() function does not include a trailing carriage return in the returned string.

  • pack_fputs() always writes in the UTF-8 text encoding format, converting from the current text encoding. Newlines (\n) are written as \r\n on DOS/Windows. If you do not want either of these things to happen, use pack_fwrite() and/or pack_putc() instead.

  • pack_feof() returns nonzero as soon as you reach the end of the file. It does not wait for you to attempt to read beyond the end of the file, contrary to the ISO C feof() function. The only way to know whether you have read beyond the end of the file is to check the return value of the read operation you use (and be wary of pack_*getl() as EOF is also a valid return value with these functions).

PACKFILE *pack_fopen_chunk(PACKFILE *f, int pack);
Opens a sub-chunk of a file. Chunks are primarily intended for use by the datafile code, but they may also be useful for your own file routines. A chunk provides a logical view of part of a file, which can be compressed as an individual entity and will automatically insert and check length counts to prevent reading past the end of the chunk. To write a chunk to the file f, use the code:

      /* assumes f is a PACKFILE * which has been opened */
      f = pack_fopen_chunk(f, pack);    /* in write mode */
      write some data to f
      f = pack_fclose_chunk(f);
The data written to the chunk will be prefixed with two length counts (32 bit, big-endian). For uncompressed chunks these will both be set to the size of the data in the chunk. For compressed chunks (created by setting the pack flag), the first length will be the raw size of the chunk, and the second will be the negative size of the uncompressed data.

To read the chunk, use the code:

      /* assumes f is a PACKFILE * which has been opened */
      f = pack_fopen_chunk(f, FALSE);    */ in read mode */
      read data from f
      f = pack_fclose_chunk(f);
This sequence will read the length counts created when the chunk was written, and automatically decompress the contents of the chunk if it was compressed. The length will also be used to prevent reading past the end of the chunk (Allegro will return EOF if you attempt this), and to automatically skip past any unread chunk data when you call pack_fclose_chunk().

Chunks can be nested inside each other by making repeated calls to pack_fopen_chunk(). When writing a file, the compression status is inherited from the parent file, so you only need to set the pack flag if the parent is not compressed but you want to pack the chunk data. If the parent file is already open in packed mode, setting the pack flag will result in data being compressed twice: once as it is written to the chunk, and again as the chunk passes it on to the parent file.

PACKFILE *pack_fclose_chunk(PACKFILE *f);
Closes a sub-chunk of a file, previously obtained by calling pack_fopen_chunk().


Datafile routines

  • find_datafile_object
  • fixup_datafile
  • get_datafile_property
  • load_datafile
  • load_datafile_callback
  • load_datafile_object
  • register_datafile_object
  • unload_datafile
  • unload_datafile_object

Datafiles are created by the grabber utility, and have a .dat extension. They can contain bitmaps, palettes, fonts, samples, MIDI music, FLI/FLC animations, and any other binary data that you import.

Warning: when using truecolor images, you should always set the graphics mode before loading any bitmap data! Otherwise the pixel format (RGB or BGR) will not be known, so the file may be converted wrongly.

See the documentation for pack_fopen() for information about how to read directly from a specific datafile object.

DATAFILE *load_datafile(const char *filename);
Loads a datafile into memory, and returns a pointer to it, or NULL on error. If the datafile has been encrypted, you must first use the packfile_password() function to set the appropriate key. See grabber.txt for more information. If the datafile contains truecolor graphics, you must set the video mode or call set_color_conversion() before loading it.

DATAFILE *load_datafile_callback(const char *filename, void (*callback)(DATAFILE *d));
Loads a datafile into memory, calling the specified hook function once for each object in the file, passing it a pointer to the object just read.

void unload_datafile(DATAFILE *dat);
Frees all the objects in a datafile.

DATAFILE *load_datafile_object(const char *filename, const char *objectname);
Loads a specific object from a datafile. This won't work if you strip the object names from the file, and it will be very slow if you save the file with global compression. See grabber.txt for more information.

void unload_datafile_object(DATAFILE *dat);
Frees an object previously loaded by load_datafile_object().

DATAFILE *find_datafile_object(const DATAFILE *dat, const char *objectname);
Searches an already loaded datafile for an object with the specified name, returning a pointer to it, or NULL if the object cannot be found. It understands '/' and '#' separators for nested datafile paths.

const char *get_datafile_property(const DATAFILE *dat, int type);
Returns the specified property string for the object, or an empty string if the property isn't present. See grabber.txt for more information.

void register_datafile_object(int id, void *(*load)(PACKFILE *f, long size), void (*destroy)(void *data));
Used to add custom object types, specifying functions to load and destroy objects of this type. See grabber.txt for more information.

void fixup_datafile(DATAFILE *data);
If you are using compiled datafiles (produced by the dat2s utility) on a platform that doesn't support constructors, or on a platform that does support constructors and the datafiles contain truecolor images, you must call this function once after your set the video mode that you will be using. This will ensure the datafiles are properly initialised in the first case and convert the color values into the appropriate format in the second case. It handles flipping between RGB and BGR formats, and converting between different color depths whenever that can be done without changing the size of the image (ie. changing between 15<->16 bit hicolor for both bitmaps and RLE sprites, and 24<->32 bit truecolor for RLE sprites).

When you load a datafile, you will obtain a pointer to an array of DATAFILE structures:

typedef struct DATAFILE
{
   void *dat;     - pointer to the actual data
   int type;      - type of the data
   long size;     - size of the data in bytes
   void *prop;    - list of object properties
} DATAFILE;
The type field will be one of the values:
   DAT_FILE       - dat points to a nested datafile
   DAT_DATA       - dat points to a block of binary data
   DAT_FONT       - dat points to a font object
   DAT_SAMPLE     - dat points to a sample structure
   DAT_MIDI       - dat points to a MIDI file
   DAT_PATCH      - dat points to a GUS patch file
   DAT_FLI        - dat points to an FLI/FLC animation
   DAT_BITMAP     - dat points to a BITMAP structure
   DAT_RLE_SPRITE - dat points to a RLE_SPRITE structure
   DAT_C_SPRITE   - dat points to a linear compiled sprite
   DAT_XC_SPRITE  - dat points to a mode-X compiled sprite
   DAT_PALETTE    - dat points to an array of 256 RGB structures
   DAT_END        - special flag to mark the end of the data list
The grabber program can also produce a header file defining the index of each object within the file as a series of #defined constants, using the names you gave the objects in the grabber. So, for example, if you have made a datafile called foo.dat which contains a bitmap called THE_IMAGE, you could display it with the code fragment:

   #include "foo.h"

   DATAFILE *data = load_datafile("foo.dat");
   draw_sprite(screen, data[THE_IMAGE].dat, x, y);
If you are programming in C++ you will get an error because the dat field is a void pointer and draw_sprite() expects a BITMAP pointer. You can get around this with a cast, eg:

   draw_sprite(screen, (BITMAP *)data[THE_IMAGE].dat, x, y);
When you load a single datafile object, you will obtain a pointer to a single DATAFILE structure. This means that you don't access it any more like an array, and it doesn't have any DAT_END object. Example:

   music_object = load_datafile_object("datafile.dat", "MUSIC");
   play_midi(music_object->dat);


Fixed point math routines

  • fixacos
  • fixadd
  • fixasin
  • fixatan
  • fixatan2
  • fixceil
  • fixcos
  • fixdiv
  • fixfloor
  • fixhypot
  • fixmul
  • fixsin
  • fixsqrt
  • fixsub
  • fixtan
  • fixtof
  • fixtoi
  • ftofix
  • itofix

Allegro provides some routines for working with fixed point numbers, and defines the type 'fixed' to be a signed 32 bit integer. The high word is used for the integer part and the low word for the fraction, giving a range of -32768 to 32767 and an accuracy of about four or five decimal places. Fixed point numbers can be assigned, compared, added, subtracted, negated and shifted (for multiplying or dividing by powers of two) using the normal integer operators, but you should take care to use the appropriate conversion routines when mixing fixed point with integer or floating point values. Writing 'fixed_point_1 + fixed_point_2' is ok, but 'fixed_point + integer' is not.

fixed itofix(int x);
Converts an integer to fixed point. This is the same thing as x<<16.

int fixtoi(fixed x);
Converts fixed point to integer, rounding as required.

int fixfloor(fixed x);
Returns the greatest integer not greater than x. That is, it rounds towards negative infinity.

int fixceil(fixed x);
Returns the smallest integer not less than x. That is, it rounds towards positive infinity.

fixed ftofix(double x);
Converts a floating point value to fixed point.

double fixtof(fixed x);
Converts fixed point to floating point.

fixed fixmul(fixed x, fixed y);
A fixed point value can be multiplied or divided by an integer with the normal '*' and '/' operators. To multiply two fixed point values, though, you must use this function.

If an overflow or division by zero occurs, errno will be set and the maximum possible value will be returned, but errno is not cleared if the operation is successful. This means that if you are going to test for overflow you should set errno=0 before calling fixmul().

fixed fixdiv(fixed x, fixed y);
Fixed point division: see comments about fixmul().

fixed fixadd(fixed x, fixed y);
Although fixed point numbers can be added with the normal '+' integer operator, that doesn't provide any protection against overflow. If overflow is a problem, you should use this function instead. It is slower than using integer operators, but if an overflow occurs it will clamp the result, rather than just letting it wrap, and set errno.

fixed fixsub(fixed x, fixed y);
Fixed point subtraction: see comments about fixadd().

The fixed point square root, sin, cos, tan, inverse sin, and inverse cos functions are implemented using lookup tables, which are very fast but not particularly accurate. At the moment the inverse tan uses an iterative search on the tan table, so it is a lot slower than the others.

Angles are represented in a binary format with 256 equal to a full circle, 64 being a right angle and so on. This has the advantage that a simple bitwise 'and' can be used to keep the angle within the range zero to a full circle, eliminating all those tiresome 'if (angle >= 360)' checks.

fixed fixsin(fixed x);
Lookup table sine.

fixed fixcos(fixed x);
Lookup table cosine.

fixed fixtan(fixed x);
Lookup table tangent.

fixed fixasin(fixed x);
Lookup table inverse sine.

fixed fixacos(fixed x);
Lookup table inverse cosine.

fixed fixatan(fixed x);
Fixed point inverse tangent.

fixed fixatan2(fixed y, fixed x);
Fixed point version of the libc atan2() routine.

fixed fixsqrt(fixed x);
Fixed point square root.

fixed fixhypot(fixed x, fixed y);
Fixed point hypotenuse (returns the square root of x*x + y*y).

If you are programming in C++ you can ignore all the above and use the fix class instead, which overloads a lot of operators to provide automatic conversion to and from integer and floating point values, and calls the above routines as they are required. You should not mix the fix class with the fixed typedef though, because the compiler will mistake the fixed values for regular integers and insert unnecessary conversions. For example, if x is an object of class fix, calling fixsqrt(x) will return the wrong result. You should use the overloaded sqrt(x) or x.sqrt() instead.

The fixed point functions used to be named with an "f" prefix instead of "fix", eg. fixsqrt() used to be fsqrt(), but were renamed due to conflicts with some libc implementations. This should not affect most existing code as there are backwards compatibility aliases. These aliases are static inline functions which map the old names to the new names, eg. fsqrt() calls fixsqrt(). You can disable the aliases by defining the preprocessor macro ALLEGRO_NO_FIX_ALIASES before including allegro.h.


3D math routines

  • apply_matrix
  • apply_matrix_f
  • cross_product
  • cross_product_f
  • dot_product
  • dot_product_f
  • get_align_matrix
  • get_align_matrix_f
  • get_camera_matrix
  • get_camera_matrix_f
  • get_rotation_matrix
  • get_rotation_matrix_f
  • get_scaling_matrix
  • get_scaling_matrix_f
  • get_transformation_matrix
  • get_transformation_matrix_f
  • get_translation_matrix
  • get_translation_matrix_f
  • get_vector_rotation_matrix
  • get_vector_rotation_matrix_f
  • get_x_rotate_matrix
  • get_x_rotate_matrix_f
  • get_y_rotate_matrix
  • get_y_rotate_matrix_f
  • get_z_rotate_matrix
  • get_z_rotate_matrix_f
  • identity_matrix
  • identity_matrix_f
  • matrix_mul
  • matrix_mul_f
  • normalize_vector
  • normalize_vector_f
  • persp_project
  • persp_project_f
  • polygon_z_normal
  • polygon_z_normal_f
  • qscale_matrix
  • qscale_matrix_f
  • qtranslate_matrix
  • qtranslate_matrix_f
  • set_projection_viewport
  • vector_length
  • vector_length_f

Allegro contains some 3d helper functions for manipulating vectors, constructing and using transformation matrices, and doing perspective projections from 3d space onto the screen. It is not, and never will be, a fully fledged 3d library (my goal is to supply generic support routines, not shrink-wrapped graphics code :-) but these functions may be useful for developing your own 3d code.

Allegro uses a right-handed coordinate system, i.e. if you point the thumb of your right hand along the x axis, and the index finger along the y axis, your middle finger points in the direction of the z axis. This also means, for any rotation, if you point the thumb of your right hand along the axis of rotation, then the fingers curl in the positive direction of rotation.

All the 3d math functions are available in two versions: one which uses fixed point arithmetic, and another which uses floating point. The syntax for these is identical, but the floating point functions and structures are postfixed with '_f', eg. the fixed point function cross_product() has a floating point equivalent cross_product_f(). If you are programming in C++, Allegro also overloads these functions for use with the 'fix' class.

3d transformations are accomplished by the use of a modelling matrix. This is a 4x4 array of numbers that can be multiplied with a 3d point to produce a different 3d point. By putting the right values into the matrix, it can be made to do various operations like translation, rotation, and scaling. The clever bit is that you can multiply two matrices together to produce a third matrix, and this will have the same effect on points as applying the original two matrices one after the other. For example, if you have one matrix that rotates a point and another that shifts it sideways, you can combine them to produce a matrix that will do the rotation and the shift in a single step. You can build up extremely complex transformations in this way, while only ever having to multiply each point by a single matrix.

Allegro actually cheats in the way it implements the matrix structure. Rotation and scaling of a 3d point can be done with a simple 3x3 matrix, but in order to translate it and project it onto the screen, the matrix must be extended to 4x4, and the point extended into 4d space by the addition of an extra coordinate, w=1. This is a bad thing in terms of efficiency, but fortunately an optimisation is possible. Given the 4x4 matrix:

   ( a, b, c, d )
   ( e, f, g, h )
   ( i, j, k, l )
   ( m, n, o, p )
a pattern can be observed in which parts of it do what. The top left 3x3 grid implements rotation and scaling. The three values in the top right column (d, h, and l) implement translation, and as long as the matrix is only used for affine transformations, m, n and o will always be zero and p will always be 1. If you don't know what affine means, read Foley & Van Damme: basically it covers scaling, translation, and rotation, but not projection. Since Allegro uses a separate function for projection, the matrix functions only need to support affine transformations, which means that there is no need to store the bottom row of the matrix. Allegro implicitly assumes that it contains (0,0,0,1), and optimises the matrix manipulation functions accordingly.

Matrices are stored in the structures:

typedef struct MATRIX            - fixed point matrix structure
{
   fixed v[3][3];                - 3x3 scaling and rotation component
   fixed t[3];                   - x/y/z translation component
} MATRIX;

typedef struct MATRIX_f          - floating point matrix structure
{
   float v[3][3];                - 3x3 scaling and rotation component
   float t[3];                   - x/y/z translation component
} MATRIX_f
extern MATRIX identity_matrix;
extern MATRIX_f identity_matrix_f;
Global variables containing the 'do nothing' identity matrix. Multiplying by the identity matrix has no effect.

void get_translation_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_translation_matrix_f(MATRIX_f *m, float x, float y, float z);
Constructs a translation matrix, storing it in m. When applied to the point (px, py, pz), this matrix will produce the point (px+x, py+y, pz+z). In other words, it moves things sideways.

void get_scaling_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_scaling_matrix_f(MATRIX_f *m, float x, float y, float z);
Constructs a scaling matrix, storing it in m. When applied to the point (px, py, pz), this matrix will produce the point (px*x, py*y, pz*z). In other words, it stretches or shrinks things.

void get_x_rotate_matrix(MATRIX *m, fixed r);
void get_x_rotate_matrix_f(MATRIX_f *m, float r);
Construct X axis rotation matrices, storing them in m. When applied to a point, these matrices will rotate it about the X axis by the specified angle (given in binary, 256 degrees to a circle format).

void get_y_rotate_matrix(MATRIX *m, fixed r);
void get_y_rotate_matrix_f(MATRIX_f *m, float r);
Construct Y axis rotation matrices, storing them in m. When applied to a point, these matrices will rotate it about the Y axis by the specified angle (given in binary, 256 degrees to a circle format).

void get_z_rotate_matrix(MATRIX *m, fixed r);
void get_z_rotate_matrix_f(MATRIX_f *m, float r);
Construct Z axis rotation matrices, storing them in m. When applied to a point, these matrices will rotate it about the Z axis by the specified angle (given in binary, 256 degrees to a circle format).

void get_rotation_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void get_rotation_matrix_f(MATRIX_f *m, float x, float y, float z);
Constructs a transformation matrix which will rotate points around all three axis by the specified amounts (given in binary, 256 degrees to a circle format).

void get_align_matrix(MATRIX *m, fixed xfront, yfront, zfront, fixed xup, fixed yup, fixed zup);
Rotates a matrix so that it is aligned along the specified coordinate vectors (they need not be normalized or perpendicular, but the up and front must not be equal). A front vector of 1,0,0 and up vector of 0,1,0 will return the identity matrix.

void get_align_matrix_f(MATRIX *m, float xfront, yfront, zfront, float xup, yup, zup);
Floating point version of get_align_matrix().

void get_vector_rotation_matrix(MATRIX *m, fixed x, y, z, fixed a);
void get_vector_rotation_matrix_f(MATRIX_f *m, float x, y, z, float a);
Constructs a transformation matrix which will rotate points around the specified x,y,z vector by the specified angle (given in binary, 256 degrees to a circle format).

void get_transformation_matrix(MATRIX *m, fixed scale, fixed xrot, yrot, zrot, x, y, z);
Constructs a transformation matrix which will rotate points around all three axis by the specified amounts (given in binary, 256 degrees to a circle format), scale the result by the specified amount (pass 1 for no change of scale), and then translate to the requested x, y, z position.

void get_transformation_matrix_f(MATRIX_f *m, float scale, float xrot, yrot, zrot, x, y, z);
Floating point version of get_transformation_matrix().

void get_camera_matrix(MATRIX *m, fixed x, y, z, xfront, yfront, zfront, fixed xup, yup, zup, fov, aspect);
Constructs a camera matrix for translating world-space objects into a normalised view space, ready for the perspective projection. The x, y, and z parameters specify the camera position, xfront, yfront, and zfront are the 'in front' vector specifying which way the camera is facing (this can be any length: normalisation is not required), and xup, yup, and zup are the 'up' direction vector. The fov parameter specifies the field of view (ie. width of the camera focus) in binary, 256 degrees to the circle format. For typical projections, a field of view in the region 32-48 will work well. Finally, the aspect ratio is used to scale the Y dimensions of the image relative to the X axis, so you can use it to adjust the proportions of the output image (set it to 1 for no scaling).

void get_camera_matrix_f(MATRIX_f *m, float x, y, z, xfront, yfront, zfront, float xup, yup, zup, fov, aspect);
Floating point version of get_camera_matrix().

void qtranslate_matrix(MATRIX *m, fixed x, fixed y, fixed z);
void qtranslate_matrix_f(MATRIX_f *m, float x, float y, float z);
Optimised routine for translating an already generated matrix: this simply adds in the translation offset, so there is no need to build two temporary matrices and then multiply them together.

void qscale_matrix(MATRIX *m, fixed scale);
void qscale_matrix_f(MATRIX_f *m, float scale);
Optimised routine for scaling an already generated matrix: this simply adds in the scale factor, so there is no need to build two temporary matrices and then multiply them together.

void matrix_mul(const MATRIX *m1, *m2, MATRIX *out);
void matrix_mul_f(const MATRIX_f *m1, *m2, MATRIX_f *out);
Multiplies two matrices, storing the result in out (this may be a duplicate of one of the input matrices, but it is faster when the inputs and output are all different). The resulting matrix will have the same effect as the combination of m1 and m2, ie. when applied to a point p, (p * out) = ((p * m1) * m2). Any number of transformations can be concatenated in this way. Note that matrix multiplication is not commutative, ie. matrix_mul(m1, m2) != matrix_mul(m2, m1).

fixed vector_length(fixed x, fixed y, fixed z);
float vector_length_f(float x, float y, float z);
Calculates the length of the vector (x, y, z), using that good 'ole Pythagoras theorem.

void normalize_vector(fixed *x, fixed *y, fixed *z);
void normalize_vector_f(float *x, float *y, float *z);
Converts the vector (*x, *y, *z) to a unit vector. This points in the same direction as the original vector, but has a length of one.

fixed dot_product(fixed x1, y1, z1, x2, y2, z2);
float dot_product_f(float x1, y1, z1, x2, y2, z2);
Calculates the dot product (x1, y1, z1) . (x2, y2, z2), returning the result.

void cross_product(fixed x1, y1, z1, x2, y2, z2, *xout, *yout, *zout);
void cross_product_f(float x1, y1, z1, x2, y2, z2, *xout, *yout, *zout);
Calculates the cross product (x1, y1, z1) x (x2, y2, z2), storing the result in (*xout, *yout, *zout). The cross product is perpendicular to both of the input vectors, so it can be used to generate polygon normals.

fixed polygon_z_normal(const V3D *v1, *v2, *v3);
float polygon_z_normal_f(const V3D_f *v1, *v2, *v3);
Finds the Z component of the normal vector to the specified three vertices (which must be part of a convex polygon). This is used mainly in back-face culling. The back-faces of closed polyhedra are never visible to the viewer, therefore they never need to be drawn. This can cull on average half the polygons from a scene. If the normal is negative the polygon can safely be culled. If it is zero, the polygon is perpendicular to the screen.

void apply_matrix(const MATRIX *m, fixed x, y, z, *xout, *yout, *zout);
void apply_matrix_f(const MATRIX_f *m, float x, y, z, *xout, *yout, *zout);
Multiplies the point (x, y, z) by the transformation matrix m, storing the result in (*xout, *yout, *zout).

void set_projection_viewport(int x, int y, int w, int h);
Sets the viewport used to scale the output of the persp_project() function. Pass the dimensions of the screen area you want to draw onto, which will typically be 0, 0, SCREEN_W, and SCREEN_H.

void persp_project(fixed x, y, z, *xout, *yout);
void persp_project_f(float x, y, z, *xout, *yout);
Projects the 3d point (x, y, z) into 2d screen space, storing the result in (*xout, *yout) and using the scaling parameters previously set by calling set_projection_viewport(). This function projects from the normalized viewing pyramid, which has a camera at the origin and facing along the positive z axis. The x axis runs left/right, y runs up/down, and z increases with depth into the screen. The camera has a 90 degree field of view, ie. points on the planes x=z and -x=z will map onto the left and right edges of the screen, and the planes y=z and -y=z map to the top and bottom of the screen. If you want a different field of view or camera location, you should transform all your objects with an appropriate viewing matrix, eg. to get the effect of panning the camera 10 degrees to the left, rotate all your objects 10 degrees to the right.


Quaternion math routines

  • apply_quat
  • get_rotation_quat
  • get_vector_rotation_quat
  • get_x_rotate_quat
  • get_y_rotate_quat
  • get_z_rotate_quat
  • identity_quat
  • matrix_to_quat
  • quat_interpolate
  • quat_mul
  • quat_slerp
  • quat_to_matrix

Quaternions are an alternate way to represent the rotation part of a transformation, and can be easier to manipulate than matrices. As with a matrix, you can encode a geometric transformations in one, concatenate several of them to merge multiple transformations, and apply them to a vector, but they can only store pure rotations. The big advantage is that you can accurately interpolate between two quaternions to get a part-way rotation, avoiding the gimbal problems of the more conventional euler angle interpolation.

Quaternions only have floating point versions, without any _f suffix. Other than that, most of the quaternion functions correspond with a matrix function that performs a similar operation.

Quaternion means 'of four parts', and that's exactly what it is. Here is the structure:

typedef struct QUAT
{
   float w, x, y, z;
}
You will have lots of fun figuring out what these numbers actually mean, but that is beyond the scope of this documentation. Quaternions do work -- trust me.

extern QUAT identity_quat;
Global variable containing the 'do nothing' identity quaternion. Multiplying by the identity quaternion has no effect.

void get_x_rotate_quat(QUAT *q, float r);
void get_y_rotate_quat(QUAT *q, float r);
void get_z_rotate_quat(QUAT *q, float r);
Construct axis rotation quaternions, storing them in q. When applied to a point, these quaternions will rotate it about the relevant axis by the specified angle (given in binary, 256 degrees to a circle format).

void get_rotation_quat(QUAT *q, float x, float y, float z);
Constructs a quaternion that will rotate points around all three axis by the specified amounts (given in binary, 256 degrees to a circle format).

void get_vector_rotation_quat(QUAT *q, float x, y, z, float a);
Constructs a quaternion that will rotate points around the specified x,y,z vector by the specified angle (given in binary, 256 degrees to a circle format).

void quat_to_matrix(const QUAT *q, MATRIX_f *m);
Constructs a rotation matrix from a quaternion.

void matrix_to_quat(const MATRIX_f *m, QUAT *q);
Constructs a quaternion from a rotation matrix. Translation is discarded during the conversion. Use get_align_matrix_f() if the matrix is not orthonormalized, because strange things may happen otherwise.

void quat_mul(const QUAT *p, const QUAT *q, QUAT *out);
Multiplies two quaternions, storing the result in out. The resulting quaternion will have the same effect as the combination of p and q, ie. when applied to a point, (point * out) = ((point * p) * q). Any number of rotations can be concatenated in this way. Note that quaternion multiplication is not commutative, ie. quat_mul(p, q) != quat_mul(q, p).

void apply_quat(const QUAT *q, float x, y, z, *xout, *yout, *zout);
Multiplies the point (x, y, z) by the quaternion q, storing the result in (*xout, *yout, *zout). This is quite a bit slower than apply_matrix_f(), so only use it to translate a few points. If you have many points, it is much more efficient to call quat_to_matrix() and then use apply_matrix_f().

void quat_interpolate(const QUAT *from, *to, float t, QUAT *out);
Constructs a quaternion that represents a rotation between from and to. The argument t can be anything between 0 and 1 and represents where between from and to the result will be. 0 returns from, 1 returns to, and 0.5 will return a rotation exactly in between. The result is copied to out. This function will create the short rotation (less than 180 degrees) between from and to.

void quat_slerp(const QUAT *from, *to, float t, QUAT *out, int how);
The same as quat_interpolate(), but allows more control over how the rotation is done. The how parameter can be any one of the values:

QUAT_SHORT - like quat_interpolate(), use shortest path
QUAT_LONG - rotation will be greater than 180 degrees
QUAT_CW - rotate clockwise when viewed from above
QUAT_CCW - rotate counterclockwise when viewed from above
QUAT_USER - the quaternions are interpolated exactly as given


GUI routines

  • active_dialog
  • active_menu
  • alert
  • alert3
  • broadcast_dialog_message
  • centre_dialog
  • d_bitmap_proc
  • d_box_proc
  • d_button_proc
  • d_check_proc
  • d_clear_proc
  • d_ctext_proc
  • d_edit_proc
  • d_icon_proc
  • d_keyboard_proc
  • d_list_proc
  • d_menu_proc
  • d_radio_proc
  • d_rtext_proc
  • d_shadow_box_proc
  • d_slider_proc
  • d_text_list_proc
  • d_text_proc
  • d_textbox_proc
  • d_yield_proc
  • dialog_message
  • do_dialog
  • do_menu
  • file_select
  • file_select_ex
  • find_dialog_focus
  • gfx_mode_select
  • gfx_mode_select_ex
  • gui_bg_color
  • gui_button_proc
  • gui_ctext_proc
  • gui_edit_proc
  • gui_fg_color
  • gui_font_baseline
  • gui_list_proc
  • gui_menu_draw_menu
  • gui_menu_draw_menu_item
  • gui_mg_color
  • gui_mouse_b
  • gui_mouse_focus
  • gui_mouse_x
  • gui_mouse_y
  • gui_mouse_z
  • gui_shadow_box_proc
  • gui_strlen
  • gui_text_list_proc
  • gui_textout
  • init_dialog
  • object_message
  • offer_focus
  • popup_dialog
  • position_dialog
  • set_dialog_color
  • shutdown_dialog
  • update_dialog

Allegro contains an object-oriented dialog manager, which was originally based on the Atari GEM system (form_do(), objc_draw(), etc: old ST programmers will know what I'm talking about :-) You can use the GUI as-is to knock out simple interfaces for things like the test program and grabber utility, or you can use it as a basis for more complicated systems of your own. Allegro lets you define your own object types by writing new dialog procedures, so you can take complete control over the visual aspects of the interface while still using Allegro to handle input from the mouse, keyboard, joystick, etc.

A GUI dialog is stored as an array of DIALOG objects, each one containing the fields:

typedef struct DIALOG
{
   int (*proc)(int, DIALOG *, int); - dialog procedure (message handler)
   int x, y, w, h;                  - position and size of the object
   int fg, bg;                      - foreground and background colors
   int key;                         - ASCII keyboard shortcut
   int flags;                       - flags about the status of
                                      the object
   int d1, d2;                      - whatever you want to use them for
   void *dp, *dp2, *dp3;            - pointers to more
                                      object-specific data
} DIALOG;
The array should end with an object which has the proc pointer set to NULL.

The flags field may contain any combination of the bit flags:

   D_EXIT          - this object should close the dialog when it is clicked
   D_SELECTED      - this object is selected
   D_GOTFOCUS      - this object has got the input focus
   D_GOTMOUSE      - the mouse is currently on top of this object
   D_HIDDEN        - this object is hidden and inactive
   D_DISABLED      - this object is greyed-out and inactive
   D_DIRTY         - this object needs to be redrawn
   D_INTERNAL      - don't use this! It is for internal use by the
                     library...
   D_USER          - any powers of two above this are free for your own use
Each object is controlled by a dialog procedure, which is stored in the proc pointer. This will be called by the dialog manager whenever any action concerning the object is required, or you can call it directly with the object_message() function. The dialog procedure should follow the form:

   int foo(int msg, DIALOG *d, int c);
It will be passed a flag (msg) indicating what action it should perform, a pointer to the object concerned (d), and if msg is MSG_CHAR or MSG_XCHAR, the key that was pressed (c). Note that d is a pointer to a specific object, and not to the entire dialog.

The dialog procedure should return one of the values:

   D_O_K          - normal return status
   D_CLOSE        - tells the dialog manager to close the dialog
   D_REDRAW       - tells the dialog manager to redraw the entire dialog
   D_REDRAWME     - tells the dialog manager to redraw the current object
   D_WANTFOCUS    - requests that the input focus be given to this object
   D_USED_CHAR    - MSG_CHAR and MSG_XCHAR return this if they used the key
Dialog procedures may be called with any of the messages:

MSG_START:
Tells the object to initialise itself. The dialog manager sends this to all the objects in a dialog just before it displays the dialog.

MSG_END:
Sent to all objects when closing a dialog, allowing them to perform whatever cleanup operations they require.

MSG_DRAW:
Tells the object to draw itself onto the screen. The mouse pointer will be turned off when this message is sent, so the drawing code does not need to worry about it.

MSG_CLICK:
Informs the object that a mouse button has been clicked while the mouse was on top of the object. Typically an object will perform its own mouse tracking as long as the button is held down, and only return from this message handler when it is released.

MSG_DCLICK:
Sent when the user double-clicks on an object. A MSG_CLICK will be sent when the button is first pressed, then MSG_DCLICK if it is released and pressed again within a short space of time.

MSG_KEY:
Sent when the keyboard shortcut for the object is pressed, or if enter, space, or a joystick button is pressed while it has the input focus.

MSG_CHAR:
When a key is pressed, this message is sent to the object that has the input focus, with a readkey() format character code (ASCII value in the low byte, scancode in the high byte) as the c parameter. If the object deals with the keypress it should return D_USED_CHAR, otherwise it should return D_O_K to allow the default keyboard interface to operate. If you need to access Unicode character input, you should use MSG_UCHAR instead of MSG_CHAR.

MSG_UCHAR:
If an object ignores the MSG_CHAR input, this message will be sent immediately after it, passed the full Unicode key value as the c parameter. This enables you to read character codes greater than 255, but cannot tell you anything about the scancode: if you need to know that, use MSG_CHAR instead. This handler should return D_USED_CHAR if it processed the input, or D_O_K otherwise.

MSG_XCHAR:
When a key is pressed, Allegro will send a MSG_CHAR and MSG_UCHAR to the object with the input focus. If this object doesn't process the key (ie. it returns D_O_K rather than D_USED_CHAR), the dialog manager will look for an object with a matching keyboard shortcut in the key field, and send it a MSG_KEY. If this fails, it broadcasts a MSG_XCHAR to all objects in the dialog, allowing them to respond to special keypresses even when they don't have the input focus. Normally you should ignore this message (return D_O_K rather than D_USED_CHAR), in which case Allegro will perform default actions such as moving the focus in response to the arrow keys and closing the dialog if ESC is pressed.

MSG_WANTFOCUS:
Queries whether an object is willing to accept the input focus. It should return D_WANTFOCUS if it does, or D_O_K if it isn't interested in getting user input.

MSG_GOTFOCUS:
MSG_LOSTFOCUS:
Sent whenever an object gains or loses the input focus. These messages will always be followed by a MSG_DRAW, to let objects display themselves differently when they have the input focus. If you return D_WANTFOCUS in response to a MSG_LOSTFOCUS event, this will prevent your object from losing the focus when the mouse moves off it onto the screen background or some inert object, so it will only lose the input focus when some other object is ready to take over the focus (this trick is used by the d_edit_proc() object).

MSG_GOTMOUSE:
MSG_LOSTMOUSE:
Sent when the mouse moves on top of or away from an object. Unlike the focus messages, these are not followed by a MSG_DRAW, so if the object is displayed differently when the mouse is on top of it, it is responsible for redrawing itself in response to these messages.

MSG_IDLE:
Sent whenever the dialog manager has nothing better to do.

MSG_RADIO:
Sent by radio button objects to deselect other buttons in the same group when they are clicked. The group number is passed in the c message parameter.

MSG_WHEEL:
Sent to the focused object whenever the mouse wheel moves. The c message parameter contains the number of clicks.

MSG_LPRESS, MSG_MPRESS, MSG_RPRESS:
Sent when the corresponding mouse button is pressed.

MSG_LRELEASE, MSG_MRELEASE, MSG_RRELEASE:
Sent when the corresponding mouse button is released.

MSG_USER:
The first free message value. Any numbers from here on (MSG_USER, MSG_USER+1, MSG_USER+2, ... MSG_USER+n) are free to use for whatever you like.

Allegro provides several standard dialog procedures. You can use these as they are to provide simple user interface objects, or you can call them from within your own dialog procedures, resulting in a kind of OOP inheritance. For instance, you could make an object which calls d_button_proc to draw itself, but handles the click message in a different way, or an object which calls d_button_proc for everything except drawing itself, so it would behave like a normal button but could look completely different.

Since the release of Allegro version 3.9.33 (CVS), some GUI objects and menus are being drawn differently unlike in previous Allegro versions. The changes are the following:

  • Shadows under d_shadow_box_proc and d_button_proc are always black.

  • The most important (and immediately visible) change is, that some objects are being drawn smaller. The difference is exactly one pixel in both height and width, when comparing to previous versions. The reason is, that in previous versions these objects were too large on the screen - their size was d->w+1 and d->h+1 pixels (and not d->w and d->h, as it should be). This change affects the following objects :

              d_box_proc,
          d_shadow_box_proc,
          d_button_proc,
          d_check_proc,
          d_radio_proc,
          d_list_proc,
          d_text_list_proc and
          d_textbox_proc.
    When you want to convert old dialogs to look equally when compiling with the new Allegro version, just increase the size of the mentioned objects by one pixel in both width and height fields.

  • When a GUI menu item (not in a bar menu) has a child menu, there is a small arrow next to the child menu name, pointing to the right - so the user can immediately see that this menu item has a child menu - and there is no need to use such menu item names as for example "New...", to show that it has a child menu. The submenu will be drawn to the right of the parent menu, trying not to overlap it.

int d_clear_proc(int msg, DIALOG *d, int c);
This just clears the screen when it is drawn. Useful as the first object in a dialog.

int d_box_proc(int msg, DIALOG *d, int c);
int d_shadow_box_proc(int msg, DIALOG *d, int c);
These draw boxes onto the screen, with or without a shadow.

int d_bitmap_proc(int msg, DIALOG *d, int c);
This draws a bitmap onto the screen, which should be pointed to by the dp field.

int d_text_proc(int msg, DIALOG *d, int c);
int d_ctext_proc(int msg, DIALOG *d, int c);
int d_rtext_proc(int msg, DIALOG *d, int c);
These draw text onto the screen. The dp field should point to the string to display. d_ctext_proc() centres the string around the x coordinate, and d_rtext_proc() right aligns it. Any '&' characters in the string will be replaced with lines underneath the following character, for displaying keyboard shortcuts (as in MS Windows). To display a single ampersand, put "&&". To draw the text in something other than the default font, set the dp2 field to point to your custom font data.

int d_button_proc(int msg, DIALOG *d, int c);
A button object (the dp field points to the text string). This object can be selected by clicking on it with the mouse or by pressing its keyboard shortcut. If the D_EXIT flag is set, selecting it will close the dialog, otherwise it will toggle on and off. Like d_text_proc(), ampersands can be used to display the keyboard shortcut of the button.

int d_check_proc(int msg, DIALOG *d, int c);
This is an example of how you can derive objects from other objects. Most of the functionality comes from d_button_proc(), but it displays itself as a check box. If the d1 field is non-zero, the text will be printed to the right of the check, otherwise it will be on the left.

Note: the object width should allow space for the text as well as the check box (which is square, with sides equal to the object height).

int d_radio_proc(int msg, DIALOG *d, int c);
A radio button object. A dialog can contain any number of radio button groups: selecting a radio button causes other buttons within the same group to be deselected. The dp field points to the text string, d1 specifies the group number, and d2 is the button style (0=circle, 1=square).

int d_icon_proc(int msg, DIALOG *d, int c);
A bitmap button. The fg color is used for the dotted line showing focus, and the bg color for the shadow used to fill in the top and left sides of the button when "pressed". d1 is the "push depth", ie. the number of pixels the icon will be shifted to the right and down when selected (default 2) if there is no "selected" image. d2 is the distance by which the dotted line showing focus is indented (default 2). dp points to a bitmap for the icon, while dp2 and dp3 are the selected and disabled images respectively (optional, may be NULL).

int d_keyboard_proc(int msg, DIALOG *d, int c);
This is an invisible object for implementing keyboard shortcuts. You can put an ASCII code in the key field of the dialog object (a character such as 'a' to respond to a simple keypress, or a number 1-26 to respond to a control key a-z), or you can put a keyboard scancode in the d1 and/or d2 fields. When one of these keys is pressed, the object will call the function pointed to by dp. This should return an int, which will be passed back to the dialog manager, so it can return D_O_K, D_REDRAW, D_CLOSE, etc.

int d_edit_proc(int msg, DIALOG *d, int c);
An editable text object (the dp field points to the string). When it has the input focus (obtained by clicking on it with the mouse), text can be typed into this object. The d1 field specifies the maximum number of characters that it will accept, and d2 is the text cursor position within the string.

int d_list_proc(int msg, DIALOG *d, int c);
A list box object. This will allow the user to scroll through a list of items and to select one by clicking or with the arrow keys. If the D_EXIT flag is set, double clicking on a list item will close the dialog. The index of the selected item is held in the d1 field, and d2 is used to store how far it has scrolled through the list. The dp field points to a function which will be called to obtain information about the contents of the list. This should follow the form:

      char *foobar(int index, int *list_size);
If index is zero or positive, the function should return a pointer to the string which is to be displayed at position index in the list. If index is negative, it should return NULL and list_size should be set to the number of items in the list.

To create a multiple selection listbox, set the dp2 field to an array of byte flags indicating the selection state of each list item (non-zero for selected entries). This table must be at least as big as the number of objects in the list!

int d_text_list_proc(int msg, DIALOG *d, int c);
Like d_list_proc, but allows the user to type in the first few characters of a listbox entry in order to select it. Uses dp3 internally, so you mustn't store anything important there yourself.

int d_textbox_proc(int msg, DIALOG *d, int c);
A text box object. The dp field points to the text which is to be displayed in the box. If the text is long, there will be a vertical scrollbar on the right hand side of the object which can be used to scroll through the text. The default is to print the text with word wrapping, but if the D_SELECTED flag is set, the text will be printed with character wrapping. The d1 field is used internally to store the number of lines of text, and d2 is used to store how far it has scrolled through the text.

int d_slider_proc(int msg, DIALOG *d, int c);
A slider control object. This object holds a value in d2, in the range from 0 to d1. It will display as a vertical slider if h is greater than or equal to w, otherwise it will display as a horizontal slider. The dp field can contain an optional bitmap to use for the slider handle, and dp2 can contain an optional callback function, which is called each time d2 changes. The callback function should have the following prototype:

      int function(void *dp3, int d2);
The d_slider_proc object will return the value of the callback function.

int d_menu_proc(int msg, DIALOG *d, int c);
This object is a menu bar which will drop down child menus when it is clicked or if an alt+key corresponding to one of the shortcuts in the menu is pressed. It ignores a lot of the fields in the dialog structure, in particular the color is taken from the gui_*_color variables, and the width and height are calculated automatically (the w and h fields from the DIALOG are only used as a minimum size.) The dp field points to an array of menu structures: see do_menu() for more information. The top level menu will be displayed as a horizontal bar, but when child menus drop down from it they will be in the normal vertical format used by do_menu(). When a menu item is selected, the return value from the menu callback function is passed back to the dialog manager, so your callbacks should return D_O_K, D_REDRAW, or D_CLOSE.

int d_yield_proc(int msg, DIALOG *d, int c);
An invisible helper object that yields timeslices for the scheduler (if the system supports it) when the gui has nothing to do but waiting for user actions. You should put one instance of this object in each dialog array because it may be needed on systems with an unusual scheduling algorithm (for instance QNX) in order to make the GUI fully responsive.

The behaviour of the dialog manager can be controlled by the variables:

extern int gui_mouse_focus;
If set, the input focus follows the mouse pointer around the dialog, otherwise a click is required to move it.

extern int gui_fg_color;
extern int gui_bg_color;
The foreground and background colors for the standard dialogs (alerts, menus, and the file selector). They default to 255 and 0.

extern int gui_mg_color;
The color used for displaying greyed-out dialog objects (with the D_DISABLED flag set). Defaults to 8.

extern int gui_font_baseline;
If set to a non-zero value, adjusts the keyboard shortcut underscores to account for the height of the descenders in your font.

extern int (*gui_mouse_x)();
extern int (*gui_mouse_y)();
extern int (*gui_mouse_z)();
extern int (*gui_mouse_b)();
Hook functions, used by the GUI routines whenever they need to access the mouse state. By default these just return copies of the mouse_x, mouse_y, mouse_z, and mouse_b variables, but they could be used to offset or scale the mouse position, or read input from a different source entirely.

You can change the global 'font' pointer to make the GUI objects use something other than the standard 8x8 font. The standard dialog procedures, menus, and alert boxes, will work with fonts of any size, but the gfx_mode_select() dialog will look wrong with anything other than 8x8 fonts.

int gui_textout(BITMAP *bmp, const char *s, int x, y, color, centre);
Helper function for use by the GUI routines. Draws a text string onto the screen, interpreting the '&' character as an underbar for displaying keyboard shortcuts. Returns the width of the output string in pixels.

int gui_strlen(const char *s);
Helper function for use by the GUI routines. Returns the length of a string in pixels, ignoring '&' characters.

void position_dialog(DIALOG *dialog, int x, int y);
Moves an array of dialog objects to the specified screen position (specified as the top left corner of the dialog).

void centre_dialog(DIALOG *dialog);
Moves an array of dialog objects so that it is centered in the screen.

void set_dialog_color(DIALOG *dialog, int fg, int bg);
Sets the foreground and background colors of an array of dialog objects.

int find_dialog_focus(DIALOG *dialog);
Searches the dialog for the object which has the input focus, returning an index or -1 if the focus is not set. This is useful if you are calling do_dialog() several times in a row and want to leave the focus in the same place it was when the dialog was last displayed, as you can call do_dialog(dlg, find_dialog_focus(dlg));

int offer_focus(DIALOG *d, int obj, int *focus_obj, int force);
Offers the input focus to a particular object. Normally the function sends the MSG_WANTFOCUS message to query whether the object is willing to accept the focus. However, passing any non zero value as force argument instructs the function to authoritatively set the focus to the object.

int object_message(DIALOG *dialog, int msg, int c);
Sends a message to an object and returns the answer it has generated. Remember that the first parameter is the dialog object (not a whole array) that you wish to send the message to. For example, to make the second object in a dialog draw itself, you might write:

      object_message(&dialog[1], MSG_DRAW, 0);
int dialog_message(DIALOG *dialog, int msg, int c, int *obj);
Sends a message to all the objects in an array. If any of the dialog procedures return values other than D_O_K, it returns the value and sets obj to the index of the object which produced it.

int broadcast_dialog_message(int msg, int c);
Broadcasts a message to all the objects in the active dialog. If any of the dialog procedures return values other than D_O_K, it returns that value.

int do_dialog(DIALOG *dialog, int focus_obj);
The basic dialog manager function. This displays a dialog (an array of dialog objects, terminated by one with a NULL dialog procedure), and sets the input focus to the focus_obj (-1 if you don't want anything to have the focus). It interprets user input and dispatches messages as they are required, until one of the dialog procedures tells it to close the dialog, at which point it returns the index of the object that caused it to exit.

int popup_dialog(DIALOG *dialog, int focus_obj);
Like do_dialog(), but it stores the data on the screen before drawing the dialog and restores it when the dialog is closed. The screen area to be stored is calculated from the dimensions of the first object in the dialog, so all the other objects should lie within this one.

DIALOG_PLAYER *init_dialog(DIALOG *dialog, int focus_obj);
This function provides lower level access to the same functionality as do_dialog(), but allows you to combine a dialog box with your own program control structures. It initialises a dialog, returning a pointer to a player object that can be used with update_dialog() and shutdown_dialog(). With these functions, you could implement your own version of do_dialog() with the lines:

      DIALOG_PLAYER *player = init_dialog(dialog, focus_obj);

      while (update_dialog(player))
         ;

      return shutdown_dialog(player);
int update_dialog(DIALOG_PLAYER *player);
Updates the status of a dialog object returned by init_dialog(). Returns TRUE if the dialog is still active, or FALSE if it has terminated. Upon a return value of FALSE, it is up to you whether to call shutdown_dialog() or to continue execution. The object that requested the exit can be determined from the player->obj field.

int shutdown_dialog(DIALOG_PLAYER *player);
Destroys a dialog player object returned by init_dialog(), returning the object that caused it to exit (this is the same as the return value from do_dialog()).

extern DIALOG *active_dialog;
Global pointer to the most recent activated dialog. This may be useful if an object needs to iterate through a list of all its siblings.

Popup or pulldown menus are created as an array of the structures:

typedef struct MENU
{
   char *text;                   - the text to display for the menu item
   int (*proc)(void);            - called when the menu item is clicked
   struct MENU *child;           - nested child menu
   int flags;                    - disabled or checked state
   void *dp;                     - pointer to any data you need
} MENU;
Each menu item contains a text string. This can use the '&' character to indicate keyboard shortcuts, or can be an zero-length string to display the item as a non-selectable splitter bar. If the string contains a "\t" tab character, any text after this will be right-justified, eg. for displaying keyboard shortcut information. The proc pointer is a function which will be called when the menu item is selected, and child points to another menu, allowing you to create nested menus. Both proc and child may be NULL. The proc function returns an integer which is ignored if the menu was brought up by calling do_menu(), but which is passed back to the dialog manager if it was created by a d_menu_proc() object. The array of menu items is terminated by an entry with a NULL text pointer.

Menu items can be disabled (greyed-out) by setting the D_DISABLED bit in the flags field, and a check mark can be displayed next to them by setting the D_SELECTED bit. With the default alignment and font this will usually overlap the menu text, so if you are going to use checked menu items it would be a good idea to prefix all your options with a space or two, to ensure there is room for the check.

int do_menu(MENU *menu, int x, int y)
Displays and animates a popup menu at the specified screen coordinates (these will be adjusted if the menu does not entirely fit on the screen). Returns the index of the menu item that was selected, or -1 if the menu was cancelled. Note that the return value cannot indicate selection from child menus, so you will have to use the callback functions if you want multi-level menus.

extern MENU *active_menu;
When a menu callback procedure is triggered, this will be set to the menu item that was selected, so your routine can determine where it was called from.

extern void (*gui_menu_draw_menu)(int x, int y, int w, int h);
extern void (*gui_menu_draw_menu_item)(MENU *m, int x, int y, int w, int h, int bar, int sel);
If set, these functions will be called whenever a menu needs to be drawn, so you can change how menus look.

gui_menu_draw_menu() is passed the position and size of the menu. It should draw the background of the menu onto screen.

gui_menu_draw_menu_item() is called once for each menu item that is to be drawn. bar will be set if the item is part of a top-level horizontal menu bar, and sel will be set if the menu item is selected. It should also draw onto screen.

int alert(const char *s1, *s2, *s3, const char *b1, *b2, int c1, c2);
Displays a popup alert box, containing three lines of text (s1-s3), and with either one or two buttons. The text for these buttons is passed in b1 and b2 (b2 may be NULL), and the keyboard shortcuts in c1 and c2. Returns 1 or 2 depending on which button was clicked. If the alert is dismissed by pressing ESC when ESC is not one of the keyboard shortcuts, it treats it as a click on the second button (this is consistent with the common "Ok", "Cancel" alert).

int alert3(const char *s1, *s2, *s3, const char *b1, *b2, *b3, int c1, c2, c3);
Like alert(), but with three buttons. Returns 1, 2, or 3.

int file_select(const char *message, char *path, const char *ext);
Deprecated. Use file_select_ex() instead, passing the two constants OLD_FILESEL_WIDTH and OLD_FILESEL_HEIGHT if you want the file selector to be displayed with the dimensions of the old file selector.

int file_select_ex(const char *message, char *path, const char *ext, int size, int w, int h);
Displays the Allegro file selector, with the message as caption. The path parameter contains the initial filename to display (this can be used to set the starting directory, or to provide a default filename for a save-as operation). The user selection is returned by altering the path buffer, whose maximum capacity in bytes is specified by the size parameter. Note that it should have room for at least 80 characters (not bytes), so you should reserve 6x that amount, just to be sure. The list of files is filtered according to the file extensions in the ext parameter. Passing NULL includes all files; "PCX;BMP" includes only files with .PCX or .BMP extensions. If you wish to control files by their attributes, one of the fields in the extension list can begin with a slash, followed by a set of attribute characters. Any attributes written on their own, or with a + before them, indicate to include only files which have that attribute set. Any attributes with a '-' before them indicate to leave out any files with that attribute. The flag characters are 'r' (read-only), 'h' (hidden), 's' (system), 'd' (directory), and 'a' (archive). For example, an extension string of "PCX;BMP;/+r-d" will display only PCX or BMP files that are read-only, and no directories. The file selector is stretched to the width and height specified in the w and h parameters, and to the size of the standard Allegro font. If either the width or height argument is set to zero, it is stretched to the corresponding screen dimension. This function returns zero if it was closed with the Cancel button or non-zero if it was OK'd.

int gfx_mode_select(int *card, int *w, int *h);
Displays the Allegro graphics mode selection dialog, which allows the user to select a screen mode and graphics card. Stores the selection in the three variables, and returns zero if it was closed with the Cancel button or non-zero if it was OK'd.

int gfx_mode_select_ex(int *card, int *w, int *h, int *color_depth);
Extended version of the graphics mode selection dialog, which allows the user to select the color depth as well as the resolution and hardware driver. This version of the function reads the initial values from the parameters when it activates, so you can specify the default values.

extern int (*gui_shadow_box_proc)(int msg, struct DIALOG *d, int c);
extern int (*gui_ctext_proc)(int msg, struct DIALOG *d, int c);
extern int (*gui_button_proc)(int msg, struct DIALOG *d, int c);
extern int (*gui_edit_proc)(int msg, struct DIALOG *d, int c);
extern int (*gui_list_proc)(int msg, struct DIALOG *d, int c);
extern int (*gui_text_list_proc)(int msg, struct DIALOG *d, int c);
If set, these functions will be used by the standard Allegro dialogs.
   This allows you to customise the look and feel, much like gui_fg_color
   and gui_bg_color, but much more flexiblely.


DOS specifics

  • DIGI_*/DOS
  • GFX_*/DOS
  • i_love_bill
  • JOY_TYPE_*/DOS
  • MIDI_*/DOS
  • split_modex_screen

Drivers JOY_TYPE_*/DOS
The DOS library supports the following type parameters for the install_joystick() function:

  • JOY_TYPE_AUTODETECT
    Attempts to autodetect your joystick hardware. It isn't possible to reliably distinguish between all the possible input setups, so this routine can only ever choose the standard joystick, Sidewider, GamePad Pro, or GrIP drivers, but it will use information from the configuration file if one is available (this can be created using the setup utility or by calling the save_joystick_data() function), so you can always use JOY_TYPE_AUTODETECT in your code and then select the exact hardware type from the setup program.

  • JOY_TYPE_NONE
    Dummy driver for machines without any joystick.

  • JOY_TYPE_STANDARD
    A normal two button stick.

  • JOY_TYPE_2PADS
    Dual joystick mode (two sticks, each with two buttons).

  • JOY_TYPE_4BUTTON
    Enable the extra buttons on a 4-button joystick.

  • JOY_TYPE_6BUTTON
    Enable the extra buttons on a 6-button joystick.

  • JOY_TYPE_8BUTTON
    Enable the extra buttons on an 8-button joystick.

  • JOY_TYPE_FSPRO
    CH Flightstick Pro or compatible stick, which provides four buttons, an analogue throttle control, and a 4-direction coolie hat.

  • JOY_TYPE_WINGEX
    A Logitech Wingman Extreme, which should also work with any Thrustmaster Mk.I compatible joystick. It provides support for four buttons and a coolie hat. This also works with the Wingman Warrior, if you plug in the 15 pin plug (remember to unplug the 9-pin plug!) and set the tiny switch in front to the "H" position (you will not be able to use the throttle or the spinner though).

  • JOY_TYPE_SIDEWINDER
    The Microsoft Sidewinder digital pad (supports up to four controllers, each with ten buttons and a digital direction control).

  • JOY_TYPE_SIDEWINDER_AG
    An alternative driver to JOY_TYPE_SIDEWINDER. Try this if your Sidewinder isn't recognized with JOY_TYPE_SIDEWINDER.

  • JOY_TYPE_GAMEPAD_PRO
    The Gravis GamePad Pro (supports up to two controllers, each with ten buttons and a digital direction control).

  • JOY_TYPE_GRIP
    Gravis GrIP driver, using the grip.gll driver file.

  • JOY_TYPE_GRIP4
    Version of the Gravis GrIP driver that is constrained to only move along the four main axis.

  • JOY_TYPE_SNESPAD_LPT1
    JOY_TYPE_SNESPAD_LPT2
    JOY_TYPE_SNESPAD_LPT3
    SNES joypads connected to LPT1, LPT2, and LPT3 respectively.

  • JOY_TYPE_PSXPAD_LPT1
    JOY_TYPE_PSXPAD_LPT2
    JOY_TYPE_PSXPAD_LPT3
    PSX joypads connected to LPT1, LPT2, and LPT3 respectively. See http://www.ziplabel.com/dpadpro/index.html for information about the parallel cable required. The driver automagically detects which types of PSX pads are connected out of digital, analog (red or green mode), NegCon, multi taps, Namco light guns, Jogcons (force feedback steering wheel) and the mouse. If the controller isn't recognised it is treated as an analog controller, meaning the driver should work with just about anything. You can connect controllers in any way you see fit, but only the first 8 will be used.

    The Sony Dual Shock or Namco Jogcon will reset themselves (to digital mode) after not being polled for 5 seconds. This is normal, the same thing happens on a Playstation, it's designed to stop any vibration in case the host machine crashes. Other mode switching controllers may have similar quirks. However, if this happens to a Jogcon controller the mode button is disabled. To reenable the mode button on the Jogcon you need to hold down the Start and Select buttons at the same time.

    The G-con45 needs to be connected to (and pointed at) a TV type monitor connected to your computer. The composite video out on my video card works fine for this (a Hercules Stingray 128/3D 8Mb). The TV video modes in Mame should work too.

  • JOY_TYPE_N64PAD_LPT1
    JOY_TYPE_N64PAD_LPT2
    JOY_TYPE_N64PAD_LPT3
    N64 joypads connected to LPT1, LPT2, and LPT3 respectively. See http://www.st-hans.de/N64.htm for information about the necessary hardware adaptor. It supports up to four controllers on a single parallel port. There is no need to calibrate the analog stick, as this is done by the controller itself when powered up. This means that the stick has to be centred when the controller is initialised. One possible issue people may have with this driver is that it is physically impossible to move the analog stick fully diagonal, but I can't see this causing any major problems. This is because of the shape of the rim that the analog stick rests against. Like the Gravis Game Pad Pro, this driver briefly needs to disable hardware interrupts while polling. This causes a noticable performance hit on my machine in both drivers, but there is no way around it. At a (very) rough guess I'd say it slows down Mame 5% - 10%.

  • JOY_TYPE_DB9_LPT1
    JOY_TYPE_DB9_LPT2
    JOY_TYPE_DB9_LPT3
    A pair of two-button joysticks connected to LPT1, LPT2, and LPT3 respectively. Port 1 is compatible with Linux joy-db9 driver (multisystem 2-button), and port 2 is compatible with Atari interface for DirectPad Pro. See the source file (src/dos/multijoy.c) for pinout information.

  • JOY_TYPE_TURBOGRAFIX_LPT1
    JOY_TYPE_TURBOGRAFIX_LPT2
    JOY_TYPE_TURBOGRAFIX_LPT3
    These drivers support up to 7 joysticks, each one with up to 5 buttons, connected to LPT1, LPT2, and LPT3 respectively. They use the TurboGraFX interface by Steffen Schwenke: see http://www.burg-halle.de/~schwenke/parport.html for details on how to build this.

  • JOY_TYPE_WINGWARRIOR
    A Wingman Warrior joystick.

  • JOY_TYPE_IFSEGA_ISA
    JOY_TYPE_IFSEGA_PCI
    JOY_TYPE_IFSEGA_PCI_FAST
    Drivers for the IF-SEGA joystick interface cards by the IO-DATA company (these come in PCI, PCI2, and ISA variants).

Drivers GFX_*/DOS
The DOS library supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    Return to text mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers. This will always fail under DOS.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution or color depth you get. See the set_gfx_mode() documentation for details.

  • GFX_VGA
    The standard 256 color VGA mode 13h, using the GFX_VGA driver. This is normally sized 320x200, which will work on any VGA but doesn't support large virtual screens and hardware scrolling. Allegro also provides some tweaked variants of the mode which are able to scroll, sized 320x100 (with a 200 pixel high virtual screen), 160x120 (with a 409 pixel high virtual screen), 256x256 (no scrolling), and 80x80 (with a 819 pixel high virtual screen).

  • GFX_MODEX
    Mode-X will work on any VGA card, and provides a range of different 256 color tweaked resolutions.

    • Stable mode-X resolutions:

      • Square aspect ratio: 320x240

      • Skewed aspect ratio: 256x224, 256x240, 320x200, 320x400, 320x480, 320x600, 360x200, 360x240, 360x360, 360x400, 360x480

      These have worked on every card/monitor that I've tested.

    • Unstable mode-X resolutions:

      • Square aspect ratio: 360x270, 376x282, 400x300

      • Skewed aspect ratio: 256x200, 256x256, 320x350, 360x600, 376x308, 376x564, 400x150, 400x600

      These only work on some monitors. They were fine on my old machine, but don't get on very well with my new monitor. If you are worried about the possibility of damaging your monitor by using these modes, don't be. Of course I'm not providing any warranty with any of this, and if your hardware does blow up that is tough, but I don't think this sort of tweaking can do any damage. From the documentation of Robert Schmidt's TWEAK program:

      "Some time ago, putting illegal or unsupported values or combinations of such into the video card registers might prove hazardous to both your monitor and your health. I have *never* claimed that bad things can't happen if you use TWEAK, although I'm pretty sure it never will. I've never heard of any damage arising from trying out TWEAK, or from general VGA tweaking in any case."

    Most of the mode-X drawing functions are slower than in mode 13h, due to the complexity of the planar bitmap organisation, but solid area fills and plane-aligned blits from one part of video memory to another can be significantly faster, particularly on older hardware. Mode-X can address the full 256k of VGA RAM, so hardware scrolling and page flipping are possible, and it is possible to split the screen in order to scroll the top part of the display but have a static status indicator at the bottom.

  • GFX_VESA1
    Use the VESA 1.x driver.

  • GFX_VESA2B
    Use the VBE 2.0 banked mode driver.

  • GFX_VESA2L
    Use the VBE 2.0 linear framebuffer driver.

  • GFX_VESA3
    Use the VBE 3.0 driver. This is the only VESA driver that supports the request_refresh_rate() function.

    The standard VESA modes are 640x480, 800x600, and 1024x768. These ought to work with any SVGA card: if they don't, get a copy of the SciTech Display Doctor and see if that fixes it. What color depths are available will depend on your hardware. Most cards support both 15 and 16 bit resolutions, but if at all possible I would advise you to support both (it's not hard...) in case one is not available. Some cards provide both 24 and 32 bit truecolor, in which case it is a choice between 24 (saves memory) or 32 (faster), but many older cards have no 32 bit mode and some newer ones don't support 24 bit resolutions. Use the vesainfo test program to see what modes your VESA driver provides.

    Many cards also support 640x400, 1280x1024, and 1600x1200, but these aren't available on everything, for example the S3 chipset has no 640x400 mode. Other weird resolution may be possible, eg. some Tseng boards can do 640x350, and the Avance Logic has a 512x512 mode.

    The SciTech Display Doctor provides several scrollable low resolution modes in a range of different color depths (320x200, 320x240, 320x400, 320x480, 360x200, 360x240, 360x400, and 360x480 all work on my ET4000 with 8, 15, or 16 bits per pixel). These are lovely, allowing scrolling and page flipping without the complexity of the mode-X planar setup, but unfortunately they aren't standard so you will need Display Doctor in order to use them.

  • GFX_VBEAF
    VBE/AF is a superset of the VBE 2.0 standard, which provides an API for accessing hardware accelerator features. VBE/AF drivers are currently only available from the FreeBE/AF project or as part of the SciTech Display Doctor package, but they can give dramatic speed improvements when used with suitable hardware. For a detailed discussion of hardware acceleration issues, refer to the documentation for the gfx_capabilities flag.

    You can use the afinfo test program to check whether you have a VBE/AF driver, and to see what resolutions it supports.

    The SciTech VBE/AF drivers require nearptr access to be enabled, so any stray pointers are likely to crash your machine while their drivers are in use. This means it may be a good idea to use VESA while debugging your program, and only switch to VBE/AF once the code is working correctly. The FreeBE/AF drivers do not have this problem.

  • GFX_XTENDED
    An unchained 640x400 mode, as described by Mark Feldman in the PCGPE. This uses VESA to select an SVGA mode (so it will only work on cards supporting the VESA 640x400 resolution), and then unchains the VGA hardware as for mode-X. This allows the entire screen to be addressed without the need for bank switching, but hardware scrolling and page flipping are not possible. This driver will never be autodetected (the normal VESA 640x400 mode will be chosen instead), so if you want to use it you will have to explicitly pass GFX_XTENDED to set_gfx_mode().

Drivers DIGI_*/DOS
The DOS sound functions support the following digital soundcards:

      DIGI_AUTODETECT      - let Allegro pick a digital sound driver
      DIGI_NONE            - no digital sound
      DIGI_SB              - Sound Blaster (autodetect type)
      DIGI_SB10            - SB 1.0 (8 bit mono single shot dma)
      DIGI_SB15            - SB 1.5 (8 bit mono single shot dma)
      DIGI_SB20            - SB 2.0 (8 bit mono auto-initialised
                             dma)
      DIGI_SBPRO           - SB Pro (8 bit stereo)
      DIGI_SB16            - SB16 (16 bit stereo)
      DIGI_AUDIODRIVE      - ESS AudioDrive
      DIGI_SOUNDSCAPE      - Ensoniq Soundscape
      DIGI_WINSOUNDSYS     - Windows Sound System
Drivers MIDI_*/DOS
The DOS sound functions support the following MIDI soundcards:

      MIDI_AUTODETECT      - let Allegro pick a MIDI sound driver
      MIDI_NONE            - no MIDI sound
      MIDI_ADLIB           - Adlib or SB FM synth (autodetect type)
      MIDI_OPL2            - OPL2 synth (mono, used in Adlib and SB)
      MIDI_2XOPL2          - dual OPL2 synths (stereo, used in
                             SB Pro-I)
      MIDI_OPL3            - OPL3 synth (stereo, SB Pro-II
                             and above)
      MIDI_SB_OUT          - SB MIDI interface
      MIDI_MPU             - MPU-401 MIDI interface
      MIDI_DIGMID          - sample-based software wavetable player
      MIDI_AWE32           - AWE32 (EMU8000 chip)
void split_modex_screen(int line);
This function is only available in mode-X. It splits the VGA display into two parts at the specified line. The top half of the screen can be scrolled to any part of video memory with the scroll_screen() function, but the part below the specified line number will remain fixed and will display from position (0, 0) of the screen bitmap. After splitting the screen you will generally want to scroll so that the top part of the display starts lower down in video memory, and then create two sub-bitmaps to access the two sections (see examples/exscroll.c for a demonstration of how this could be done). To disable the split, call split_modex_screen(0).

extern int i_love_bill;
When running in clean DOS mode, the timer handler dynamically reprograms the clock chip to generate interrupts at exactly the right times, which gives an extremely high accuracy. Unfortunately, this constant speed adjustment doesn't work under most multitasking systems (notably Windows), so there is an alternative mode that just locks the hardware timer interrupt to a speed of 200 ticks per second. This reduces the accuracy of the timer (for instance, rest() will round the delay time to the nearest 5 milliseconds), and prevents the vertical retrace simulator from working, but on the plus side, it makes Allegro programs work under Windows. This flag is set by allegro_init() if it detects the presence of a multitasking OS, and enables the fixed rate timer mode.


Windows specifics

  • blit_from_hdc
  • blit_to_hdc
  • convert_bitmap_to_hbitmap
  • convert_hbitmap_to_bitmap
  • convert_hpalette_to_palette
  • convert_palette_to_hpalette
  • DIGI_*/Windows
  • draw_to_hdc
  • GFX_*/Windows
  • MIDI_*/Windows
  • set_gdi_color_format
  • set_palette_to_hdc
  • stretch_blit_from_hdc
  • stretch_blit_to_hdc
  • win_get_dc
  • win_get_window
  • win_release_dc
  • win_set_window
  • win_set_wnd_create_proc

A Windows program that uses the Allegro library is only required to include one or more header files from the include/allegro tree, or allegro.h; however, if it also needs to directly call non portable Win32 API functions, it must include the Windows-specific header file winalleg.h after the Allegro headers, and before any Win32 API header file. By default winalleg.h includes the main Win32 C API header file windows.h. If instead you want to use the C++ interface to the Win32 API (a.k.a. the Microsoft Foundation Classes), define the preprocessor symbol ALLEGRO_AND_MFC before including any Allegro header so that afxwin.h will be included. Note that, in this latter case, the Allegro debugging macros ASSERT() and TRACE() are renamed AL_ASSERT() and AL_TRACE() respectively.

Windows GUI applications start with a WinMain() entry point, rather than the standard main() entry point. Allegro is configured to build GUI applications by default and to do some magic in order to make a regular main() work with them, but you have to help it out a bit by writing END_OF_MAIN() right after your main() function. If you don't want to do that, you can just include winalleg.h and write a WinMain() function. Note that this magic may bring about conflicts with a few programs using direct calls to Win32 API functions; for these programs, the regular WinMain() is required and the magic must be disabled by defining the preprocessor symbol ALLEGRO_NO_MAGIC_MAIN before including Allegro headers.

If you want to build a console application using Allegro, you have to define the preprocessor symbol USE_CONSOLE before including Allegro headers; it will instruct the library to use console features and also to disable the special processing of the main() function described above.

When creating the main window, Allegro searches the executable for an ICON resource named "allegro_icon". If it is present, Allegro automatically loads it and uses it as its application icon; otherwise, Allegro uses the default IDI_APPLICATION icon. See the manual of your compiler for a method to create an ICON resource, or use the wfixicon utility from the tools/win directory.

DirectX requires that system and video bitmaps (including the screen) be locked before you can draw onto them. This will be done automatically, but you can usually get much better performance by doing it yourself: see the acquire_bitmap() function for details.

Due to a major oversight in the design of DirectX, there is no way to preserve the contents of video memory when the user switches away from your program. You need to be prepared for the fact that your screen contents, and the contents of any video memory bitmaps, may be destroyed at any point. You can use the set_display_switch_callback() function to find out when this happens.

On the Windows platform, the only return values for the desktop_color_depth() function are 8, 16, 24 and 32. This means that 15-bit and 16-bit desktops cannot be differentiated and are both reported as 16-bit desktops. See below for the consequences for windowed and overlay DirectX drivers.

Drivers GFX_*/Windows
The Windows library supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    This closes any graphic mode previously opened with set_gfx_mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution or color depth you get. See the set_gfx_mode() documentation for details.

  • GFX_DIRECTX
    Alias for GFX_DIRECTX_ACCEL.

  • GFX_DIRECTX_ACCEL
    The regular fullscreen DirectX driver, running with hardware acceleration enabled.

  • GFX_DIRECTX_SOFT
    DirectX fullscreen driver that only uses software drawing, rather than any hardware accelerated features.

  • GFX_DIRECTX_SAFE
    Simplified fullscreen DirectX driver that doesn't support any hardware acceleration, video or system bitmaps, etc.

  • GFX_DIRECTX_WIN
    The regular windowed DirectX driver, running in color conversion mode when the color depth doesn't match that of the Windows desktop. Color conversion is much slower than direct drawing and is not supported between 15-bit and 16-bit color depths. This limitation is needed to work around that of desktop_color_depth() (see above) and allows to select the direct drawing mode in a reliable way on desktops reported as 16-bit:

       if (desktop_color_depth() == 16) {
      set_color_depth(16);
      if (set_gfx_mode(GFX_DIRECTX_WIN, 640, 480, 0, 0) != 0) {
         set_color_depth(15);
         if (set_gfx_mode(GFX_DIRECTX_WIN, 640, 480, 0, 0) != 0) {
            /* 640x480 direct drawing mode not supported */
            goto Error;
         }
      }
      /* ok, we are in direct drawing mode */
   }
    Note that, mainly for performance reasons, this driver requires the width of the screen to be a multiple of 4.

  • GFX_DIRECTX_OVL
    The DirectX overlay driver. It uses special hardware features to run your program in a windowed mode: it doesn't work on all hardware, but performance is excellent on cards that are capable of it. It requires the color depth to be the same as that of the Windows desktop. In light of the limitation of desktop_color_depth() (see above), the reliable way of setting the overlay driver on desktops reported as 16-bit is:

       if (desktop_color_depth() == 16) {
      set_color_depth(16);
      if (set_gfx_mode(GFX_DIRECTX_OVL, 640, 480, 0, 0) != 0) {
         set_color_depth(15);
         if (set_gfx_mode(GFX_DIRECTX_OVL, 640, 480, 0, 0) != 0) {
            /* 640x480 overlay driver not supported */
            goto Error;
         }
      }
      /* ok, the 640x480 overlay driver is running */
   }

  • GFX_GDI
    The windowed GDI driver. It is extremely slow, but is guaranteed to work on all hardware, so it can be useful for situations where you want to run in a window and don't care about performance. Note that this driver features a hardware mouse cursor emulation in order to speed up basic mouse operations (like GUI operations).

Drivers DIGI_*/Windows
The Windows sound functions support the following digital soundcards:

      DIGI_AUTODETECT      - let Allegro pick a digital sound driver
      DIGI_NONE            - no digital sound
      DIGI_DIRECTX(n)      - use DirectSound device #n (zero-based) with
                             direct mixing
      DIGI_DIRECTAMX(n)    - use DirectSound device #n (zero-based) with
                             Allegro mixing
      DIGI_WAVOUTID(n)     - high (n=0) or low (n=1) quality WaveOut device
Drivers MIDI_*/Windows
The Windows sound functions support the following MIDI soundcards:

      MIDI_AUTODETECT      - let Allegro pick a MIDI sound driver
      MIDI_NONE            - no MIDI sound
      MIDI_WIN32MAPPER     - use win32 MIDI mapper
      MIDI_WIN32(n)        - use win32 device #n (zero-based)
      MIDI_DIGMID          - sample-based software wavetable player

The following functions provide a platform specific interface to seamlessly integrate Allegro into general purpose Win32 programs. To use these routines, you must include winalleg.h after other Allegro headers.

HWND win_get_window(void);
Retrieves a handle to the window used by Allegro. Note that Allegro uses an underlying window even though you don't set any graphics mode, unless you have installed the neutral system driver (SYSTEM_NONE).

void win_set_window(HWND wnd);
Registers an user-created window to be used by Allegro. This function is meant to be called before initialising the library with allegro_init() or installing the autodetected system driver (SYSTEM_AUTODETECT). It lets you attach Allegro to any already existing window and prevents the library from creating its own, thus leaving you total control over the window; in particular, you are responsible for processing the events as usual (Allegro will automatically monitor a few of them, but will not filter out any of them). You can then use every component of the library (mouse, keyboard, sound, timers and so on) except the graphics subsystem, bearing in mind that some Allegro functions are blocking (e.g readkey() if the key buffer is empty) and thus must be carefully manipulated by the window thread.

However you can also call it after the library has been initialised, provided that no graphics mode is set. In this case the keyboard, mouse, sound and sound recording modules will be restarted.

Passing NULL instructs Allegro to switch back to its built-in window if an user-created window was registered, or to request a new handle from Windows for its built-in window if this was already in use.

void win_set_wnd_create_proc(HWND (*proc)(WNDPROC));
Registers an user-defined procedure to be used by Allegro for creating its window. This function must be called *before* initializing the library with allegro_init() or installing the autodetected system driver (SYSTEM_AUTODETECT). It lets you customize Allegro's window but only by its creation: unlike with win_set_window(), you have no control over the window once it has been created (in particular, you are not responsible for processing the events). The registered function will be passed a window procedure (WNDPROC object) that it must make the procedure of the new window of and it must return a handle to the new window. You can then use the full-featured library in the regular way.

HDC win_get_dc(BITMAP *bmp);
Retrieves a handle to the device context of a DirectX video or system bitmap.

void win_release_dc(BITMAP *bmp, HDC dc);
Releases a handle to the device context of the bitmap that was previously retrieved with win_get_dc().

The following GDI routines are a very platform specific thing, to allow drawing Allegro memory bitmaps onto a Windows device context. When you want to use this, you'll have to install the neutral system driver (SYSTEM_NONE) or attach Allegro to an external window with win_set_window().

There are two ways to draw your Allegro bitmaps to the Windows GDI. When you are using static bitmaps (for example just some pictures loaded from a datafile), you can convert them to DDB (device-dependent bitmaps) with convert_bitmap_to_hbitmap() and then just use Win32's BitBlt() to draw it.

When you are using dynamic bitmaps (for example some things which react to user input), it's better to use set_palette_to_hdc() and blit_to_hdc() functions, which work with DIB (device-independent bitmaps).

There are also functions to blit from a device context into an Allegro BITMAP, so you can do things like screen capture.

All the drawing and conversion functions use the current palette as a color conversion table. You can alter the current palette with the set_palette_to_hdc() or select_palette() functions. Warning: when the GDI system color palette is explicitly changed, (by another application, for example) the current Allegro palette is not updated along with it!

To use these routines, you must include winalleg.h after Allegro headers.

void set_gdi_color_format(void);
Tells Allegro to use the GDI color layout for truecolor images. This is optional, but it will make the conversions work faster. If you are going to call this, you should do it right after initialising Allegro and before creating any graphics.

void set_palette_to_hdc(HDC dc, PALETTE pal);
Selects and realizes an Allegro palette on the specified device context.

HPALETTE convert_palette_to_hpalette(PALETTE pal);
Converts an Allegro palette to a Windows palette and returns a handle to it. You should call DeleteObject() when you no longer need it.

void convert_hpalette_to_palette(HPALETTE hpal, PALETTE pal);
Converts a Windows palette to an Allegro palette.

HBITMAP convert_bitmap_to_hbitmap(BITMAP *bitmap);
Converts an Allegro memory bitmap to a Windows DDB and returns a handle to it. This bitmap uses its own memory, so you can destroy the original bitmap without affecting the converted one. You should call DeleteObject() when you no longer need this bitmap.

BITMAP *convert_hbitmap_to_bitmap(HBITMAP bitmap);
Creates an Allegro memory bitmap from a Windows DDB.

void draw_to_hdc(HDC dc, BITMAP *bitmap, int x, int y);
Draws an entire Allegro bitmap to a Windows device context, using the same parameters as the draw_sprite() function.

void blit_to_hdc(BITMAP *bitmap, HDC dc, int sx, sy, dx, dy, w, h);
Blits an Allegro memory bitmap to a Windows device context, using the same parameters as the blit() function.

void stretch_blit_to_hdc(BITMAP *bitmap, HDC dc, int sx, sy, sw, sh, int dx, dy, dw, dh);
Blits an Allegro memory bitmap to a Windows device context, using the same parameters as the stretch_blit() function.

void blit_from_hdc(HDC hdc, BITMAP *bitmap, int sx, sy, dx, dy, w, h);
Blits from a Windows device context to an Allegro memory bitmap, using the same parameters as the blit() function. See stretch_blit_from_hdc() for details.

void stretch_blit_from_hdc(HDC hcd, BITMAP *bitmap, int sx, sy, sw, sh, int dx, dy, dw, dh);
Blits from a Windows device context to an Allegro memory bitmap, using the same parameters as the stretch_blit() function. It uses the current Allegro palette and does conversion to this palette, regardless of the current DC palette. So if you are blitting from 8 bit mode, you should first set the DC palette with the set_palette_to_hdc() function.


Unix specifics

  • DIGI_*/Unix
  • GFX_*/Linux
  • GFX_*/X
  • MIDI_*/Unix

In order to locate things like the config and translation files, Allegro needs to know the path to your executable. Since there is no standard way to find that, it needs to capture a copy of your argv[] parameter, and it does this with some preprocessor macro trickery. Unfortunately it can't quite pull this off without a little bit of your help, so you will have to write END_OF_MAIN() right after your main() function. Pretty easy, really, and if you forget, you'll get a nice linker error about a missing _mangled_main function to remind you :-)

Drivers GFX_*/Linux
When running in Linux console mode, Allegro supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    Return to text mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers. This will always fail under Linux console mode.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution or color depth you get. See the set_gfx_mode() documentation for details.

  • GFX_FBCON
    Use the framebuffer device (eg. /dev/fb0). This requires you to have framebuffer support compiled into your kernel, and correctly configured for your hardware. It is currently the only console mode driver that will work without root permissions, unless you are using a development version of SVGAlib.

  • GFX_VBEAF
    Use a VBE/AF driver (vbeaf.drv), assuming that you have installed one which works under Linux (currently only two of the FreeBE/AF project drivers are capable of this: I don't know about the SciTech ones). VBE/AF requires root permissions, but is currently the only Linux driver which supports hardware accelerated graphics.

  • GFX_SVGALIB
    Use the SVGAlib library for graphics output. This requires root permissions if your version of SVGAlib requires them.

  • GFX_VGA
    GFX_MODEX
    Use direct hardware access to set standard VGA or mode-X resolutions, supporting the same modes as in the DOS versions of these drivers. Requires root permissions.

Drivers GFX_*/X
When running in X mode, Allegro supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    This closes any graphic mode previously opened with set_gfx_mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution or color depth you get. See the set_gfx_mode() documentation for details.

  • GFX_XWINDOWS
    The standard X graphics driver. This should work on any Unix system, and can operate remotely. It does not require root permissions.

  • GFX_XWINDOWS_FULLSCREEN
    The same as above, but while GFX_XWINDOWS runs windowed, this one uses the XF86VidMode extension to make it run in fullscreen mode even without root permissions. You're still using the standard X protocol though, so expect the same low performances as with the windowed driver version.

  • GFX_XDGA
    Use the XFree86 DGA 1.0 extension to write directly to the screen surface. DGA is normally much faster than the standard X mode, but does not produce such well behaved windowed programs, and will not work remotely. This driver requires root permissions.

  • GFX_XDGA_FULLSCREEN
    Like GFX_XDGA, but also changes the screen resolution so that it will run fullscreen. This driver requires root permissions.

  • GFX_XDGA2
    Use new DGA 2.0 extension provided by XFree86 4.0.x. This will work in fullscreen mode, and it will support hardware acceleration if available. This driver requires root permissions.

  • GFX_XDGA2_SOFT
    The same as GFX_XDGA2, but turns off hardware acceleration support. This driver requires root permissions.

Drivers DIGI_*/Unix
The Unix sound functions support the following digital soundcards:

      DIGI_AUTODETECT      - let Allegro pick a digital sound driver
      DIGI_NONE            - no digital sound
      DIGI_OSS             - Open Sound System
      DIGI_ESD             - Enlightened Sound Daemon
      DIGI_ARTS            - aRts (Analog Real-Time Synthesizer)
      DIGI_ALSA            - ALSA sound driver
Drivers MIDI_*/Unix
The Unix sound functions support the following MIDI soundcards:

      MIDI_AUTODETECT      - let Allegro pick a MIDI sound driver
      MIDI_NONE            - no MIDI sound
      MIDI_OSS             - Open Sound System
      MIDI_DIGMID          - sample-based software wavetable player
      MIDI_ALSA            - ALSA RawMIDI driver


BeOS specifics

  • DIGI_*/BeOS
  • GFX_*/BeOS
  • MIDI_*/BeOS

Drivers GFX_*/BeOS
BeOS Allegro supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    This closes any graphic mode previously opened with set_gfx_mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution. See the set_gfx_mode() documentation for details.

  • GFX_BEOS_FULLSCREEN
    Fullscreen exclusive mode. Supports only resolutions higher or equal to 640x480, and uses hardware acceleration if available.

  • GFX_BEOS_FULLSCREEN_SAFE
    Works the same as GFX_FULLSCREEN, but disables acceleration.

  • GFX_BEOS_WINDOWED
    Fast windowed mode using the BDirectWindow class. Not all graphics cards support this.

Drivers DIGI_*/BeOS
The BeOS sound functions support the following digital soundcards:

      DIGI_AUTODETECT      - let Allegro pick a digital sound driver
      DIGI_NONE            - no digital sound
      DIGI_BEOS            - BeOS digital output
Drivers MIDI_*/BeOS
The BeOS sound functions support the following MIDI soundcards:

      MIDI_AUTODETECT      - let Allegro pick a MIDI sound driver
      MIDI_NONE            - no MIDI sound
      MIDI_BEOS            - BeOS MIDI output
      MIDI_DIGMID          - sample-based software wavetable player


QNX specifics

  • DIGI_*/QNX
  • GFX_*/QNX
  • MIDI_*/QNX
  • qnx_get_window

Drivers GFX_*/QNX
QNX Allegro supports the following card parameters for the set_gfx_mode() function:

  • GFX_TEXT
    This closes any graphic mode previously opened with set_gfx_mode.

  • GFX_AUTODETECT
    Let Allegro pick an appropriate graphics driver.

  • GFX_AUTODETECT_FULLSCREEN
    Autodetects a graphics driver, but will only use fullscreen drivers, failing if these are not available on current platform.

  • GFX_AUTODETECT_WINDOWED
    Same as above, but uses only windowed drivers.

  • GFX_SAFE
    Special driver for when you want to reliably set a graphics mode and don't really care what resolution. See the set_gfx_mode() documentation for details.

  • GFX_PHOTON_DIRECT
    Fullscreen exclusive mode through Photon.

  • GFX_PHOTON
    Windowed mode in a Photon window. Note that, mainly for performance reasons, this driver requires the width of the screen to be a multiple of 4.

Drivers DIGI_*/QNX
The QNX sound functions support the following digital soundcards:

      DIGI_AUTODETECT      - let Allegro pick a digital sound driver
      DIGI_NONE            - no digital sound
      DIGI_ALSA            - ALSA sound driver
Drivers MIDI_*/QNX
The QNX sound functions support the following MIDI soundcards:

      MIDI_AUTODETECT      - let Allegro pick a MIDI sound driver
      MIDI_NONE            - no MIDI sound
      MIDI_ALSA            - ALSA RawMIDI driver
      MIDI_DIGMID          - sample-based software wavetable player

The following functions provide a platform specific interface to seamlessly integrate Allegro into general purpose QNX programs. To use these routines, you must include qnxalleg.h after other Allegro headers.

PtWidget_t qnx_get_window(void);
Retrieves a handle to the window used by Allegro. Note that Allegro uses an underlying window even though you don't set any graphics mode, unless you have installed the neutral system driver (SYSTEM_NONE).


Differences between platforms

Here's a quick summary of things that may cause problems when moving your code from one platform to another (you can find a more detailed version of this in the docs section of the Allegro website).

The Windows and Unix versions require you to write END_OF_MAIN() after your main() function, which is used to magically turn an ANSI C style main() into a Windows style WinMain(), and so that the Unix code can grab a copy of your argv[] parameter.

On many platforms Allegro runs very slowly if you rely on it in order to automatically lock bitmaps when drawing onto them. For good performance, you need to call acquire_bitmap() and release_bitmap() yourself, and try to keep the amount of locking to a minimum.

The Windows version may lose the contents of video memory if the user switches away from your program, so you need to deal with that.

None of the currently supported platforms require input polling, but it is possible that some future ones might, so if you want to ensure 100% portability of your program, you should call poll_mouse() and poll_keyboard() in all the relevant places.

Allegro defines a number of standard macros that can be used to check various attributes of the current platform:

ALLEGRO_PLATFORM_STR
Text string containing the name of the current platform.

ALLEGRO_DOS
ALLEGRO_DJGPP
ALLEGRO_WATCOM
ALLEGRO_WINDOWS
ALLEGRO_MSVC
ALLEGRO_MINGW32
ALLEGRO_BCC32
ALLEGRO_UNIX
ALLEGRO_LINUX
ALLEGRO_BEOS
ALLEGRO_QNX
ALLEGRO_GCC
Defined if you are building for a relevant system. Often several of these will apply, eg. DOS+Watcom, or Windows+GCC+MinGW32.

ALLEGRO_I386
ALLEGRO_BIG_ENDIAN
ALLEGRO_LITTLE_ENDIAN
Defined if you are building for a processor of the relevant type.

ALLEGRO_VRAM_SINGLE_SURFACE
Defined if the screen is a single large surface that is then partitioned into multiple video sub-bitmaps (eg. DOS), rather than each video bitmap being a totally unique entity (eg. Windows).

ALLEGRO_CONSOLE_OK
Defined if when you are not in a graphics mode, there is a text mode console that you can printf() to, and from which the user could potentially redirect stdout to capture it even while you are in a graphics mode. If this define is absent, you are running in an environment like Windows that has no stdout at all.

ALLEGRO_MAGIC_MAIN
Defined if Allegro uses a magic main, i.e takes over the main() entry point and turns it into a secondary entry point suited to its needs.

ALLEGRO_LFN
Non-zero if long filenames are supported, or zero if you are limited to 8.3 format (in the djgpp version, this is a variable depending on the runtime environment).

LONG_LONG
Defined to whatever represents a 64-bit "long long" integer for the current compiler, or not defined if that isn't supported.

OTHER_PATH_SEPARATOR
Defined to a path separator character other than a forward slash for platforms that use one (eg. a backslash under DOS and Windows), or defined to a forward slash if there is no other separator character.

DEVICE_SEPARATOR
Defined to the filename device separator character (a colon for DOS and Windows), or to zero if there are no explicit devices in paths (Unix).

Allegro also defines a number of standard macros that can be used to insulate you from some of the differences between systems:

USE_CONSOLE
If you define this prior to including Allegro headers, Allegro will be set up for building a console application rather than the default GUI program on some platforms (especially Windows).

INLINE
Use this in place of the regular "inline" function modifier keyword, and your code will work correctly on any of the supported compilers.

ZERO_SIZE_ARRAY(type, name)
Use this to declare zero-sized arrays in terminal position inside structures, like in the BITMAP structure. These arrays are effectively equivalent to the flexible array members of ISO C99.


Reducing your executable size

Some people complain that Allegro produces very large executables. This is certainly true: with the djgpp version, a simple "hello world" program will be about 200k, although the per-executable overhead is much less for platforms that support dynamic linking. But don't worry, Allegro takes up a relatively fixed amount of space, and won't increase as your program gets larger. As George Foot so succinctly put it, anyone who is concerned about the ratio between library and program code should just get to work and write more program code to catch up :-)

Having said that, there are several things you can do to make your programs smaller:

  • For all platforms, you can use an executable compressor called UPX, which is available at http://upx.tsx.org/ . This usually manages a compression ratio of about 40%.

  • When using djgpp: for starters, read the djgpp FAQ section 8.14, and take note of the -s switch. And don't forget to compile your program with optimisation enabled!

  • If a DOS program is only going to run in a limited number of graphics modes, you can specify which graphics drivers you would like to include with the code:

       BEGIN_GFX_DRIVER_LIST
      driver1
      driver2
      etc...
   END_GFX_DRIVER_LIST
    where the driver names are any of the defines:

       GFX_DRIVER_VBEAF
   GFX_DRIVER_VGA
   GFX_DRIVER_MODEX
   GFX_DRIVER_VESA3
   GFX_DRIVER_VESA2L
   GFX_DRIVER_VESA2B
   GFX_DRIVER_XTENDED
   GFX_DRIVER_VESA1
    This construct must be included in only one of your C source files. The ordering of the names is important, because the autodetection routine works down from the top of the list until it finds the first driver that is able to support the requested mode. I suggest you stick to the default ordering given above, and simply delete whatever entries you aren't going to use.

  • If your DOS program doesn't need to use all the possible color depths, you can specify which pixel formats you want to support with the code:

       BEGIN_COLOR_DEPTH_LIST
      depth1
      depth2
      etc...
   END_COLOR_DEPTH_LIST
    where the color depth names are any of the defines:

       COLOR_DEPTH_8
   COLOR_DEPTH_15
   COLOR_DEPTH_16
   COLOR_DEPTH_24
   COLOR_DEPTH_32
    Removing any of the color depths will save quite a bit of space, with the exception of the 15 and 16 bit modes: these share a great deal of code, so if you are including one of them, there is no reason not to use both. Be warned that if you try to use a color depth which isn't in this list, your program will crash horribly!

  • In the same way as the above, you can specify which DOS sound drivers you want to support with the code:

       BEGIN_DIGI_DRIVER_LIST
      driver1
      driver2
      etc...
   END_DIGI_DRIVER_LIST
    using the digital sound driver defines:

       DIGI_DRIVER_SOUNDSCAPE
   DIGI_DRIVER_AUDIODRIVE
   DIGI_DRIVER_WINSOUNDSYS
   DIGI_DRIVER_SB
    and for the MIDI music:

       BEGIN_MIDI_DRIVER_LIST
      driver1
      driver2
      etc...
   END_MIDI_DRIVER_LIST
    using the MIDI driver defines:

       MIDI_DRIVER_AWE32
   MIDI_DRIVER_DIGMID
   MIDI_DRIVER_ADLIB
   MIDI_DRIVER_MPU
   MIDI_DRIVER_SB_OUT
    If you are going to use either of these sound driver constructs, you must include both.

  • Likewise for the DOS joystick drivers, you can declare an inclusion list:

       BEGIN_JOYSTICK_DRIVER_LIST
      driver1
      driver2
      etc...
   END_JOYSTICK_DRIVER_LIST
    using the joystick driver defines:

       JOYSTICK_DRIVER_WINGWARRIOR
   JOYSTICK_DRIVER_SIDEWINDER
   JOYSTICK_DRIVER_GAMEPAD_PRO
   JOYSTICK_DRIVER_GRIP
   JOYSTICK_DRIVER_STANDARD
   JOYSTICK_DRIVER_SNESPAD
   JOYSTICK_DRIVER_PSXPAD
   JOYSTICK_DRIVER_N64PAD
   JOYSTICK_DRIVER_DB9
   JOYSTICK_DRIVER_TURBOGRAFX
   JOYSTICK_DRIVER_IFSEGA_ISA
   JOYSTICK_DRIVER_IFSEGA_PCI
   JOYSTICK_DRIVER_IFSEGA_PCI_FAST
    The standard driver includes support for the dual joysticks, increased numbers of buttons, Flightstick Pro, and Wingman Extreme, because these are all quite minor variations on the basic code.

  • If you are _really_ serious about this size, thing, have a look at the top of include/allegro/alconfig.h and you will see the lines:

       #define ALLEGRO_COLOR8
   #define ALLEGRO_COLOR16
   #define ALLEGRO_COLOR24
   #define ALLEGRO_COLOR32
    If you comment out any of these definitions and then rebuild the library, you will get a version without any support for the absent color depths, which will be even smaller than using the DECLARE_COLOR_DEPTH_LIST() macro. Removing the ALLEGRO_COLOR16 define will get rid of the support for both 15 and 16 bit hicolor modes, since these share a lot of the same code.

Note: the aforementioned methods for removing unused hardware drivers only apply to statically linked versions of the library, eg. DOS. On Windows and Unix platforms, you can build Allegro as a DLL or shared library, which prevents these methods from working, but saves so much space that you probably won't care about that. Removing unused color depths from alconfig.h will work on any platform, though.

If you are distributing a copy of the setup program along with your game, you may be able to get a dramatic size reduction by merging the setup code into your main program, so that only one copy of the Allegro routines will need to be linked. See setup.txt for details. In the djgpp version, after compressing the executable, this will probably save you about 200k compared to having two separate programs for the setup and the game itself.


Debugging

  • al_assert
  • al_trace
  • ASSERT
  • register_assert_handler
  • register_trace_handler
  • TRACE

There are three versions of the Allegro library: the normal optimised code, one with extra debugging support, and a profiling version. See the platform specific readme files for information about how to install and link with these alternative libs. Although you will obviously want to use the optimised library for the final version of your program, it can be very useful to link with the debug lib while you are working on it, because this will make debugging much easier, and includes assert tests that will help to locate errors in your code at an earlier stage. Allegro also contains some debugging helper functions:

void al_assert(const char *file, int line);
Raises an assert for an error at the specified file and line number. The file parameter is always given in ASCII format. If you have installed a custom assert handler it uses that, or if the environment variable ALLEGRO_ASSERT is set it writes a message into the file specified by the environment, otherwise it aborts the program with an error message. You will usually want to use the ASSERT() macro instead of calling this function directly.

void al_trace(const char *msg, ...);
Outputs a debugging trace message, using a printf() format string given in ASCII. If you have installed a custom trace handler it uses that, or if the environment variable ALLEGRO_TRACE is set it writes into the file specified by the environment, otherwise it writes the message to "allegro.log" in the current directory. You will usually want to use the TRACE() macro instead of calling this function directly.

void ASSERT(condition);
Debugging helper macro. Normally compiles away to nothing, but if you defined the preprocessor symbol DEBUGMODE before including Allegro headers, it will check the supplied condition and call al_assert() if it fails.

void TRACE(char *msg, ...);
Debugging helper macro. Normally compiles away to nothing, but if you defined the preprocessor symbol DEBUGMODE before including Allegro headers, it passes the supplied message given in ASCII format to al_trace().

void register_assert_handler(int (*handler)(const char *msg));
Supplies a custom handler function for dealing with assert failures. Your callback will be passed a formatted error message in ASCII, and should return non-zero if it has processed the error, or zero to continue with the default actions. You could use this to ignore assert failures, or to display the error messages on a graphics mode screen without aborting the program.

void register_trace_handler(int (*handler)(const char *msg));
Supplies a custom handler function for dealing with trace output. Your callback will be passed a formatted error message in ASCII, and should return non-zero if it has processed the message, or zero to continue with the default actions. You could use this to ignore trace output, or to display the messages on a second monochrome monitor, etc.


Makefile targets

There are a number of options that you can use to control exactly how Allegro will be compiled. On Unix platforms you do this by passing arguments to the configure script (run "configure --help" for a list), but on other platforms you can set the environment variables:

  • DEBUGMODE=1
    Selects a debug build, rather than the normal optimised version.

  • DEBUGMODE=2
    Selects a build intended to debug Allegro itself, rather than the normal optimised version.

  • PROFILEMODE=1
    Selects a profiling build, rather than the normal optimised version.

  • WARNMODE=1
    Selects strict compiler warnings. If you are planning to work on Allegro yourself, rather than just using it in your programs, you should be sure to have this mode enabled.

  • STATICLINK=1 (MSVC and Mingw32 only)
    Link as a static library, rather than the default DLL.

  • TARGET_ARCH_COMPAT=[cpu] (implemented for most GNU platforms)
    This option will optimize for the given processor while maintaining compatibility with older processors. Example: set TARGET_ARCH_COMPAT=i586

  • TARGET_ARCH_EXCL=[cpu] (implemented for most GNU platforms)
    This option will optimize for the given processor. Please note that using it will cause the code to *NOT* run on older processors. Example: set TARGET_ARCH_EXCL=i586

  • TARGET_OPTS=[opts] (implemented for most GNU platforms)
    This option allows you to customize general compiler optimisations.

  • CROSSCOMPILE=1 (djgpp only)
    Allows you to build the djgpp library under Linux, using djgpp as a cross-compiler.

  • ALLEGRO_USE_C=1 (djgpp only)
    Allows you to build the djgpp library using C drawing code instead of the usual asm routines. This is only really useful for testing, since the asm version is faster.

If you only want to recompile a specific test program or utility, you can specify it as an argument to make, eg. "make demo" or "make grabber". The makefiles also provide some special pseudo-targets:

  • 'default'
    The normal build process. Compiles the current library version (one of optimised, debugging, or profiling, selected by the above environment variables), builds the test and example programs, and converts the documentation files.

  • 'all'
    Compiles all three library versions (optimised, debugging, and profiling), builds the test and example programs, and converts the documentation files.

  • 'lib'
    Compiles the current library version (one of optimised, debugging, or profiling, selected by the above environment variables).

  • 'install'
    Copies the current library version (one of optimised, debugging, or profiling, selected by the above environment variables), into your compiler lib directory, recompiling it as required, and installs the Allegro headers.

  • 'installall'
    Copies all three library versions (optimised, debugging, and profiling), into your compiler lib directory, recompiling them as required, and installs the Allegro headers.

  • 'uninstall'
    Removes the Allegro library and headers from your compiler directories.

  • 'docs'
    Converts the documentation files from the ._tx sources.

  • 'docs-dvi' (Unix only)
    Creates the allegro.dvi device independent documentation file. This is not a default target, since you need the texi2dvi tool to create it. The generated file is especially prepared to be printed on paper.

  • 'docs-ps' or 'docs-gzipped-ps' (Unix only)
    Creates a Postcript file from the previously generated DVI file. This is not a default target, since you need the texi2dvi and dvips tools to create it. The second target compresses the generated Postscript file. The generated file is especially prepared to be printed on paper.

  • 'install-man' or 'install-gzipped-man' (Unix only)
    This generates Unix man pages for each Allegro function or variable and installs them. The second target compresses the manual pages after installing them.

  • 'install-info' or 'install-gzipped-info' (Unix only)
    Converts the documentation to Info format and installs it. The second target compresses the info file after installing it.

  • 'clean'
    Removes generated object and library files, either to recover disk space or to force a complete rebuild the next time you run make. This target is designed so that if you run a "make install" followed by "make clean", you will still have a functional version of Allegro.

  • 'distclean'
    Like "make clean", but more so. This removes all the executable files and the documentation, leaving you with only the same files that are included when you unzip a new Allegro distribution.

  • 'veryclean'
    Use with extreme caution! This target deletes absolutely all generated files, including some that may be non-trivial to recreate. After you run "make veryclean", a simple rebuild will not work: at the very least you will have to run "make depend", and perhaps also fixdll.bat if you are using the Windows library. These targets make use of non-standard tools like SED, so unless you know what you are doing and have all this stuff installed, you should not use them.

  • 'depend'
    Regenerates the dependency files (obj/*/makefile.dep). You need to run this after "make veryclean", or whenever you add new headers to the Allegro sources.

  • 'compress' (djgpp, Mingw32 and MSVC only)
    Uses the DJP or UPX executable compressors (whichever you have installed) to compress the example executables and utility programs, which can recover a significant amount of disk space.


Allegro Changes

Changes from 4.0.2 to 4.0.3 (Apr 2003)

  • Many minor changes and clarifications in the docs.

  • Eric Botcazou fixed the profile build on BeOS.

  • Eric Botcazou updated the FAQ about DJGPP's va_list problem (thanks to aj for spotting this).

  • Andrei Ellman suggested some additions to the docs.

  • Eric Botcazou added makeinfo detection under Unix.

  • Ville Skyttä fixed a problem with make install libdir= and modules on Unix systems.

  • Peter Wang added a hack to not unload the SVGAlib module if SVGAlib installs an atexit() handler.

  • Grzegorz Adam Hankiewicz corrected broken chapter references emitted by the doc processor.

  • Grzegorz Adam Hankiewicz documented the END_OF_MAIN macro.

  • Eric Botcazou added big-endian support to the BMP, PCX and TGA loaders as well as to the X11 driver.

  • Eric Botcazou fixed the 'uninstall' target and a problem with Mingw32's make for the Watcom port.

  • Annie Testes fixed a bug with asynchronous I/O mode restoring under Linux.

  • Annie Testes made the screen be cleared before setting the default palette when calling set_gfx_mode().

  • Annie Testes fixed a bug with patterned drawing in the C version.

  • Vincent Penquerc'h spotted an off-by-one problem when building the list of color depths in the gfx mode selector.

  • Peter Wang made the Intellimouse PS/2 driver work for USB mice in Linux.

  • Oscar Giner fixed a conflict between the magic main and the MFC.

  • Matthew Leverton fixed a bug with pack_fgets().

  • Eric Botcazou fixed broken and missing dependencies for make -j2 builds.

  • Grzegorz Adam Hankiewicz backported his email address mangling code from 4.1.x for inclusion in makedoc.

  • Hein Zelle revamped the cross-compilation section of docs/build/mingw32.txt.

  • Marcel Smit and Eric Botcazou made the show_video_bitmap() method of the Windows windowed driver wait for a vsync.

  • Eric Botcazou made the test program really time the fixed math functions.

  • Eric Botcazou clarified the limitations of Allegro's interrupts regarding the FPU state under DOS.

  • Peter Wang fixed a bug in stretch_blit() where the first column or row can get an extra pixel, reported by David Gowers and AJ.

  • Eric Botcazou made the linux mouse detection code really empty the buffer before proceeding in the setup program.

  • Eric Botcazou made the Watcom port compile in warnmode with Open Watcom.

  • Elias Pschernig fixed the build with the Unix->MinGW cross-compiler.

  • Magnus Henoch made the gfx mode selector keep the current selection as much as possible.

  • Henrik Stokseth merged the standard and extended gfx mode selectors.

  • Eric Botcazou added -Wstrict-prototypes to the build warnmode under DOS, Windows and BeOS.

  • Philipp Thomas added the German translation to the RPM spec file.

  • Philipp Thomas fixed all function prototypes, thus allowing to build with -Wstrict-prototypes on Unix systems.

  • Philipp Thomas fixed the compilation on x86-64.

  • Philipp Thomas fixed all comparisons between signed and unsigned types, thus allowing to build with -W -Wno-unused on Unix systems.

  • Eric Botcazou reworked the truecolor subsection of the 'Transparency and patterned drawing' section.

  • Eric Botcazou clarified the return value on failure of file_time(), following AJ's suggestion.

  • Eric Botcazou fixed the build in strictwarn mode on Unix systems.

  • Peter Wang added an aRts driver to the Unix port.

  • Eric Botcazou fixed a mouse bug when the screen is scrolled with the X11 fullscreen driver.

  • Eric Botcazou fixed a bug with resolution and color depth not being taken into account by gfx_mode_select_ex().

  • Eric Botcazou defined ALLEGRO_LIB_BUILD for debug and profile releases as well on Unix systems.

  • Eric Botcazou forced the exstream example to abort if no real sound driver is found.

  • Eric Botcazou clarified the limitations of the stretching functions.

  • Eric Botcazou re-enabled the autodetection of joysticks in the setup program.

  • Annie Testes fixed some device name strings in the setup program.

  • Eric Botcazou disabled hackish centering code in fullscreen mode under X11 which caused some artifacts to appear on KDE desktops.

  • Eric Botcazou fixed a bug with Alt+TAB under X11.

  • Eric Botcazou added a configure check for the include prefix problem with gcc 3.1 or later on Unix systems.

  • Matt Witherspoon and Eric Botcazou fixed a bug in the scroll() method of the Linux SVGAlib driver so as to make it wait for the vertical retrace.

  • Ben Davis documented the non-standard behaviour of pack_feof().

  • Eric Botcazou worked around a weird problem with some X11 window managers that prevented the fullscreen driver from setting up.

  • Grzegorz Adam Hankiewicz added a warning about DJGPP stability under some Windows versions.

  • Eric Botcazou made it so that the window is centered at startup under Windows.

  • Chris Jones and Eric Botcazou worked around a problem with DOS file attributes under Win2k.

  • Eric Botcazou made the filetest work better with the keyboard.

  • Elias Pschernig added support to use the saved window position for initial window placing under Windows.

  • Eric Botcazou fixed the mishandling of TAB characters in menu bar entries.

  • Elias Pschernig optimized the load_bitmap() function family when no palette is specified and documented the feature.

  • Eric Botcazou added a new DEBUGMODE level so that debuggers will not be flooded by internal debug messages any more under Windows.

  • Grzegorz Adam Hankiewicz improved the internationalization of the close button message.

  • Thomas Klausner added NetBSD detection.

  • Ben Davis constified the parameter of set_window_title().

  • Lisa Parratt added IRIX detection.

  • Robert J. Ohannessian clarified the docs for play_audio_stream().

  • Eric Botcazou fixed a buffer overflow in the Windows debug version spotted by aj.

  • Eric Botcazou fixed the compile-time check for the MMX asm support.

  • Eric Botcazou fixed the non-MMX asm color copy routine.

  • Grzegorz Adam Hankiewicz added informations on the FLI format provided by Kronoman X to the FAQ.

  • Eric Botcazou added the support for plugin scripts to the MinGW port.

  • Matthew Leverton added the detection of left-hand mouse configuration under Windows.

  • Eric Botcazou fixed a crash when Alt+Tabbing under WinXP.

  • Grzegorz Adam Hankiewicz updated the docs about mailing lists/contacts.

  • Grzegorz Adam Hankiewicz added instructions on how to create and submit patches to the Allegro developers.

  • Lisa Parratt spotted a BSDism that IRIX doesn't like at all.

  • Eric Botcazou fixed a bug in scare_mouse_area().

  • Elias Pschernig added the Euro character to the default font and to the German and French keyboard configuration files.

  • Eric Botcazou prevented set_gfx_mode() from resetting the layout of all color depths.

  • Oscar Giner added the Catalan translation.

  • Oscar Giner corrected the Spanish translation.

  • Eric Botcazou prevented the linker from choking on Solaris because of a static library with no symbols.

  • Eric Botcazou removed joystick control from main part of the setup program.

  • Eric Botcazou documented the workaround needed for C++ programs compiled with Borland C++ (in docs/build/bcc32.txt).

  • Eric Botcazou unified the magic main for the 3 Windows compilers and fixed the WinMain() linkage for Borland C++.

  • Henrik Schmidt made gcc pass '-h' instead of '-soname' to the linker and replaced '-L' by '-h' in shell comparisons so as not to break on Solaris.

  • Javier Gonzalez and Eric Botcazou fixed the infamous blank screen problem under Win2k/WinXP.

  • Evert Glebbeek added configure options for x86 processor optimizations on Unix systems.

  • Benny Colyn added the Dutch translation.

  • Evert Glebbeek added the detection of SunOS/Solaris.

  • Javier Gonzalez fixed a graphics bug with always-on-top applications.

  • Igor Gnip added the detection of MSYS via the SHELL variable to the MingW32 port.

  • Eric Botcazou fixed a bug than had prevented ALT+F4 from being properly handled under Windows and cleaned up the low-level scancode handler.

  • Eric Botcazou updated the description of the layout of header files in the aHack file.

  • Grzegorz Adam Hankiewicz corrected the docs about 'ulimit' in the Help file.

  • Peter Wang made fix.sh and zipup.sh not destroy timestamps when just changing EOL markers.

  • Robert J. Ohannessian added more caveats to docs/build/mingw32.txt.

  • Eric Botcazou modified the querying of DirectSound devices under Windows.

  • Evert Glebbeek added a '-fullscreen' switch to the grabber, Laurence Withers a '-windowed' switch.

  • Daniel Schlydler fixed problems with get_executable_name() under Windows.

  • Eric Botcazou added a FAQ entry on the C++ headers problem with gcc 3.x and Mingw32, summarizing findings by Robert J. Ohannessian.

  • Grzegorz Adam Hankiewicz fixed a crash in the exmouse example when no mouse is present.

  • Angelo Mottola made the exunicod example welcome Italian programmers too.

  • Eric Botcazou fixed a conflict between Allegro headers and standard C++ headers of gcc 3.x under Mingw32.

  • Matthew Leverton made the DOS/Windows makefiles use 'copy /B' instead of 'copy' for file concatenation.

  • Roberto Alfonso added an srand() call in the demo game.

  • Elias Pschernig removed (seemingly) arbitrary window size checks in the Unix X11 driver.

  • Javier Gonzaled fixed a bug with volume and pan not properly set in loop mode by the DirectSound driver.

  • Eric Botcazou fixed the documented prototype of fixtof() and ftofix().

  • Eric Botcazou fixed a bug that causes timers to restart permanently when Allegro is switched out under Windows.

  • Eric Botcazou fixed a bug with graphics mode switching using a ALT+key combination under Windows.

  • Eric Botcazou improved win_set_window() so that it can be called after the library has been initialized.

  • Elias Pschernig fixed a bug in midi_seek().

  • Grzegorz Adam Hankiewicz added a linux specific debug help section.

  • Jan Bruun Andersen fixed a compilation problem with Cygwin.

  • Ben Davis and Robert J. Ohannessian put in (void *) casts for the LOCK_* macros on DJGPP and Mac.

  • Nicholas Davies made the fix class not trigger warnings with gcc -Weffc++.

  • Angelo Mottola fixed a keyboard focus problem under BeOS.

  • Peter Wang fixed the detection of ESD on Unix systems.

  • Peter Wang made files be opened with as permissive as possible permissions on Unix systems.

  • Peter Wang did some housekeeping work throughout the code and the documentation.

  • Peter Wang added support for the environment variable ALLEGRO_MODULES under Unix.

  • Sven Sandberg fixed various problems in the makefiles.

  • Henrik Stokseth made the zipwin.sh script for packaging the Windows binary distribution work with Cygwin.

  • Peter Wang and Eric Botcazou made it so that Allegro C programs can compile with gcc -ansi -pedantic.

  • Eric Botcazou fixed the 'configure --disable-constructor' problem.

  • Igor Gnip removed the requirements for fileutils on DOS/Windows platforms.

Changes from 4.0.1 to 4.0.2 (Jun 2002)

  • Many clarifications in the docs.

  • Sven Sandberg improved accuracy and fixed bugs in do_arc().

  • Matthew Leverton added missing header files to be installed by the Windows binary distribution.

  • Grzegorz Adam Hankiewicz fixed a problem with the TOC of the FAQ.

  • Eric Botcazou fixed a bug with stretch_blit() under Windows XP.

  • Peter Wang fixed various configure machinery problems under Unix.

  • Sven Sandberg updated the Swedish translation file.

  • Sven Sandberg fixed a crash in the exswitch example when compiled by Watcom C/C++ and also made if faster.

  • Maxime Carey added a Canada (French) keyboard mapping file.

  • Henrik Stokseth updated instructions and fixed installation for Cygwin.

  • Eric Botcazou added an option to disable direct updating in color conversion mode under Windows.

  • Eric Botcazou (presumably) fixed the bug in the emergency exit mechanism under Windows when called from the DLL.

  • Angelo Mottola made it so that the sound doesn't block the main thread anymore under BeOS.

  • Deepak T and Eric Botcazou fixed clipping in three C sprite drawing routines.

  • Peter Wang fixed a deadlock that occurred under Unix when Allegro received an X11 close event.

  • Eric Botcazou added a --cppflags option to allegro-config and fixed C++ compilation under QNX.

  • Vincent Penquerc'h added a --version= option to allegro-config.

  • Robert J. Ohannessian made the 32->24 color convertors more robust and improved the MMX one in the process.

  • Robert J. Ohannessian, Eric Botcazou and Sven Sandberg fixed a bug in the hue blender and the hsv_to_rgb() routine.

  • Matthew Leverton fixed another problem with al_find*() and NTFS partitions under Windows.

  • Peter Wang fixed a bug in ALSA device detection.

  • Peter Wang fixed a bug in al_find* under Unix when running as root.

  • Matthew Leverton and Eric Botcazou fixed a bug with mouse mickeys in windowed mode under Windows.

Changes from 4.0.0 to 4.0.1 (Mar 2002)

  • Many minor changes, many clarifications in the docs.

  • Peter Wang fixed the installation of shared libs under FreeBSD.

  • Peter Wang and Eric Botcazou fixed autodetection glitches for VGA and SVGAlib.

  • Eric Botcazou fixed a problem under X11 when the MIT X-SHM extension is used.

  • Eric Botcazou fixed a deadlock on exit when an user window is used in conjunction with timers under Windows.

  • Eric Botcazou disabled useless backbuffers for the DirectX safe driver.

  • Peter Wang made the Alsa sound driver use non-blocking mode when detecting if ALSA PCM available.

  • Sven Sandberg added support for long long integers to usprintf() and al.

  • Robert J. Ohannessian fixed the difference blender.

  • Peter Wang fixed a race condition when closing the X display.

  • Elias Pschernig made all active dialogs redraw themselves after a switch.

  • Peter Wang made fbcon a priority driver, so that it can appear above VGA.

  • Javier Gonzalez fixed a glitch in the DirectSound input code.

  • Eric Botcazou fixed the SIGSEGV on exit with the three-finger salute under QNX.

  • Eric Botcazou fixed the C-to-asm calling problem for Borland C++ compiled programs.

  • Eric Botcazou cleaned up the messy (and somewhat incorrect) DirectDraw bitmap management code.

  • Sven Sandberg improved the video bitmap subdivision algorithm.

  • Sven Sandberg fixed problems in the Windows makefiles (especially Borland) when building Allegro under Win98.

  • Peter Wang removed the hack which switched off fix aliases under IRIX.

  • Vincent Penquerc'h fixed a problem with the SIGALRM timer and SWITCH_PAUSE.

  • Javier Gonzalez fixed a latency problem with audiostreams.

  • Laurence Withers made the font exporter use the current palette for the output.

  • Elias Pschernig made some changes to grabber: added a close hook; keeps track if anything has been modified; when you exit the grabber and the file was modified, the popup now has a 3rd option for save+exit; window title displays the current filename, and if the file has been modified; fixed multicolour font exports.

  • Sven Sandberg optimized again the create_light_table() function.

  • Attila Szilagyi fixed SVGAlib horizontal scrolling.

  • Eric Botcazou fixed synchronization problems under QNX.

  • Grzegorz Adam Hankiewicz made the TOC at the top of sections alphabetically sorted.

  • Eric Botcazou fixed the screen not restored after a wake-up in the Windows windowed and overlay drivers.

  • Richard Reeve fixed a silly mistake with gcc 3.0.x detection.

  • Angelo Mottola fixed static keyconf compilation problem on BeOS due to pckeys keyboard driver.

  • Eric Botcazou fixed the not-returning-focus-on-exit bug under Windows.

  • Michael Bukin fixed a bug with C-version textprintf on 24-bpp bitmaps, reported by Bertrand Coconnier.

  • Eric Botcazou fixed a bug in the 32->15 MMX color conversion routine.

  • Eric Botcazou fixed the DLL linking problem with Borland C++ Builder 4.

  • Sven Sandberg made exaccel more responsive.

  • Sven Sandberg fixed a glitch with short filenames under DOS.

Changes from 3.9.40 to 4.0.0 (Dec 2001)

  • Many minor changes.

  • Eric Botcazou modularised the VGA/Mode-X drivers under Linux.

  • Peter Wang fixed the segfault bug in Mode-X under Linux with threads.

  • Peter Wang made the X11 port use SIGTERM signal instead of exit() when invoking the three finger salute. This solves a problem where programs with sound hang when they are killed.

  • Eric Botcazou added os_version and os_revision support to the QNX port and added a QNX specific section to the docs.

  • Peter Wang added a deadzone for digital readings of joystick axes under Linux, as suggested by George Foot and made the driver look for /dev/input/js# before /dev/js#.

  • Peter Wang renamed fixed point functions to be prefixed with "fix" instead of "f", to avoid clashes with some libcs. Backwards compatibility is provided using static inline functions.

  • Peter Wang fixed two problems with emergency exits under Linux/Unix.

  • Eric Botcazou changed the updating logic of the QNX Photon graphics driver.

  • Eric Botcazou added a doc for the wfixicon utility, with the help of Laurence Withers.

  • Angelo Mottola unicodified allegro_message on BeOS and wrote a new BeOS keyboard driver (using the shared pckeys system).

  • Eric Botcazou fixed a problem with David Capello's d_menu_proc steal/return mouse focus patch.

  • Peter Wang made passing NULL to install_allegro() as the atexit_ptr parameter mean allegro_exit() won't be installed as an atexit() callback, as suggested by Javier Gonzalez.

  • Lorenzo Petrone added a gfxinfo utility.

  • Eric Botcazou added fetch_mode_list() to the QNX Photon Direct driver.

  • Peter Wang made X desktop_color_depth() able to return 15 bpp.

  • Grzegorz Adam Hankiewicz updated Spanish translation strings.

  • Peter Wang fixed a problem with X shutdown sequence.

  • Eric Botcazou repaired the QNX build process, revamped the layout of the QNX port sources and made some fixes.

  • Peter Wang disabled the SVGAlib mode fetching code as it was causing problems with other drivers.

  • Angelo Mottola added BeOS notes to the ABI compatibility doc.

  • Eric Botcazou fixed a bug in the Windows locking code that caused the grabber to crash on switch out.

  • Eric Botcazou fixed a bug in the handling of recursive sub-bitmaps under Windows.

  • Eric Botcazou fixed a bug preventing old style password-protected packfiles from loading in the grabber.

  • Lorenzo Petrone added two FAQ entries on DGA2 problems.

  • Grzegorz Adam Hankiewicz revamped the structure of the docs directory.

  • Stepan Roh updated the Czech translation.

  • Javier Gonzalez fixed a bug in the DirectSound driver related to the loop playing modes.

  • David Capello fixed a problem with submenus which overlapped their parents, where focus would pop back to the parent instead of the child.

Changes from 3.11 to 3.9.40 (Nov 2001)

  • 3.9.40: Eric Botcazou enabled SSE support under Linux. Also reduced the delay in the DOS Sidewinder init code. Made the definition of _AL_DLL for MinGW32 consistent with other Windows ports.

  • 3.9.40: Henrik Stokseth improved make install to install only the needed headers from the include/allegro/platform directory.

  • 3.9.40: Vincent Penquerc'h updated 7 makefiles after his header splitting patch.

  • 3.9.40: Robert J. Ohannessian added two new entries to the GFX_VTABLE structure.

  • 3.9.40: Eric Botcazou replaced sprintf() by snprintf() in the Linux/Unix code. Increased the delay in the Windows switch handling code. Unicodified the GFX mode selector and fixed some glitches. Added a new test dubbed filetest. Fixed more unicode string problems. Unified the handling of system directory variables in the Windows makefiles. Made two strings translatable in the GFX mode selector.

  • 3.9.40: Ben Davis added support for timers with parameters under Windows.

  • 3.9.40: Eric Botcazou fixed the bug in the asm sprite functions when used with sub-bitmaps. Fixed a problem of the new header layout for platforms not supporting asm.

  • 3.9.40: George Foot and Eric Botcazou fixed the C fceil() function and added the ffloor() function.

  • 3.9.40: Chris Graham suggested to add a new flag for Windows NTFS compressed files.

  • 3.9.40: Henrik Schmidt and Eric Botcazou found a workaround for the switching problem under Windows.

  • 3.9.40: Eric Botcazou revamped the Borland C++ build process. Now it targets BC++ 5.5. Made pack_fdopen() an exported internal function. Reverted to the 3.9.38 code for 16-bit audio streaming with DirectSound.

  • 3.9.40: Vincent Penquerc'h contributed a rather large split-up/ reorganization of the Allegro header files. Henrik and Eric did some related clean-up and fixing.

  • 3.9.40: Peter Wang updated put_backslash() docs.

  • 3.9.40: Eric Botcazou modified the way DirectDraw surfaces are enumerated. Fixed compilation errors/warnings with BC++. Made generate_optimized_palette_ex() a static function. Worked around the DOS limitations for al_findfirst() and for_each_file(). Moved platform-dependent stuff out of src/fsel.c.

  • 3.9.40: Peter Wang updated timer docs for non-DOS. Added ABI compatibility readme.

  • 3.9.40: Javier Gonzalez removed all references to the RSXNT build.

  • 3.9.40: Vincent Penquerc'h made it so that users can provide their own ustrdup().

  • 3.9.40: Robin Burrows fixed two glitches in the DirectDraw code.

  • 3.9.40: Peter Wang fixed a problem where XUnlockDisplay was called after XCloseDisplay.

  • 3.9.40: Eric Botcazou removed old Sidewinder asm driver. Cleaned up buffer usage in DIGMID. Fixed unicode support in the DIGMID driver. Replaced all occurrences of SEND_MESSAGE() by object_message().

  • 3.9.40: Annie Testes caught a misordering in the X system shutdown.

  • 3.9.40: Eric Botcazou increased the size of filename buffers to 1024 bytes.

  • 3.9.40: Sven Sandberg improved fix.bat script.

  • 3.9.40: David Capello fixed a problem with lost GUI mouse clicks.

  • 3.9.40: Vincent Penquerc'h removed two hard-coded list sizes in grabber.

  • 3.9.40: Peter Wang added a little clarification regarding mouse_accel_factor.

  • 3.9.40: Eric Botcazou made debugging functions revert to ASCII strings. Added some defines for backwards compatibility with former cpu_* flags. Fixed a compilation problem under DJGPP.

  • 3.9.40: Henrik Stokseth added VBE/AF fetch_mode_list().

  • 3.9.40: Robert J. Ohannessian revamped the retrieval mechanism of CPU capabilities and added some new flags.

  • 3.9.40: Eric Botcazou fixed various mouse cursor problems under Windows. Updated docs about the DIGI_DIRECTX drivers.

  • 3.9.40: Javier Gonzalez fixed audio streams in Windows.

  • 3.9.40: Peter Wang improved the XDGA2 driver by removing unneccessary scrolling, which also resulted in speed-ups due to less locking/unlocking. The original fix was by Michael Bukin.

  • 3.9.40: Eric Botcazou and Javier Gonzalez added some documentation on static linking with MSVC/MinGW32.

  • 3.9.40: Peter Wang fixed sonames for debug and profile libs. Also added a 'configure' check that ld supports -export-modules before enabling modules.

  • 3.9.40: Annie Testes found ASCII strings that needed to be converted. Also added a pack_fdopen() function.

  • 3.9.40: Robert J. Ohannessian clarified some Dev-C++ instructions. Fixed fix.bat script under MinGW32/Win2k.

  • 3.9.40: Marcel Smit corrected a bug that caused errors when drawing perspective-correct polygons facing the screen. (dz=0)

  • 3.9.40: Peter Wang made install_timer_int static. Also moved allegro_404_char into public API.

  • 3.9.40: Laurence Withers added docs for allegro_404_char.

  • 3.9.40: Eric Botcazou fixed a little glitch with menu auto-opening. Also fixed a color glitch in the Windows windowed driver on 8-bit desktops.

  • 3.9.40: Salvador Eduardos Tropea fixed inline friend declarations with bodies. (gcc 3.0.x problem)

  • 3.9.40: Peter Wang improved behaviour between mouse auto-opening menus and navigating with keyboard. Also unspartanised the ustrtok_r() docs.

  • 3.9.40: Henrik Stokseth replaced the mmxtest with a more advanced assembler capabilities testing.

  • 3.9.40: Eric Botcazou re-enabled full pairing on Pentium for five color conversion routines. Applied xor vs. mov instruction-length optimization to the non-MMX code. Applied %ecx vs. %edx instruction-length optimization to the non-MMX code. Updated the mouse_accel_factor docs.

  • 3.9.40: Peter Wang eliminated use of static buffers by uconvert() in several places.

  • 3.9.40: David A. Capello made d_menu_proc steal/return focus when activated/deactivated.

  • 3.9.40: Henrik Stokseth added Out of Environment space detection on the fix.bat script.

  • 3.9.40: Eric Botcazou fixed a non ANSI C compliant behaviour in usprintf().

  • 3.9.40: Seunghwan Ji made makedoc output correct html and rtf files for Korean.

  • 3.9.39: Robert J. Ohannessian added -? and --help options to dat.

  • 3.9.39: Sven Sandberg and Grzegorz Adam Hankiewicz fixed some errors in the documentation.

  • 3.9.39: Annie Testes fixed several glitches related to unicode support.

  • 3.9.39: Henrik Stokseth added an internal _al_sane_realloc() function with guaranteed behaviour. Used this to fix a memory leak and updated the FAQ.

  • 3.9.39: Eric Botcazou and Peter Wang updated the documentation on: file attribute flags, request_scroll and request_video_bitmap.

  • 3.9.39: Eric Botcazou unified the use of internal timers in Windows drivers. Also let digitest use max volume of Allegro mixer.

  • 3.9.39: Paul Hampson improved again the DOS SNESpad joystick driver.

  • 3.9.39: Eric Botcazou revamped the locking mechanism of the DGA2 driver. Also fixed some memory leaks.

  • 3.9.39: Peter Wang added mode fetching for X11 fullscreen and DGA fullscreen drivers.

  • 3.9.39: Robert J. Ohannessian fixed 16bit masked blit SSE code and removed unused instruction in the other blitters.

  • 3.9.39: Salvador Eduardos Tropea added some GCC 3.x fixes.

  • 3.9.39: Peter Wang added a check if a module listed in modules.lst exist before trying to load it.

  • 3.9.39: Charles Wardlaw made alert/alert3 use transparent background for text label.

  • 3.9.39: Eric Botcazou added a flush_config_file() API function. Also added a hfill() method to the GFX_VTABLE structure.

  • 3.9.39: Peter Wang fixed some memory leaks.

  • 3.9.39: Eric Botcazou fixed two compilation warnings with gcc > 2.95.

  • 3.9.39: Johan Peitz contributed 'Alex the Allegator' icon.

  • 3.9.39: Angelo Mottola fixed safe fullscreen bug and fetch_mode_list() for BeOS.

  • 3.9.39: Peter Wang updated XDGA2 and SVGAlib driver's fetch_mode_list() function.

  • 3.9.39: Henrik Stokseth rewrote the mode-list API, updated the code and updated the documentation.

  • 3.9.39: Grzegorz Adam Hankiewicz updated all URLs in the Allegro sources and documentation.

  • 3.9.39: Eric Botcazou fixed cmplog script for perl 5.6.1.

  • 3.9.39: Peter Wang added a FAQ entry.

  • 3.9.39: Peter Wang fixed up the sound subsystem which he accidentally broke when he introduced the dynamic modules.

  • 3.9.39: Eric Botcazou fixed a compilation warning. Also added support for 8-bit desktops to the windows windowed driver. Fixed color shifts in the color convertors from 8-bit. Fixed a bug in the 8->8 color conversion routine.

  • 3.9.39: Javier Gonzalez contributed bidirectional looping support for the directsound driver.

  • 3.9.39: Robert J. Ohannessian and Henrik Stokseth did a large update on the installation instructions for Mingw32.

  • 3.9.39: Eric Botcazou cleaned up windows dll version info sheet and let the windows makefiles use implicit rules on some file targets. Fixed a compilation glitch with MSVC.

  • 3.9.39: Henrik Stokseth added support for building RPMs with SuSE Linux.

  • 3.9.39: Peter Wang fixed some off-by-one errors. Fixed unix makefile. Fixed disabling of dynamic modules.

  • 3.9.39: Eric Botcazou and Grzegorz Adam Hankiewicz finished translation of the allegro.spec file.

  • 3.9.39: Eric Botcazou re-added a faq entry on DirectX version problem.

  • 3.9.39: Grzegorz made fbcon a module.

  • 3.9.39: Peter Wang removed allegro-enduser.spec as it is no longer needed. Also contributed a rewrite of the allegro.spec file, and updated the scripts to make the rpm. The new allegro.spec file was based on one contributed by Osvaldo Santana Neto. Peter also allowed configure to give linker flags to allegro-config (for modules). Also let _unix_find_resource search in /usr/[local/]share/allegro for .dat files.

  • 3.9.39: Javier Gonzalez contributed backward playing support for the directsound driver.

  • 3.9.39: Eric Botcazou fixed a glitch with backward playing in the digitest test.

  • 3.9.39: Salvador Eduardos Tropea made a small update on the cygwin section of readme.mgw.

  • 3.9.39: Peter Wang fixed a problem with BSD make and Mac directory separators ':'. Documented gfx_cardw variable.

  • 3.9.39: Sven Sandberg fixed a nasty side-effect of clear() inlining on Watcom.

  • 3.9.39: Laurence Withers fixed a crash bug in the mode-selector.

  • 3.9.39: Peter Wang removed SIGIO asynch stuff since it's not needed when we have pthreads. Updated documentation to mention dynamic modules. Added configure option to disable threads.

  • 3.9.39: Burton Radons fixed a bug in his dissolve blender.

  • 3.9.39: Eric Botcazou fixed a bug in the menus caused by auto-opening.

  • 3.9.39: Henrik Stokseth updated the makefiles to use -mcpu=pentium instead of the depreciated -mpentium gcc option. Also let the packaging scripts run autoconf and remove hidden or leftover files.

  • 3.9.39: Eric Botcazou cleaned up the windows sound code. Also clarified the code in the core menu function. Corrected a unicode glitch. Removed remaining references to ALLEGRO_NO_FINDFIRST. Added a unified al_find*() interface. Made the Portuguese translation file of the former Portuguese (Br) file. Fixed a few keyboard configuration files. Changed pl.cfg EOLN delimiter to \r\n.

  • 3.9.39: Grzegorz Godlewski contributed a Polish localization patch. Also added support for lower and upper altgr tables.

  • 3.9.39: Eric Botcazou fixed a bug in the keyconf utility caused by the sectionification.

  • 3.9.38: Robert J. Ohannessian added the following to the color convertor: color copy routines needed by the BeOS port, support for cross-conversion between 15-bit and 16-bit colors, support for conversion to 8-bit color, support for rectangles of any width and added two new MMX routines.

  • 3.9.38: Henrik Stokseth rewrote get_gfx_mode_list() likewise rewrote the mode-selector to use get_gfx_mode_list(). Also added fetch_mode_list() functions on the DirectX, VGA, Mode-X and Xtended GFX drivers.

  • 3.9.38: Angelo Mottola fixed problems with SMP on the BeOS port.

  • 3.9.38: Eric Botcazou fixed some problems with the non-MMX code in the color convertor.

  • 3.9.38: Sven Sandberg improved spline() for DRAW_MODE_TRANS

  • 3.9.38: Peter Wang renamed clear() to clear_bitmap(). clear() is still provided for backwards compatibility.

  • 3.9.38: Stepan Roh made fractal generator work under non-Intel processors.

  • 3.9.38: Eric Botcazou made a valid display switch mode of SWITCH_NONE under DOS.

  • 3.9.38: Angelo Mottola made the BeOS port use the new unified color conversion routines.

  • 3.9.38: Peter Wang added check to see if display is local under X11.

  • 3.9.38: Eric Botcazou and Sven Sandberg fixed compilation under Watcom 10.6.

  • 3.9.38: Elias Pschernig contributed an icon resource fixer for the Windows port and added support for shared library under BeOS.

  • 3.9.38: Angelo Mottola added a bfixicon utility.

  • 3.9.38: Stepan Roh made the native Allegro time format of ANSI time_t.

  • 3.9.38: Peter Wang added an ustrtok_r() function.

  • 3.9.38: Robert J. Ohannessian optimized some masked_blits with SSE instructions.

  • 3.9.38: Angelo Mottola did a sound fix for audiostream output and SMP machines and added triple buffering support on the BeOS port.

  • 3.9.38: Angelo Mottola added fetch_mode_list() support to the BeOS fullscreen driver.

  • 3.9.38: Eric Botcazou changed the acceleration scheme for the mouse under Windows.

  • 3.9.38: Peter Wang added fetch_mode_list() support to the svgalib driver.

  • 3.9.38: Peter Wang added pthread timer and removed dependancy to SIGALRM.

  • 3.9.38: Henrik Stokseth added Windows XP detection.

  • 3.9.38: Andreas Kluge fixed a bug with volume setting in the DOS Soundscape driver.

  • 3.9.38: Angelo Mottola rewrote the BeOS sound driver to use the BSoundPlayer class.

  • 3.9.38: Robert J. Ohannessian added SSE and SSE2 detection.

  • 3.9.38: Connelly Barnes fixed a bug with the DirectSound pan.

  • 3.9.38: Eric Botcazou added support of switch modes to the test program.

  • 3.9.38: Eric Botcazou modified the Windows switch mechanism.

  • 3.9.38: Angelo Mottola added fullscreen display switching support and did many fixes and cleanups on the BeOS port.

  • 3.9.38: Henrik Stokseth added code to get more os info under unix.

  • 3.9.38: Nimrod Abing fixed a bug in the config routines related to the NULL section.

  • 3.9.38: Eric Botcazou fixed a crash in the Windows windowed driver on fast machines.

  • 3.9.38: Ronaldo Hideki Yamada did a large update on the PowerMac port and added a midi driver.

  • 3.9.38: Henrik Stokseth generalised the support for processor specific optimisations in some makefiles.

  • 3.9.38: Evert Glebbeek put set_gfx_mode on a diet and added config entry for specifying the card to use for GFX_AUTODETECT_WINDOWED.

  • 3.9.38: Robert J. Ohannessian made blit not convert between colordepths for video bitmaps. (for AllegroGL)

  • 3.9.38: Peter Wang made fix_filename_slashes() handle both types of slashes.

  • 3.9.38: Grzegorz Adam Hankiewicz implemented a switch in makedoc to check for long (>77) doc lines.

  • 3.9.38: Owen Rudge contributed a DLL version resource script.

  • 3.9.38: Sven Sandberg made the rotation functions faster, more accurate and working with any type of bitmap. Also removed rotate_scaled_sprite_flip().

  • 3.9.38: Angelo Mottola added fetch_mode_list() support to DGA2.

  • 3.9.38: David A. Capello made test program use transparent polygon types.

  • 3.9.38: Owen Rudge contributed a mkdata.bat script.

  • 3.9.38: Grzegorz Adam Hankiewicz added reload_config_texts().

  • 3.9.38: Eric Botcazou added an enhanced building mechanism for DLL export definition files.

  • 3.9.38: Eric Botcazou added a new unicode example program and did a ton of small fixes.

  • 3.9.37: Johan Peitz fixed and enhanced the Win32 joystick driver.

  • 3.9.37: Sven Sandberg added Ctrl + arrow keys to d_edit_proc().

  • 3.9.37: Eric Botcazou changed the color key for the Windows overlay driver to bright pink.

  • 3.9.37: Eric Botcazou reverted some changes he made to the timer core last release which were causing problems with the MIDI player, and removed the Windows multithreaded timer driver.

  • 3.9.37: Henrik Stokseth made some updates to the OS detection code, and added a os_multitasking variable.

  • 3.9.37: Eric Botcazou fixed a problem in the config routines, where entries in the NULL section were hiding duplicate entries in other sections.

  • 3.9.37: Eric Botcazou made the setup program use Unicode functions.

  • 3.9.37: Henrik Stokseth unified the fix* scripts, and gave them new options.

  • 3.9.37: Peter Wang added support for dynamically loaded modules under Unix. The SVGAlib, ALSA digital, ALSA MIDI, ESD and DGA2 drivers will be built as modules when possible. This removes external dependencies on the main library and improves binary transportability under Linux.

  • 3.9.37: Eric Botcazou made many changes and bug fixes to the Unicode string functions, and their use in the library. The old functions now behave exactly like the libc equivalents, while the new functions (the 'z' functions) behave more sanely. This change affects most code which uses the Unicode functions.

  • 3.9.37: Bertrand Coconnier changed the recently merged scene rendering API, fixed a bug, and provided a new example program. The API change will affect all code which uses the scene functions.

  • 3.9.37: Laurence Withers wrapped registration of the bitmap file types in a constructor. Where constructors are supported, this should reduce the executable size when statically linking (unless you use the bitmap loaders, of course).

  • 3.9.37: Ben Davis modified the set_volume_per_voice scale. Please see the docs for this function if you have used it in the past.

  • 3.9.37: Eric Botcazou worked around a DOS mouse bug under Win2k.

  • 3.9.37: Eric Botcazou added VGA Mode 13h support under DirectX 5 or greater.

  • 3.9.37: Henrik Stokseth added a get_gfx_mode_list() function, and the implementation of it for the VESA driver.

  • 3.9.37: Eric Botcazou and Annie Testes toiled hard to avoid buffer overflows (particularly with regards to the Unicode functions).

  • 3.9.37: Eric Botcazou fixed a mouse mickeys bug and cleaned up the input subsystem under Windows.

  • 3.9.37: Eric Botcazou made two minor changes in the handling of index 0 in paletted modes.

  • 3.9.37: Eric Botcazou added a transparency preserving feature to the grabber and dat utility.

  • 3.9.37: Eric Botcazou fixed a crash when alt-tabbing in page flipping under Windows.

  • 3.9.37: Peter Wang added gui_menu_draw_menu and gui_menu_draw_menu_item to allow customising the look of the GUI menus (to a certain extent).

  • 3.9.37: Angelo Mottola added support for the new GFX_AUTODETECT_FULLSCREEN and GFX_AUTODETECT_WINDOWED constants, which we _all_ wholeheartedly agreed upon :-)

  • 3.9.37: Eduard Bloch made config vars which exist but are empty return defaults.

  • 3.9.37: Elias Pschernig added a COLORCONV_KEEP_TRANS mode.

  • 3.9.37: Henrik Stokseth added support for compiling with Cygwin. It works in Mingw compatibility mode.

  • 3.9.37: Angelo Mottola made GUI submenus automatically open when the mouse hovers for long enough. (This was an old patch that finally got merged.) Eric made some related modifications to it later.

  • 3.9.37: Eric Botcazou made clear_keybuf() not clear the key[] array.

  • 3.9.37: Sven Sandberg added a --quick option to fix scripts.

  • 3.9.37: Angelo Mottola did _loads_ of work on the QNX port (much too much to document here).

  • 3.9.37: Eric Botcazou made the Win32 asm color conversion code for windowed drivers available for other ports, and added a few other converters. Isaac Cruz added one too.

  • 3.9.37: Eric Botcazou restructured the config file format. Some previously unsectioned variables are now in sections.

  • 3.9.37: George Foot added a threading system to handle asynchronous events, instead of using SIGALRM (under Unix).

  • 3.9.37: George Foot fixed some problems with pack_fgets().

  • 3.9.36: Eric Botcazou made it so that set_keyboard_rate(0, 0) will disable keyboard repeat, as in the documentation.

  • 3.9.36: Annie Testes added font_height, render_char, char_length hooks to FONT_VTABLE.

  • 3.9.36: Eric Botcazou made some minor changes related to AllegroGL in the window management code, and fixed two little mouse bugs Javier Gonzalez had found (both under Windows).

  • 3.9.36: Eric Botcazou added a get_desktop_resolution() function for Windows and X. Joshua Haberman added a BeOS version.

  • 3.9.36: Angelo Mottola comprehensively started a QNX port.

  • 3.9.36: Robert Ohannessian corrected src/dest ordering in additive blenders.

  • 3.9.36: Eric Botcazou improved support of external windows in Windows.

  • 3.9.36: Peter Wang updated the SVGAlib driver for version 2.

  • 3.9.36: Peter Wang added a fullscreen version of the X-Windows graphics driver. The original was by Benjamin Joel Stover.

  • 3.9.36: Peter Wang made grabber use file_select_ex(). This is just here so you don't get a shock :-)

  • 3.9.36: Eric Botcazou fixed some small bugs in the DirectSound input code.

  • 3.9.36: Eric Botcazou fixed the NumLock state in X not matching keyboard LEDs.

  • 3.9.36: Eric Botcazou reenabled the multi-threaded timer under Windows.

  • 3.9.36: Eric Botcazou and Javier Gonzalez made the keyboard repeat system more efficient.

  • 3.9.36: Eric Botcazou fixed some asm blitters, and also a bug with changing timer speeds.

  • 3.9.36: Peter Wang made the keypad return / * - + ASCII values even if NumLock is off, under Linux console.

  • 3.9.36: Ronaldo Hideki Yamada made a big update of the Mac port, including some new PPC files.

  • 3.9.36: The GGI driver was removed, due to its inability to actually work. It is no longer supported, unless someone rewrites it.

  • 3.9.36: Eric Botcazou fixed a problem with the GDI driver when compiled with MSVC.

  • 3.9.36: Some MIDI fixes by Javier Gonzalez and Eric Botcazou.

  • 3.9.36: Grzegorz Adam Hankiewicz improved the fb.modes line parsing function in the fbcon driver.

  • 3.9.36: Grzegorz Adam Hankiewicz changed the behaviour of GFX_SAFE. This means that "set_gfx_mode(GFX_SAFE, ...)" now returns an error if it is unable to set a video mode, just like any other video driver.

  • 3.9.36: Eric Botcazou fixed volume setting in Windows.

  • 3.9.36: Eric Botcazou added DirectX 3 compatibility.

  • 3.9.36: Nick Kochakian added input routines to the DirectSound driver. It was also modified by Javier Gonzalez.

  • 3.9.35: Eric Botcazou made Windows restore the original sound volume after an Allegro program quits.

  • 3.9.35: Eric Botcazou fixed sample looping in DirectSound driver.

  • 3.9.35: Grzegorz Adam Hankiewicz solved some color problems in the demo game.

  • 3.9.35: Angelo Mottola implemented a close button hook for X11.

  • 3.9.35: Eric Botcazou fixed _the_ Windows 2000 keyboard bug.

  • 3.9.35: Eric Botcazou made some changes to the locking/unlocking mechanism in the Windows port.

  • 3.9.35: Laurence Withers made some modules avoid linking dependencies.

  • 3.9.35: Javier Gonzalez added close button support for Windows.

  • 3.9.35: Eric Botcazou improved mouse handling in the GFX_GDI driver and fixed some other mouse glitches.

  • 3.9.35: Peter Wang made set_mouse_sprite(NULL) regenerate the default arrow bitmap (using the current palette).

  • 3.9.35: Eric Botcazou made hardware accelerated primitives stop when the user switches out in Windows.

  • 3.9.35: Tom St Denis fixed clipping of transparent objects.

  • 3.9.35: Eric Botcazou and Javier Gonzalez improved switching in Windows and other things.

  • 3.9.35: Peter Wang made the Linux joystick driver use standard constants.

  • 3.9.35: Sven Sandberg changed the Z-buffer API.

  • 3.9.35: Peter Wang made the default mouse sprite independent of the palette in 8 bpp modes.

  • 3.9.35: Bertrand Coconnier added documentation for the P3D merge.

  • 3.9.35: Angelo Mottola fixed desktop_color_depth() and added window close button support for the BeOS port.

  • 3.9.35: Ben Davis added the set_window_close_button() and set_window_close_hook() framework.

  • 3.9.35: Peter Wang exposed the mouse_sprite, mouse_x_focus and mouse_y_focus variables.

  • 3.9.35: Robert Ohannessian and Javier Gonzalez fixed bad clearing of subbitmaps.

  • 3.9.35: Peter Wang renamed GFX_XDFS to GFX_XDGA_FULLSCREEN.

  • 3.9.35: Henrik Stokseth updated the cross-compilation system.

  • 3.9.35: Tomohiko Sugiura added some keys and renamed some JP keys.

  • 3.9.35: Eric Botcazou added a DirectDraw2 interface, with support for refresh rates.

  • 3.9.35: Bertrand Coconnier merged in Calin Andrian's P3D library.

  • 3.9.35: Javier Gonzalez made allegro_message() use the title from set_window_title() in Windows.

  • 3.9.35: Andreas Kluge fixed division bugs in the fix class.

  • 3.9.35: Stepan Roh documented the FA_* flags.

  • 3.9.35: Peter Wang added hooks to allow overriding the look of standard dialogs.

  • 3.9.35: Peter Wang changed X window placement and mapping behaviour.

  • 3.9.35: David A. Capello made dotted_rect() avoid bank switches.

  • 3.9.35: Eric Botcazou fixed a freezing problem under Window with locking/unlocking bitmaps under heavy load. He received help tracking down the bug from Javier Gonzalez.

  • 3.9.35: Stepan Roh fixed a bug with FA_RDONLY constant under Unix.

  • 3.9.35: Eric Botcazou cleaned up the Windows graphics subsystem.

  • 3.9.35: "Sask Allegro" added support for more than two joysticks in the Windows port.

  • 3.9.34: Ben Davis made close button in Windows windowed modes not simulate Escape key, in preparation for new behaviour (in next WIP).

  • 3.9.34: Laurence Withers fixed a problem with accents in keyconf.

  • 3.9.34: Javier Gonzalez added DIGMID to the Windows MIDI drivers list.

  • 3.9.34: Eric Botcazou cleaned up the DirectDraw subsystem.

  • 3.9.34: Eric Botcazou made the DirectDraw overlay driver comply with page flipping and triple buffering code, amongst other things.

  • 3.9.34: Bertrand Coconnier improved subtexel accuracy for texture mapping.

  • 3.9.34: Javier Gonzalez corrected mouse movement speed in Windows.

  • 3.9.34: Ben Davis adapted polygon functions to handle two coincident vertices, and changed and clarified texture coordinate alignment in code and documentation.

  • 3.9.34: Grzegorz Adam Hankiewicz fleshed out the docs for Unicode functions, adapting from djgpp and gcc docs.

  • 3.9.34: Eric Botcazou fixed a triple buffering problem in the DirectDraw accelerated driver.

  • 3.9.34: Henrik Stokseth added support for cross-compilation in the mingw32 build.

  • 3.9.34: Grzegorz Adam Hankiewicz updated more examples for GFX_SAFE.

  • 3.9.34: Ben Davis added set_volume_per_voice(), made silent voices continue playing and fixed other minor bugs.

  • 3.9.34: Ben Davis fixed a bug in create_rgb_table().

  • 3.9.34: Angelo Mottola added display switching routines for BeOS and fixed some bugs.

  • 3.9.34: Laurence Withers updated documentation about `const'.

  • 3.9.34: Ronaldo Hideki Yamada contributed a macintosh port of Allegro.

  • 3.9.34: Grzegorz Adam Hankiewicz changed and documented new GFX_SAFE behaviour (that color depth is undefined), updated the fbcon driver to take advantage of this and updated example programs.

  • 3.9.34: Peter Pavlovic fixed a bug caused by file selector stretching.

  • 3.9.34: Bertrand Coconnier fixed bugs related to poly3d(); removed never-called C versions of scanline functions for POLYTYPE_FLAT and non-8bpp POLYTYPE_GCOL; and made clip3d() and clip3d_f() functions compliant with Z-buffered polygons.

  • 3.9.34: Stepan Roh added C version of masked_stretch_blit().

  • 3.9.34: Angelo Mottola did more work on BeOS: hardware acceleration (rect, hline, vline, clear_to_color, blit); mouse fix in windowed mode; desktop_color_depth(); yield_timeslice();

  • 3.9.34: Peter Wang retroactively updated CHANGES and AUTHORS from late 3.9.33 to present using CVS logs and email archives, and possibly messed up.

  • 3.9.34: Angelo Mottola added a BeOS windowed driver (originally by Peter Wang), a BeOS MIDI driver, mouse wheel support under BeOS and made many bug fixes and changes to other BeOS code and documentation.

  • 3.9.34: Laurence Withers fixed dat2s output of fonts for new font subsystem.

  • 3.9.34: Peter Wang made the SVGAlib driver more robust.

  • 3.9.34: Peter Wang changed the way Intellimouse protocols are selected under Linux console.

  • 3.9.34: Eric Botcazou added file_select_ex and reverted file_select to old behaviour.

  • 3.9.34: Laurence Withers added ugetcx() function.

  • 3.9.34: Laurence Withers designed and implemented a new FONT structure, which should provide many advantages over the old one.

  • 3.9.34: Eric Botcazou made more fixes to Windows code.

  • 3.9.34: Bertrand Coconnier added a z-buffer rendering mode for 3D polygons (derived from Calin Andrian's P3D library) and an example program for it.

  • 3.9.34: Michael Bukin added customization for keycode to scancode mapping in X.

  • 3.9.34: Peter Wang added mouse wheel support to d_textbox_proc and d_slider_proc, and made file selector dialog stretch.

  • 3.9.34: Tom Fjellstrom added an ALSA MIDI driver.

  • 3.9.34: Eric Botcazou made some changes to the Windows windowed driver.

  • 3.9.34: Grzegorz Adam Hankiewicz updated the documentation and the makedoc program to produce better .texi output. The new version works very well with the texi2dvi program, which produces fine ready to print device independent output. Also documented the new unix makefile targets.

  • 3.9.34: George Foot added --env option to allegro-config script.

  • 3.9.34: Benjamin Stover made some vararg fixes in unicode.c and added a workaround for missing defines in fbcon.c.

  • 3.9.34: Robin Burrows added a Windows waveOut sound driver.

  • 3.9.34: Eric Botcazou changed desktop_color_depth() for Windows.

  • 3.9.34: Angelo Mottola added line switching and refresh rate support to DGA2 driver.

  • 3.9.34: Bertrand Coconnier added scanline subdivisions and fixed 3D polygon drawing.

  • 3.9.34: Angelo Mottola added BeOS joystick driver.

  • 3.9.34: Angelo Mottola added DGA2 driver.

  • 3.9.34: Robin Burrows added Windows sound driver using Allegro mixer.

  • 3.9.34: Stepan Roh added workaround for fceil defined in Irix headers.

  • 3.9.34: Michael Bukin changed DGA screen clearing.

  • 3.9.34: Tomohiko Sugiura added a more aggressive Sidewinder driver.

  • 3.9.34: Tomohiko Sugiura added three Japanese keys.

  • 3.9.34: Stepan Roh made C functions const-correct.

  • 3.9.34: Bertrand Coconnier fixed blending in atex_lit scanline functions.

  • 3.9.34: Michael Bukin modified text_mode to return previous mode.

  • 3.9.34: Peter Pavlovic fixed scrollbar display in grabber and improved scrolling in GUI objects.

  • 3.9.34: anarko made GUI objects restore textmode.

  • 3.9.34: Laurence Withers added font destroy hook.

  • 3.9.34: Vincent Penquerc'h modified the mouse button press/release events so they have higher priority than double-click events.

  • 3.9.34: Eric Botcazou improved colormap handling in XDGA.

  • 3.9.34: Robin Burrows provided a new page flipping code for the DirectDraw subsytem, which now works on every graphic card.

  • 3.9.33: Henrik Stokseth updated the mingw32 makefile, the documentation and sent in some other related fixes and updates. You will never again need MSVC to compile the Allegro DLLs. ;o)

  • 3.9.33: Peter Puck contributed some updates to Allegro's win32 code which got the native mingw32 build fully working.

  • 3.9.33: Michael Bukin changed the auto-repeat handling in X, sched_yield handling for Unix, fixed _add_exit_func, and added list of active dialogs to the GUI.

  • 3.9.33: Vincent Penquerc'h sped up the C versions of the RLE sprite drawing routines by quite a bit.

  • 3.9.33: Peter Wang improved TGA palette loading.

  • 3.9.33: Laurence Withers made more functions const-correct.

  • 3.9.33: Isaac Cruz moved Windows bitmap locking to a separate .S file, changed the update logic for the windowed driver, and added an accelerated vline implementation.

  • 3.9.33: Stephen Kittelson fixed a bug in pckeys.c, and changed the ASCII values returned for a few weird key combinations.

  • 3.9.33: Peter Wang made various functions const-correct.

  • 3.9.33: Peter Pavlovic made aesthetic modifications to the GUI menu system.

  • 3.9.33: Javier Gonzalez suggested that the file and mode selector dialogs should use popup_dialog.

  • 3.9.33: Vincent Penquerc'h added the install-gzipped-man makefile target, patched some of the EINTR handling, and made the OSS driver detect whether the device is 16 bit or not.

  • 3.9.33: Peter Pavlovic modified the Slovak keyboard mapping and made the file selector detect available drives in Windows.

  • 3.9.33: Peter Wang added a sound (output only) driver for BeOS.

  • 3.9.33: Sven Sandberg fixed a typo in the definition of ustrdup, added the uwidth_max function, provided the d_yield_proc function, and made various dialogs use it.

  • 3.9.33: Michael Bukin made the DGA driver clear video memory and centre the screen, if it's not fullscreen.

  • 3.9.33: Eduard Bloch suggested better ways to find the executable in Unix.

  • 3.9.33: Andrew Geers added flipped rotated sprites.

  • 3.9.33: George Foot made the Unix makefile work for non-root users.

  • 3.9.33: Grzegorz Adam Hankiewicz made language config files be forced to lower case.

  • 3.9.33: Grzegorz Adam Hankiewicz added documentation for findfirst(), findnext(), and findclose(), and corrected the documentation for get_executable_name().

  • 3.9.33: Stepan Roh made patches to allow compilation on IRIX.

  • 3.9.33: John Harger made a change to improve the stability of AllegroGL in Windows.

  • 3.9.33: Sven Sandberg fixed a bug in the plain C 16bpp stretched blitter.

  • 3.9.33: George Foot fixed a bug in the i386 8bpp masked blit routines, reported by Damian Yerrick.

  • 3.9.33: Eduard Bloch fixed a freeze caused by the ESD detection code.

  • 3.9.33: Vincent Penquerc'h added mouse button press/release events to the GUI system.

  • 3.9.33: Peter Wang solved a conflict with SVGAlib.

  • 3.9.33: Vincent Penquerc'h added the XCRP and YCRP properties to bitmap objects in datafiles.

  • 3.9.33: Vincent Penquerc'h made the GUI system not send MSG_DRAW to hidden objects.

  • 3.9.33: Chris La Mantia pointed out that his code for textprintf_right had mutated somehow.

  • 3.9.33: Peter Wang added a workaround for a mouse motion reporting bug in some X servers.

  • 3.9.33: Eric Botcazou altered the DGA code to work better in 32bpp modes.

  • 3.9.33: Daniel Nilsson tweaked exstars and exlights

  • 3.9.33: Isaac Cruz fixed a nasty bug with subbitmap locking, and added desktop_color_depth and yield_timeslice support to the Windows version.

  • 3.9.33: Peter Cech made uisspace() recognise non-ASCII space characters.

  • 3.9.32: S.Sakamaki added a function for controlling the refresh rate when using the DOS VESA 3.0 driver (this could also be supported by some other drivers if anyone wants to implement that).

  • 3.9.32: S.Suzuki added DOS drivers for the IF-SEGA /PCI, /PCI2, and /ISA joystick interface cards.

  • 3.9.32: Fabrizio Gennari added DOS drivers for multisystem joysticks with 9-pin connectors (Atari, Commodore 64, MSX).

  • 3.9.32: Peter Pavlovic improved the support for accented character maps in the keyboard driver.

  • 3.9.32: Sven Sandberg optimised the GUI listbox scrolling to skip redraws if it can't keep up with the update speed.

  • 3.9.32: Olly Betts did some work to make cross-compiling the djgpp version work on Linux.

  • 3.9.32: Isaac Cruz improved the windowed mode ddraw driver, adding support for many different color depth conversions.

  • 3.9.32: Vincent Penquerc'h added an update selection function to the grabber.

  • 3.9.32: many bugfixes from various people.

  • 3.9.32: zipup.sh now generates dependencies entirely using standard Unix tools and gcc, so it can setup all the supported platforms without needing those compilers to be available (ie. I can create Watcom, BeOS, and Mingw32 dependencies all from my Linux machine). This does require a bit of cooperation from the different targets, though: they have to set up their "make depend" target to override the standard gcc defines, and wrap any non-standard header includes with "#ifndef SCAN_DEPEND".

  • 3.9.32: fixed (I hope :-) bug with non-GMT timezones in the datafile update code.

  • 3.9.32: rewrote the Unicode usprintf() to piggyback on libc when converting floating point data (too hard to get this right ourselves :-)

  • 3.9.31: Henrik Stokseth did some work on a native Mingw32 build. This is currently incomplete, and unlikely to work right now since there have been other changes in the Windows code since the version he started from. At the moment this version is statically linked, using makefile.mgs, and makefile.mgw still exists for the MSVC-piggyback version. The ultimate goal is to get this native version building as a DLL in addition to statically linked, at which point we can merge both makefiles into makefile.mgw and remove makefile.mgs. Oh yeah, and there are currently no docs for the native version.

  • 3.9.31: Greg Hackmann contributed a Borland C++ Builder port. Like the RSXNT and Mingw32 versions, this is a client for the MSVC DLL, and not able to compile Allegro directly itself, but allows you to build Allegro programs using the Borland compiler.

  • 3.9.31: Robert Ohannessian added MMX optimisation for the 8 and 16 bit clear() functions, and Jose Antonio Luque optimised the 16 bit blit() and masked_blit() routines.

  • 3.9.31: Vincent Penquerc'h added a yield_timeslice() function (currently implemented in DOS and Unix).

  • 3.9.31: added a desktop_color_depth() function (currently only implemented in X: a Windows version will follow).

  • 3.9.31: Isaac Cruz added support for windowed modes in color depths other than the current Windows desktop, and hardware accelerated system bitmaps.

  • 3.9.31: Jose Antonio Luque improved the Windows joystick driver.

  • 3.9.31: James Hyman added support for dithering truecolor down to paletted images.

  • 3.9.31: Chris La Mantia added textout_right(), textprintf_right(), and textprintf_justify() functions.

  • 3.9.31: Sven Sandberg added a ustrrchr() function, and improved the usprintf() handling of large floating point values.

  • 3.9.31: Peter Pavlovic added a Slovak keyboard mapping and message translation.

  • 3.9.31: Manni Heumann fixed some problems with the German keyboard mapping.

  • 3.9.31: Michael Bukin improved the X keyboard and mouse handling, and fixed some problems with building on non-GNU Unix systems.

  • 3.9.31: many bugfixes and tweaks from various people (sorry, my typing patience has run out so you don't get a full list :-)

  • 3.9.31: Peter Wang added input support to the Linux OSS sound driver.

  • 3.9.31: David Kuhling optimised the i386/gcc fsqrt() code, and added an fhypot() routine.

  • 3.9.30: fixed the double XOR that was making datafile passwords so easy to reverse. The new code can still read old-style encrypted files, but data written by this version can't be accessed by older copies of Allegro.

  • 3.9.30: made load_datafile(), load_datafile_object(), and the file.dat#object syntax work correctly in all possible combinations.

  • 3.9.30: Vincent Penquerc'h added a scare_mouse_area() function.

  • 3.9.30: changed the DirectX surface locking mechanism, to improve the performance of hardware accelerated drawing.

  • 3.9.30: George Foot improved the Linux LED code, and made the internal X driver state visible via xalleg.h.

  • 3.9.30: added EINTR retry handling to read/write calls. I hope I got this right: if anyone who properly groks this stuff could check over file.c, that would be cool.

  • 3.9.30: made the Windows mouse driver work correctly in windowed mode.

  • 3.9.30: fixed various problems with Windows foreground/background switching (keys were getting stuck down, timers weren't being paused, and not all the right switching modes were being reported to the caller).

  • 3.9.30: made the X keyboard handler release all keys when it loses the input focus, to avoid stuck buttons when you alt+tab between windows.

  • 3.9.30: made the allegro-lib script arguments compatible with the standard used by GTK, ESD, etc, and renamed it to allegro-config. This changes the syntax for linking Allegro programs on Unix: see readme.uni for details of the new method.

  • 3.9.30: George Foot improved the Unix shared library system.

  • 3.9.30: Joerg Rueppel added a find_datafile_object() function.

  • 3.9.30: Peter Wang improved the SVGAlib driver.

  • 3.9.30: Peter Wang improved the Linux joystick driver.

  • 3.9.29: made the Windows code agree with other platforms about how video bitmaps are supposed to behave.

  • 3.9.29: fixed some problems with the Windows mouse wheel support.

  • 3.9.29: added set_write_alpha_blender(), set_add_blender() and create_blender_table() functions, and made the 32 bit version of draw_trans_sprite() able to use 8 bit source images in conjunction with set_write_alpha_blender(). In addition to being generally useful, using these routines makes the sources for my SpeedHack entry much smaller :-)

  • 3.9.29: added uninstall targets to the Linux makefile.

  • 3.9.29: made the X windowed mouse driver hide the Allegro cursor when the mouse moves out of our window.

  • 3.9.29: added a simple timer delay emulation of vsync() to the X code, so that eg. the demo worms game runs sensibly.

  • 3.9.29: Isaac Cruz added a GFX_DIRECTX_WIN driver.

  • 3.9.29: Keith Gerdes made some more improvements to the DirectX overlay driver.

  • 3.9.29: Andrew Geers added scrolling support to the grabber image viewer.

  • 3.9.29: Peter Wang added an alternative X DGA driver, that includes mode switching support to run in fullscreen mode.

  • 3.9.29: Peter Wang added a MSG_WHEEL event to the GUI, and made d_list_proc() use it.

  • 3.9.29: Lucas Vignoli Reis added a Portuguese (Brazil) message translation and keyboard mapping.

  • 3.9.29: Peter Wang added a Linux OSS MIDI driver for FM synth devices, and mixer support for the OSS digital driver.

  • 3.9.29: George Foot added scripts for building various Linux distribution formats.

  • 3.9.29: Michael Bukin fixed the portability problems in quantize.c.

  • 3.9.29: added a zipwin.sh script for making Windows binary distributions, including a batch file that can compile the MSVC support programs without having any GNU tools installed.

  • 3.9.29: fixed bug with color font rendering in the Windows version.

  • 3.9.29: added hardware accelerated rectfill() and hline() to the Windows version, and fixed a couple of accel related bugs (clears were being clipped wrongly, and it was claiming to support XOR drawing even though that isn't supported).

  • 3.9.29: Michael Bukin fixed bug with X drawing onto screen sub-bitmaps.

  • 3.9.28: various documentation updates.

  • 3.9.28: added parameter autodetection to the Unix OSS sound driver.

  • 3.9.28: made it possible to nest calls to the Unix for_each_file() routine.

  • 3.9.28: added a load_datafile_callback() function.

  • 3.9.28: rationalised the sound config variables, so they can be shared between drivers more easily. For instance sb_freq has been renamed to sound_freq.

  • 3.9.28: Antti Koskipaa added a DOS driver for WSS (Windows Sound System) cards.

  • 3.9.28: the audiosteam code is now able to merge multiple buffers into a single larger one, so it will still work correctly even if the user supplies a buffer smaller than the current soundcard transfer size. You can even play streams with single byte buffers now, as long as you refill them often enough!

  • 3.9.28: made the Windows timer code more robust, so it will no longer lock up when you install extremely high frequency callbacks.

  • 3.9.28: Teijo Hakala added wheel support to the Windows mouse driver.

  • 3.9.28: Peter Wang added wheel support to the X mouse driver.

  • 3.9.28: Andrew Geers added -ppassword and -nosound options to the grabber.

  • 3.9.28: Keith Gerdes fixed the DirectDraw overlay mode driver.

  • 3.9.28: Isaac Cruz fixed the bug with accelerated drawing onto sub bitmaps of DirectDraw surfaces.

  • 3.9.28: Peter Wang added banked mode support to the SVGAlib driver.

  • 3.9.28: Peter Wang fixed some problems with the ESD sound driver, and added an ALSA driver.

  • 3.9.28: palette fading speed is now timer regulated, to avoid problems with some systems (eg. DGA with non-matching color depth) where it can be excessively slow.

  • 3.9.28: fixed a couple of different overflow bugs that were causing timers to run slow on heavily loaded Unix systems.

  • 3.9.28: added a display of author credits to the demo game.

  • 3.9.28: changed the info page installation system. It now creates a dir file in the same directory as the info page, rather than messing around with symlinks, and autoconf is used to locate the install-info program.

  • 3.9.28: added an allegro-lib script to the Unix installation, which can be run by makefiles to find the right linker commandline for building Allegro programs.

  • 3.9.28: added a manpage output format to the makedoc utility. It doesn't work terribly well with apropos due to the lack of a one-line summary for each function, but the basic formatting seems to be ok: please let me know if you see any problems.

  • 3.9.28: patches from George Foot for Linux console handing, keyboard, and filename manipulations.

  • 3.9.28: many improvements by Michael Bukin, in particular enhanced performance in X, better X mouse behaviour, and DGA graphics support.

  • 3.9.27: Robert J. Ragno made some improvements to the Wingman, PSX, and throttle joystick input code.

  • 3.9.27: Peter Wang added wheel input support to the Linux mouse code (this shows up as a new mouse_z state variable).

  • 3.9.27: Patrick Hogan made Windows audiostreams work properly.

  • 3.9.27: Sven Sandberg optimised the spline routines.

  • 3.9.27: Tomohiko Sugiura added KEY_YEN and KEY_YEN2 Japanese keys to the input handler.

  • 3.9.27: Chris Robinson wrote a fixed point version of clip3d_f(), called (surprise!) clip3d().

  • 3.9.27: Sven Sandberg improved the file selector sorting algorithm.

  • 3.9.27: Henrik Stokseth improved the OS detection in the Windows lib.

  • 3.9.27: Sven Sandberg made more accurately rounded lookup tables for the fixed point trig routines.

  • 3.9.27: George Foot made the fbcon driver reset the palette on exit.

  • 3.9.27: much new X code from Michael Bukin: this stuff is working brilliantly now!

  • 3.9.27: added the X library path to the Linux liballeg.a wrapper. I think I prefer Michael's idea of having a script to return this info, though, so perhaps we should change across to doing it that way.

  • 3.9.27: fixed various bugs in both the C and i386 RLE sprite code (mostly relating to lit modes and hicolor formats).

  • 3.9.27: front-ported various fixes from the 3.12 release, to make WARNMODE=1 compile cleanly with gcc 2.95.

  • 3.9.27: Knut Pape improved the Mingw32 readme file.

  • 3.9.26: rewrote the DOS Sidewinder driver, after powerjaw sent me a pad to test it with. It still doesn't work for me in DOS mode, but it is ok under Windows, which is better than before, and as good as any of the other Sidewinder code that I've been able to locate. If anyone has or knows of code that works better than this, please let me know!

  • 3.9.26: more flexible mode flags for set_color_conversion().

  • 3.9.26: Robert J. Ragno added a driver for Gravis GrIP devices.

  • 3.9.26: Gorka Olaizola added a Redhat RPM .spec file.

  • 3.9.26: Stepan Roh updated the Czech translation and added multiple codepage support to the textconv utility, and a Unicode-aware ustrtod() function.

  • 3.9.26: added ustrdup() to the Unicode support functions.

  • 3.9.26: Sven Sandberg optimised the gcc fixed point math routines to collapse constant expressions at compile time.

  • 3.9.26: Stefan T. Boettner added a proper Linux SVGAlib driver.

  • 3.9.26: several tweaks from Vincent Penquerc'h (added a datafile merge function to the grabber, GUI bugfixes, optimised spline calculation, fix for 24 bit version of the C drawing code).

  • 3.9.26: Linux patches from Michael Bukin improve the OSS sound driver, SIGALRM handling, and X keyboard driver.

  • 3.9.26: many Linux patches from George Foot (fixes to the mouse driver, shared library and configure script, and assorted other stuff).

  • 3.9.25: fixed pckeys.c to leave sensible data in the key[] array when doing numeral vs. arrow key numlock fakery.

  • 3.9.25: fixed a bunch of problems with the SWITCH_BACKGROUND mode (I'd stupidly forgotten to disable a lot of graphics driver functions that could do bad things if called when the Allegro console isn't active).

  • 3.9.25: added pivot_sprite() and pivot_scaled_sprite() functions (thanks to Matt Jallo for the suggestion).

  • 3.9.25: added ustrerror() to the standard Unicode support functions.

  • 3.9.25: fixed the d_edit_proc() GUI object to handle shift+tab focus movement properly.

  • 3.9.25: lots of Linux patches from George Foot (proper fbcon mode setting, different mouse types and setup program support for configuring them, fixes to the shared library support, exedat no longer destroys the file permissions, and probably some other stuff that I forgot about).

  • 3.9.24: assorted bugfixes to the Linux fbcon and sound code (this is mostly an emergency release because these were broken in 3.9.23).

  • 3.9.24: James Arthur wrote some docs for the Photoshop-style truecolor blender routines.

  • 3.9.23: Michael Bukin added an OSS sound driver to the Linux code, and the beginnings of an ESD driver.

  • 3.9.23: many Linux patches from George Foot, including shared library support.

  • 3.9.23: Ole Laursen made the Unicode utolower() and utoupper() functions understand the entire 16 bit character set.

  • 3.9.23: Pavlos Touboulidis made file_select() able to include or exclude files based on their attributes.

  • 3.9.23: the d_check_proc() GUI object can now print the text to the right of the check, selected by having a non-zero d1 field.

  • 3.9.23: changed my mind about how GFX_SAFE should work, and removed the color depth emulation bodges. Now, the GFX_SAFE driver may simply change the color depth if it doesn't like what you are requesting, and it is up to the caller to deal with this.

  • 3.9.23: fixed problems with MMX polygon rendering code in the MSVC version.

  • 3.9.23: added a strictwarn option to the configure script, and fixed everything that it moaned about. The warnings still aren't all that strict: at some point I want to sit down and make it build cleanly with -W, as well as -Wall -Werror.

  • 3.9.22: fixed some potential race conditions introduced by my previous fixes to the Windows timer code.

  • 3.9.22: made set_display_switch_callback() able to install multiple hook functions, added a remove_display_switch_callback() routine, and wrote an exswitch example program.

  • 3.9.22: adjusted MSVC inline asm syntax in an attempt to work around compiler version conflicts.

  • 3.9.22: more flexible GFX_SAFE system. As well as defining fixed safe values for each platform, you can now leave out those definitions to get zeros passed through to the actual hardware drivers, and if your driver sets a color depth other than the requested one, graphics.c will hook up some emulation routines so that everything still works in a sensible way.

  • 3.9.22: George Foot added a scancode to ASCII conversion function to the keyboard driver (implemented for DOS, Windows, Linux, and X). This is needed to handle alt+key input sensibly when using unusual mappings like the Dvorak layout.

  • 3.9.22: Linux patches from George add better console switching, shared library support, and various other nice things.

  • 3.9.22: Windows patch from Stefan adds much cool new stuff, including windowed mode support.

  • 3.9.22: Peter Wang made the Linux GGI driver work properly.

  • 3.9.22: Johan Venter made some more improvements to the RSXNT and Mingw32 makefiles.

  • 3.9.22: updated the Watcom makefile to allow manual override of the 10.6 vs. 11.0 version detection, in case it guesses wrong.

  • 3.9.21: Windows patch from Stefan adds support for the new screen mode switching system.

  • 3.9.21: more BeOS patches from Jason Wilkins.

  • 3.9.21: Johan Venter fixed some problems with the RSXNT and Mingw32 makefiles.

  • 3.9.21: ran "configure --enable-asm=no", and fixed all the reasons why this didn't work. In particular there was a bug in patterned drawing modes, RLE sprites were broken, and I'd forgotten to add C versions of the RGBA sprite functions. Those of you who are interested in such things will be interested to know that the test program thinks the C drawing code is 20% slower at hline(), 10% slower at rectfill(), 50% slower at blitting, and 40% slower at draw_sprite(), which is not at all bad going. It's actually a bit faster at drawing translucent and lit sprites, so we need to have a look at that!

  • 3.9.21: many new Linux patches from George Foot.

  • 3.9.21: added VBE/AF support to the Linux code.

  • 3.9.21: finished the Linux fbcon driver.

  • 3.9.21: made Linux console switching work in a more complete manner, with a set of helper functions in dispsw.c. The background mode should work now, but is untested.

  • 3.9.21: added Linux GGI driver by Carsten Schmidt (this is somewhat out of date, and doesn't work yet, but a good start if anyone wants to hack on it).

  • 3.9.21: improved the Unix configure and build system. Moved more things into makefile.lst, so there are no file lists anywhere else now. Made it understand how to build the datafile tools, and convert the documentation (this may cause problems for systems without makeinfo: it would be good if someone who groks autoconf could try to do this better). Made the Linux VGA drivers (vga and modex) configurable.

  • 3.9.21: added ctrl+alt+end abort sequence to the Linux keyboard driver.

  • 3.9.21: directory structure changes: moved ufile.c into the misc directory, so BeOS can share it. Moved various helper scripts into the misc directory, including a cmplog.pl that compares two test.exe profile logs.

  • 3.9.21: made the Linux PS2 mouse driver understand the middle button. Added a scaling factor to make it go at a more sensible speed in SVGA modes.

  • 3.9.20: started working on a driver for the Linux fbcon device. It works, but can't change video mode yet.

  • 3.9.20: Windows patch from Stefan adds joystick input, and the beginnings of a windowed mode driver.

  • 3.9.20: moved all filename lists (even the platform specific ones) into makefile.lst, to avoid any duplication and give us a nice centralised place that mentions every single source file we use.

  • 3.9.20: removed the install_lost_bitmap_callback() function, in favour of the more generic set_display_switch_mode(). Updated the Windows code to use these new routines.

  • 3.9.20: merged X patch from Michael Bukin (adds mouse support).

  • 3.9.20: Vincent Penquerc'h optimised the 256 to truecolor graphics blitting code to avoid repeated conversions of the palette table.

  • 3.9.20: James Hyman added quoting support to get_config_argv().

  • 3.9.20: Peter Cech optimised the alpha sprite blending routines. Shawn optimised them a bit more by expanding out specialised versions for common pixel formats.

  • 3.9.20: Richard Davies made some improvements to the PSX joypad driver.

  • 3.9.20: added a system driver parameter to allegro.cfg, and hooks to make the Unix version look for config data in /etc/ and ~/.

  • 3.9.20: moved the Posix findfirst() emulation into libc.c, removing it from the autoconf and BeOS specific builds.

  • 3.9.20: more BeOS patches from Jason Wilkins. The graphics stuff be working there now!

  • 3.9.20: improved the VBE/AF driver to know that vertical lines can be implemented as a rectfill. This enables hardware acceleration for patterned vertical lines, and with drivers that don't have hardware support for the VBE/AF line draw routine.

  • 3.9.20: George Foot did some major work on the Linux console version, getting it up and running in a fairly convincing way.

  • 3.9.20: the Windows sound driver lists are now dynamically generated based on the available devices, so you can select which ones to use.

  • 3.9.19: wrote the first part of an Allegro Hacker's Guide, which is my (probably futile :-) attempt to document at least a few of the more gory parts of the Allegro code.

  • 3.9.19: finally got around to documenting the Unicode functions.

  • 3.9.19: more BeOS patches from Jason Wilkins.

  • 3.9.19: Michael Bukin made some more patches to the X code (timers are implemented now), and added a complete (?) C implementation of all the drawing code. Non-Intel machines, here we come! If you define ALLEGRO_USE_C before building the djgpp library, you can actually test out a pure C version of test.exe, the demo game, etc.

  • 3.9.19: added a findtext.sh script, which scans the source code and creates a list of all the strings that are available for translation. It can also compare this list against an existing translation file, to see if any new messages need to be added.

  • 3.9.19: Stepan Roh updated the Czech keyboard mapping for Unicode support, added support for keyconf to use a non-standard font, and added the Latin Extended-A characters (U+0100 to U+017F) to the default font.

  • 3.9.19: Grzegorz Adam Hankiewicz updated the Spanish translation with UTF-8 format (ie. properly accented) strings. Converted the setup program font into Latin-1 ordering so that this will display correctly. Fixed bug with dat2s not correctly converting the resulting multiple-range font.

  • 3.9.19: Chris La Mantia made some cosmetic fixes to the d_slider_proc() GUI object.

  • 3.9.19: Richard Davies added support for N64 joypads.

  • 3.9.19: added keyboard_ucallback() (I missed this one when I first added the Unicode support).

  • 3.9.19: made some changes to setup.c so that it can easily be embedded into other programs (thanks to Grzegorz Adam Hankiewicz for the suggestion).

  • 3.9.18: added support for 32 bit RGBA images. You can now read TGA files with an alpha channel into the grabber, or you can import a normal image and then overlay alpha data from any greyscale bitmap. You can save these alpha channels as part of a datafile, call the makeacol(r, g, b, a) function, and most importantly, call set_alpha_blender() and then draw_trans_sprite() to display them. Check out exalpha.c. There is much room to optimise the 15, 16, and 24 bit versions of _blender_alpha*(), if anyone wants to have a go at this. I think it would be profitable to write specific versions for common pixel orderings, and only keep the current generic implementation around as an emergency fallback.

  • 3.9.18: more Unix patches from Michael Bukin. It builds flawlessly now, even if it doesn't do anything very interesting yet.

  • 3.9.18: Jason Wilkins contributed the beginnings of a BeOS port (not yet functional, but it does compile).

  • 3.9.18: Revin Guillen added a position_dialog() function.

  • 3.9.18: portability improvements: changed makefile to be a generated stub, which normally just includes makefile.all, but can be completely replaced when using autoconf, and moved the emulation for missing libc functions into the shared sources.

  • 3.9.18: numerous bugfixes.

  • 3.9.17: Burton Radons changed the truecolor pixel blending functions to use a single callback function rather than the previous table. This may break some old code, but should remain largely backward compatible, and the new way is much more flexible. He also added a more complete set of blender functions, including Photoshop modes like burn, difference, lumincance, etc.

  • 3.9.17: Richard Davies added support for PSX joypads.

  • 3.9.17: fixed bug in dat2s handling of truecolor images.

  • 3.9.17: Jason Wilkins improved the quaternion math routines, and added some documentation for them.

  • 3.9.17: Neil Townsend added callback parameters to the timer handlers.

  • 3.9.17: Gunter Ladwig added three-button mouse emulation, which can be enabled using the config file (it defaults to on if you have a two button mouse).

  • 3.9.16: applied some patches from Michael Bukin, which add the basics of a Unix build system. It doesn't actually work yet, though :-)

  • 3.9.16: merged new code from Stefan. Lots more cool things are working in the Windows version now, eg. hardware acceleration, triple buffering, sound...

  • 3.9.16: added an example of how to write a Windows screensaver using Allegro. If anyone knows how to get a proper name to show up in the Windows selection dialog, please let me know! (I've made the stringtable entry that MSDN says you need, but it doesn't work).

  • 3.9.16: Andy Goth added a d_text_list_proc() dialog object, that lets you alter the selection by typing the first few characters of a list entry.

  • 3.9.16: Ole Laursen updated the Danish message translation.

  • 3.9.16: Calvin French added a -w (always update) switch to dat.exe.

  • 3.9.16: Joerg Rueppel added more flexible wildcard matching for object names in dat.exe.

  • 3.9.16: added GFX_HW_SYS_TO_VRAM_BLIT and GFX_HW_SYS_TO_VRAM_BLIT_MASKED capabilities flags, and more flexible blitting functions in the vtable.

  • 3.9.16: added lock_voice() and unlock_voice() methods to the digital sound driver, for implementing audiostreams under Windows.

  • 3.9.16: _handle_timer_tick() now returns the desired gap until the next interrupt.

  • 3.9.15: Michael Rickmann added a Mingw32 port. This currently works the same way as the RSXNT version, using MSVC to build the DLL, but will become a full gcc port after the core Windows code stabilises a bit.

  • 3.9.15: Vincent Penquerc'h added a D_DIRTY flag for GUI objects, and I extended this with a new D_REDRAWME return code for the handlers.

  • 3.9.15: changed the syntax of the create_color_table() callback. This breaks the API, but is the only way to make it work reliably with different compiler calling conventions.

  • 3.9.15: added a sub bitmap creation hooks to the vtable structure (so the parent bitmap can be told when it is being cloned).

  • 3.9.15: "make install" is now a separate target, not run automatically. This means that you now have to run "make" and "make install" as two separate operations, or if you want all three versions of the library, "make all" and then "make installall".

  • 3.9.15: added an END_OF_MAIN() macro, which makes the WinMain() magic work correctly in any combination of C and C++ code.

  • 3.9.15: Olly Betts modified the djgpp makefile to support cross-compiling on a Linux machine.

  • 3.9.15: Andy Goth added a 256x256 tweaked VGA mode.

  • 3.9.15: major documentation update (from now on I'll be adding a version number to each changelog comment).

  • Merged new code from Stefan. Windows version is getting much closer to completion, including mouse support and video bitmaps, although the mouse code isn't working quite right for me at the moment.

  • Rewrote fix_filename_path() to avoid calling _fixpath(). The new version is much more portable, although things like reading the current directory across multiple drives need some tweaking to work with different compilers.

  • Fixed oodles of things that were stopping the Watcom version from working. It now runs everything without any trouble at all, including such gems as exdodgy and the grabber shell edit! According to test.exe, gcc 2.8.1 is about 10% faster than Watcom 10.6 for most things, although for some reason textout() is about twice as fast in the Watcom version.

  • Fixed a bunch of stuff to make the RSXNT version work. All the tests and examples now build with RSXNT, and work identically to the MSVC originals.

  • Added quaternion math routines by Jason Wilkins.

  • Added more flexible gfx_card config support by Andy Goth.

  • Added a masked_stretch_blit() function (trivial change, the code could do it, but the API entry point was missing).

  • Added Windows GDI routines by Marian Dvorsky.

  • Added a DMA poll to the Soundscape driver, to make sure it can never get out of sync with the transfer.

  • Merged various bits and pieces that have been sitting around my hard drive for ages (Swedish and Norwegian translations, various patches from Michael Bukin, new palette generation code by Michal Mertl, Soundscape driver fixes by Andreas Kluge).

  • Grabber now knows about and can manipulate Unicode fonts.

  • Now passing atexit() as a parameter to install_allegro(), to avoid problems with DLL shutdown.

  • Made FLIC player set the dirty variables when clearing the bitmap at the start/loop point (this was sometimes causing the screen not to be cleared from previous contents).

  • Fixed several bugs in the grabber.

  • Changed the datafile utilities to link the datedit and plugin routines as a proper library. This will make life easier for third parties that want to use those routines (duplicating the plugin linkage isn't much fun).

  • Replaced errno references with allegro_errno pointer, to avoid problems with multiple runtimes when linking as a DLL. The MSVC version of dat now works perfectly!

  • Added a system_none driver for commandline utilities and other platform neutral situations.

  • Made new demo intro animation. My first ever Max rendering!

  • Merged Windows patches from Stefan. Whoah! This thing is cool. It works (sort of :-) on two platforms. Now I can die happy....

  • The file selector now adjusts for platforms without any directory list (eg. Unix).

  • Added a global default_palette (the normal IBM BIOS one), and made set_gfx_mode() select it.

  • Modified DIGMID driver to avoid using 64 bit ints or floating point in the interrupt handler.

  • Added ASSERT() and TRACE() debugging routines, and lots of asserts throughout the library code.

  • The default truecolor pixel format before setting a video mode is now BGR rather than RGB. This should help to shake out bugs in BGR support, and catch any errors where people load graphics before setting a video mode.

  • Fixed fmul() overflow detection bug.

  • Rewrote gpro.c and sw.c to avoid using inline asm. The SW code is currently very ugly (literal translation of the asm routine), but I'm keen to improve it given some testing feedback. If you have a Gamepad Pro or Sidewinder, and were able to use it with the Allegro 3.11 driver, I would _really_ like to hear whether this current code works for you or not...

  • Numerous changes to make the support programs more portable.

  • Added a get_executable_name() function.

  • The sound.cfg file is no longer supported. Use allegro.cfg instead.

  • Added versions of the inline _putpixel() and _getpixel() for all color depths.

  • The check_cpu() function is now called automatically by allegro_init().

  • Added system bitmap objects, which exist in system memory but are accessed in a similar way to video memory surfaces (this can enable better hardware acceleration on some platforms).

  • Added enable_triple_buffer(), timer_can_simulate_retrace(), and timer_is_using_retrace() functions. This enables programs to correctly handle the interrelationship between mode-X triple buffering, the retrace sync mode, and the current OS, without having to include any DOS specific code.

  • GUI routines now call the input polling functions and acquire/release the screen as appropriate.

  • Fixed a real show-stopping error that was causing VBE/AF crashes on some machines (calling driver functions with non-flat memory selector in %es).

  • Added an allegro_message() function.

  • Added dummy bank switch routines that can emulate linear access to a mode-X screen, albeit rather slowly. The only practical result from this is that polygon routines work in mode-X now, but it helps to make things more robust in general (if a routine doesn't know about mode-X, now it will just run more slowly than usual, rather than not working at all).

  • The SB, Adlib, and standard joystick drivers now properly have a separate instance for each variant of the hardware, rather than a single driver pretending to exist under multiple different ID codes.

  • Rewrote joystick polling to avoid inline asm.

  • Converted translation files into UTF-8 format. These can now use any Unicode characters they like, so accented vowels etc. can safely be used.

  • Keyboard scancodes have changed from the hardware format to an abstract, Allegro-specific encoding. This simplifies the code a great deal, and avoids hassles with two different keys generating the same scancode.

  • Added generic find_allegro_resource() function, which removes a lot of duplicated code from config.c, digmid.c, and pckeys.c.

  • Timer module now autoinstalls whenever someone tries to use it.

  • Keyboard functions can now alter the repeat rate.

  • Watcom port.

  • Added a special GFX_SAFE driver ID.

  • Now using VDS to detect win95 even when in stealth mode.

  • Added fixver.sh for patching version numbers and dates when releasing a new version (requires bash, fileutils, shutils, etc, to run on DOS).

  • Added zipup.sh for building a distribution zip and diffs, which automatically cleans up the tree ready for this (eg. pregenerating the dependency files for all supported compilers).

  • Added input polling functions.

  • Major code restucturing, added system drivers, new framework for input handling, timers, keyboard scancode conversion, file access, etc.

  • Added full support for Unicode text, including string manipulation functions, a new font format, the textconv utility, a new GUI MSG_UCHAR, and a ureadkey() function.

  • Added variable sized monochrome fonts, replacing the the old 8x8 fixed size format. As a result, the GFX_HW_TEXTOUT_FIXED capabilities flag has been renamed to GFX_HW_GLYPH.

  • New system for accessing video memory, using bmp_select(), bmp_write*(), and bmp_unwrite_line(). This is equivalent to the djgpp farptr functions, but portable to different platforms.

  • Drastic reorganisation of directory structure, makefile system, etc.

  • Enhanced the makedoc utility to simplify adding links and email addresses to the docs.

  • Added a bodge to make the VESA code work with broken S3 Trio64 drivers.

  • Removed the 386DX vs. 386SX processor detection code (it was sometimes crashing).

Changes from 3.11 to 3.12 (Aug 1999)

  • Fixed a few incompatibilities with gcc 2.95. This release is otherwise identical to 3.11.

Changes from 3.1 to 3.11 (Feb 1999)

  • Cleaned up a few places where memory wasn't getting freed during the system shutdown. A cosmetic detail since the OS will free it for us, but it is nice to get these things right.

  • Alessandro Monopoli added an Italian translation of the system messages.

  • Henrik Stokseth added code to distinguish between win95 and win98.

  • Creative Labs have been removed from the THANKS file, because of their refusal to release any specs on the SB Live soundcard.

  • Changed the name of the library. After years of thinking that Allegro was a word with no particular meaning, I realised that it is in fact a recursive acronym for "Allegro Low Level Game Routines".

  • Established a new mailing list (conductors@canvaslink.com) for use by the people currently working on Allegro. Please send code contributions to this list rather than directly to me (Shawn Hargreaves), because this will allow Allegro development to continue even if I'm not around or am busy with something else at the moment.

  • Andreas Kluge wrote a driver for Ensoniq Soundscape cards.

  • More localisation: Swedish message translation by Sven Sandberg, Anton Ragnarsson, and Erik Sandberg, Finnish message translation by Antti Haapala, and Russian message translation and keyboard mapping by Dmitriy Kazimirow.

  • The midi_out() function now correctly updates the pan/volume/bend controller status.

  • Kester Maddock added a Wingman Warrior joystick driver.

  • Fixed some problems with the Sidewinder, Gamepad Pro, and SNES joypad drivers.

  • Changed the SB16 driver to use signed 16 bit output mode, rather than the previous unsigned format. Hopefully this will improve compatibility with crappy clone hardware.

  • Added a new WARNMODE environment switch to the makefile. Allegro developers should all set this to get strict warnings, but it will be left off by default so that the distributed version will be more forgiving about different compiler/libc versions.

  • Fixed problem with reading the top and left positions on digital joystick devices.

  • Fixed (I think, still waiting accurate confirmation on this one :-) problem with timers running too fast on some motherboards.

  • Fixed stupid bug where get_align_matrix() wasn't bothering to zero the translation vector.

  • Fixed stupid bug where rotated sprites were coming out upside down in mode-X and hi/truecolor modes.

  • Fixed bug where dat utility was truncating long filenames to 8.3 format.

  • Renamed the ChangeLog file to CHANGES, to avoid problems on 8.3 systems.

  • Various other minor bugfixes.

Changes from 3.0 to 3.1 (Jan 1999)

  • Changes between the 3.1 beta and final releases: assorted bugfixes, Antoine Mathys added a Swiss keyboard mapping, Thomas Wolf added a German translation of the system messages.

  • Changes between the 3.1 alpha and beta releases: assorted bugfixes, FLIC routines can now read from datafiles, included rotation optimisations by Ivan Baldo.

  • Peter Cech added support for hot-swapping between a custom keyboard layout and the standard US mapping.

  • Neil Townsend improved the accuracy of the timer routines.

  • Added exlights.c example program, showing one way to do colored lighting effects in a hicolor mode (and also because it makes the total number of examples a nice round number :-)

  • Added an afinfo test program, which does the same thing as vesainfo but for VBE/AF drivers.

  • Michael Bukin made a lot more portability patches and some bug fixes, including some improvements to the FLIC player and a much more rational filename handling system.

  • Removed the chipset-specific SVGA hardware drivers from the main library distribution. Instead, these will now be available both as an optional addon package, and reformatted as part of the FreeBE/AF project.

  • Added FreeBE/AF extensions support to the Allegro VBE/AF driver (farptr access to video memory, and the libc and pmode exports needed for future compatibility with the SciTech Nucleus drivers).

  • Fixed a bug with the patterned and translucent vline() function in 15 bit color depths.

  • Fixed a NULL pointer dereference bug in the config routines.

  • Fixed an order of processing bug that was causing data to be lost when calling set_config_file() with the same filename as the current config.

  • Stepan Roh added a Czech translation of the system messages.

  • Ole Laursen added a Danish translation of the system messages.

  • Grzegorz Ludorowski made a new demo game intro animation.

  • Calin Andrian added 3d polygon timing routines to test.exe.

  • Peter Cech added grabber support for the 8x8 BIOS font format.

  • Stepan Roh added a Czech keyboard mapping.

  • Renamed the Spanish language translation file from SP to ES.

  • Calin Andrian added a complete set of truecolor polygon rendering routines, with support for MMX and 3DNow! optimisations and a new masked lit drawing mode, along with a new polygon clipping function. One minor change is that POLYTYPE_FLAT mode is now implemented by calling hline(), so it will respond to the current drawing_mode() settings.

  • Changed the graphics/sound/joystick driver ID numbers from a zero based list to a descriptive 4-character string, to make them more readable and flexible. Added config functions to read/write data in this format. The sound config data is backwardly compatible, but you will need to manually update any graphics or joystick driver numbers that are stored in your config files.

  • Michael Bukin contributed a _lot_ of patches to improve the portability and robustness of pretty much the entire library. The only externally visible change is that the macros used for declaring hardware driver lists have been redesigned to use a more portable syntax, although the old syntax is still available as a compatibility macro.

  • Burton Radons did some more optimisation of the truecolor pixel blending functions.

  • Martijn Versteegh added a hook mechanism for extending the config file system, which can be used to provide extended system status information or customisation routines for addon packages.

  • Redesigned the grabber and dat utilities to support source-code "plugin" modules, which can be used to extend the system with additional object types, import/export routines, and menu commands.

  • Ivan Baldo added a dithering option to the 15/16 bit color conversion routines.

  • Kerry High added a SNES joypad driver.

  • Added a font override to the d_text_proc() and d_ctext_proc() GUI objects, using the dp2 field to specify a custom font.

  • Michael Tanczos fixed some bugs in the FLIC player.

  • Cloud Wu optimised the truecolor pixel blending functions.

  • Paul Pinault added a French translation of the system error messages.

  • Grzegorz Adam Hankiewicz added a Spanish translation of the system error messages, and added a new (but undocumented :-) command line option to the demo game.

  • Fixed clicks in the interpolated sample mixing.

  • Fixed a bug with position_mouse() not updating the mouse_pos variable.

  • Fixed a bug in mode-X horizontal scrolling while the timer retrace simulator is active.

  • Added a language.dat file, which can be used to provide translated versions of system strings (eg. error messages), in a similar way to the existing keyboard.dat. If you want to use this mechanism from your own code, replace all your constant strings with calls to get_config_text("string"). This allows them to be translated by including a line of the form "string=foreignstring" in the relevant section of language.dat.

  • Added an ASCII name field to the keyboard mapping files, in order to make the setup program a bit more friendly.

  • Increased the maximum number of sound channels from 32 to 64.

  • Modified the DIGMID patch loader to support 16 bit samples, rather than just reducing everything to 8 bit.

  • Added an interpolation option to the sample mixer (quality=2).

  • Salvador Eduardo Tropea added support for proper 16 bit sample mixing (quality=1).

  • Lee Killough added a lower level hook routine to the keyboard handler.

  • Removed floating point code from the DIGMID driver, to avoid potential FPU stack overflows.

  • Jim Flynn removed floating point calculations from the AWE32 MIDI driver (these could sometimes cause stack overflows).

  • Salvador Eduardo Tropea improved the datafile system to avoid linking of unused code.

  • Romano Signorelli contributed a Bresenham arc plotting function.

  • Thomas Wolf corrected some errors in the German keyboard mapping file.

  • Grzegorz Adam Hankiewicz improved the excolmap example program.

  • Sven Sandberg optimised the fixed point trig routines.

  • Fixed some silly crash bugs in the joystick code.

  • Added a "compress" target to the makefile, based on a suggestion by Grzegorz Adam Hankiewicz.

  • Added dummy bitmap acquire/release functions to allegro.h, for compatibility with the Windows version.

  • Added a cross-reference facility to the Info format documentation.

  • Martin Fuller fixed an obscure bug in the reading of compressed .bmp files.

  • The emergency exit signal handler now correctly restores the previous handler, rather than resetting to the default action.

  • Sven Sandberg optimised the create_light_table() function.

  • George Foot fixed a bug when the get_mouse_mickeys() routine was called with both parameters pointing to the same value.

  • Changed the licensing terms from "swapware" to "giftware". See the Allegro website for an explanation of the reasons for this change.

  • Added yet more overloaded operators (this time for long and double types) to the fix class.

  • Marius Fodor added support for the Sidewinder and Gravis GamePad Pro. Many apologies for my taking so long to merge in this code!

  • Stefan Schimanski optimised the reverse blitting routine (for overlapping images).

  • Added a shift+tab reverse focus movement key to the GUI routines.

  • Grzegorz Adam Hankiewicz added a new example showing how to create and use a custom color mapping table.

  • Totally revamped the joystick system (better API and new driver structure).

  • Modified the fix class to work properly with gcc 2.8.0.

  • Added a help.txt "how to get tech support" file.

  • The midi_pos variable is now negated, rather than cleared to -1, at the end of a MIDI file. This can be used for measuring the length of a file.

  • Added a rendering hook to the font structure, for use by text addon packages.

  • Improved the VBE/AF text output routine.

  • Corrected an error in the way the VBE/AF driver interprets hardware cursor colors.

  • Pedro Cardoso contributed a tweaked 80x80 VGA mode.

  • The VBE/AF driver now supports dumb framebuffer drivers as well as accelerated ones.

  • Added more accelerator support to the VBE/AF driver (hardware cursors, lines, vertical lines, triangles, fixed width text output, and opaque/masked blitting from system memory to the screen).

  • Added a scare_mouse() function, based on ideas by Martijn Versteegh.

  • The grabber now stores the "grab from grid" dialog state in allegro.cfg.

  • Sven Sandberg fixed a problem with save_bitmap() widths being rounded upwards.

  • Made the _timer_installed flag globally visible.

  • Ove Kaaven added linear framebuffer support to the native mach64 driver.

  • Erik Sandberg optimised the 8 bit draw_sprite() and draw_trans_sprite() functions.

  • Michal Mertl fixed a memory leak in the generate_optimized_palette() function.

  • Added an ALLEGRO_DATE version define to allegro.h.

  • Michael Bukin optimised the line drawing routine and fixed problem with the inline asm constraints for fadd()/fsub().

  • Fixed potential problems caused by a lag between the mouse state variables changing and the pointer being redrawn.

  • Michal Mertl optimised the clipping code for lines, rectangles, and circles.

  • Maiolino Carmelo contributed an Italian keyboard mapping.

  • Fixed lockup problems caused by the keyboard LED functions on some platforms/hardware.

  • Added new create_video_bitmap() and show_video_bitmap() functions.

  • Added a profile option to the test program.

  • The keyboard handler now correctly updates the BIOS state for the right control and alt keys when it shuts down.

  • Fixed a problem that was preventing the DIGMID driver from reading patch sets stored in executable appended datafiles.

  • Changed the default sample priority from 255 to 128.

  • Fixed some problems with virtual screen sizes in the VBE/AF driver.

  • Added two new example programs.

  • The VBE/AF driver now has full support for hardware accelerated drawing.

  • Added VBE 3.0 support, including new triple buffering routines.

  • Wrote a routine to select the sound input source (microphone, line input or CD audio).

  • Added proper support for stereo samples. This requires an extra parameter to the play_audio_stream() function, so you will need to change any programs that use this. I'm very sorry for breaking your old code!

  • Fixed bugs with the SB16 autodetection and 16 bit sample recording.

  • Added input support to the raw SB MIDI interface driver.

  • Wrote a new test program to demonstrate the audio input features.

  • Ove Kaaven added support for MIDI and audio (sampled sound) input.

  • The pack_fopen() function now understands nested datafiles as directory structures, using filenames like "graphics.dat#level1/sprites/zdurgle".

  • Charles Mac Donald showed me how to set a 160x120 VGA mode, and more reliable 400x* mode-X resolutions.

  • Guilherme Silveira and Theuzifan Sumachingun both independently modified the file selector to only list valid drive letters.

  • Carsten Sorensen added a driver for the ESS AudioDrive soundcard.

  • Przemek Podsiadly added hicolor versions of the 3d polygon routines.

  • Ove Kaaven added truecolor support to the native ATI mach64 driver.

  • Patrick Hogan added a draw_gouraud_sprite() function.

  • Ben Chauveau added a driver for Tseng ET6000 cards.

  • Marco Campinoti added truecolor support to the native Tseng ET4000 driver.

  • Marco Marmulla added 16 bit support to the load_voc() routine.

  • Added Danish, Swedish, and Norwegian keyboard mappings.

  • Added GUI hook functions for scaling or offsetting the mouse position.

  • Fixed bug which was causing a lockup when calling set_leds(-1).

  • Michael Bevin optimised the create_trans_table() function.

  • It is now possible to display a mouse pointer without the mouse handler needing to be installed.

  • Added a create_sample() function.

  • Made the _blender_map pixel blending functions and the _mouse_installed, _keyboard_installed, and _sound_installed flags globally visible.

  • Added an 8-button joystick mode.

  • Chris La Mantia fixed a minor visual problem with the d_icon_proc().

  • Added a Rich Text Format (.rtf) version of the documentation.

  • Added postfix increment and decrement operators to the C++ fix class, and the unary negation operator is now const-correct.

Changes from 3.0 beta to release (Dec 1997)

  • The pat2dat utility can now import instruments from AWE32 SoundFont files.

  • Optimised the DIGMID patch loader and fixed a couple of bugs.

  • Ove Kaaven fixed the ATI mach64 driver.

  • The config file can now mention several possible video drivers, using lines in the form gfx_driver=x, gfx_driver2=x, etc.

  • Improved the native SVGA driver helper functions, making it easier to add truecolor support to the register level drivers.

  • Double-clicking on a font object in the grabber now allows you to view the extended characters as well as normal ASCII.

  • Markus Oberhumer corrected a potential problem with the Video-7 initialisation code.

  • Markus Oberhumer, Bitland, and Sormuras all sent me mapping tables for the German keyboard layout. Coordination of effort: who needs it? :-)

  • Mathieu Lafon improved the French keyboard mapping.

  • Fixed some bugs in the MIDI voice allocation system.

  • Added a -k (keep names) option to the dat utility.

  • The setup program now uses the ALLEGRO environment variable to locate the keyboard.dat file.

  • Fixed a problem with < and > characters in the HTML documentation.

Changes from 2.2 to 3.0 beta (Nov 1997)

  • Merged in George's improved instrument parameters for the AWE32 driver.

  • The pat2dat utility can now reduce sample data from 16 to 8 bits (saves space, and the DIGMID driver only uses 8 bits in any case).

  • Added yet another version of the mouse handler, this time in an attempt to make it work more reliably under Windows NT.

  • Frodo Baggins added a mapping table for Portuguese keyboards.

  • Added an external tool "shell" function to the grabber.

  • Added a "box grab" function to the grabber, which uses a color #255 bounding box to determine the extent of the sprite to grab.

  • Santeri Saarimaa added a Finnish keyboard mapping.

  • Finished writing the pat2dat utility, and the DIGMID driver is working a lot better now.

  • Mathieu Lafon added support for the Pause and PrtScr keys, and changed the key[] array to a bitfield indicating whether either or both of the normal and extended versions of the key are pressed. This remains compatible with the "if (key[KEY_*])" syntax, but also allows you to distinguish between, for example, the Enter key on the numeric pad and the one next to the right shift key.

  • Fixed a bug in the handling of config variables that don't belong to any section.

  • The makefile now tries to detect and warn people about some of the more common installation errors.

  • The HTML version of the documentation now uses a short .htm file extension if it is built on a system with LFN disabled.

  • Keyboard mapping files now only bother saving the entries that differ from the default US mapping. This makes the maps a great deal smaller!

  • Changed the default font and keyboard mapping tables from DOS codepage 437 to the standard ISO charset (first part of Unicode). If you have made a keyboard config using the old codepage it will need to be updated, but don't worry, I have a script that can do this very easily.

  • Fixed a bug in the detection of font formats (fixed or proportional) when grabbing from a bitmap font.

  • Added an editable loop point to the MIDI player (thanks to George for sorting out how to do this...)

  • Rewrote the mouse handler to track the position itself, using only the mickey counters from the int 0x33 driver. Hopefully this will fix the problem with buggy Logitech drivers...

  • Added a mouse_pos variable containing both the X and Y values in one 32 bit location, to allow a single instruction read during tight polling loops.

  • The grabber now supports multiple selection, and has a new "ungrab" command that copies from a bitmap object into the scratch buffer (you can use this to generate palettes from truecolor images, or to re-grab a smaller area from the image).

  • Added multiple selection abilities to the GUI listbox object.

  • Theuzifan improved the cpu detection for Cyrix chips.

  • Mathieu Lafon added a French keyboard mapping.

  • Richard Mitton wrote an example program demonstrating how to fake a 12 bit truecolor display on an 8 bit card.

  • Michal Mertl added a routine for generating optimised palettes for a specific truecolor image.

  • Optimised the getr/g/b() functions. Converting between different color depths should be much faster now...

  • Scott Harrison added code to detect OpenDOS, and use the i_love_bill mode if their version of EMM386 is in use.

  • Added some new example programs.

  • The makedoc utility now converts between the DOS and Windows extended character sets when producing HTML output files.

  • Ettore Perazzoli made a spectacular optimisation to the linear -> mode-X blitting function.

  • Added a grid option to the dat utility, to specify which region of a bitmap you want to grab.

  • Fixed a bug in blitting truecolor bitmaps onto mode-X destinations.

  • Fixed a bug that was preventing the Adlib volume from being changed when only MIDI sound drivers were installed.

  • The grabber can now be run in video modes other than 640x480 (it doesn't look very nice in lower resolutions, though :-)

  • Added a new fake scancode for the extended / key (the one on the numeric keypad) so that the two keys can be distinguished from each other.

  • Joaquin Hierro Diaz made a mapping table for Spanish keyboards.

  • The setup utility can now be used to select a keyboard layout and to calibrate the joystick, as well as for the sound hardware.

  • Moved some of the documentation to different locations, so hopefully people will now be less likely to miss the faq.txt, and to bring it closer in line with the standard GNU distribution format.

  • Better keyboard configuration system. There is now a proper utility for setting up the mapping tables, the tables can be read from external files, and it properly supports the alt-gr and accent escape keys.

  • Menu items can now be disabled, have check marks next to them, and support right aligned text eg. for displaying keyboard shortcuts, there is a new "void *dp" field in the menu structure, and the click callback routines can now use the global pointer "active_menu" to determine which option they were called by, if a single routine is shared by several menu items.

  • Peter Palotas added an input callback to the keyboard routines, and event flags to the mouse callback.

  • Added a -pal option to the dat utility.

  • Grzegorz Ludorowski made some new graphics for the demo game.

  • Moved some code to new files and added a bunch of macros so you can remove unused graphics and sound drivers at link time.

  • Fabian Nunez added support for the Logitech Wingman Extreme joystick.

  • Chris La Mantia contributed a d_slider_proc() dialog object.

  • Sean Gugler added a routine for changing the keyboard LED state.

  • George Foot added pause and seek functions to the MIDI player.

  • Added the ability to append datafiles (in fact any files at all) onto the end of your program executable.

  • Merged in the AWE32 driver. Long live George!

  • Can now read RLE compressed TGA files.

  • Added a mouse movement callback function (useful for detecting double click events).

  • Stefan Eilert added support for dual joysticks.

  • Seymour Shlien contributed a routine for drawing justified text.

  • Krzysztof Krzyzaniak contributed a loader for .VOC sample files.

  • Added a rotate_scaled_sprite() function.

  • Now supports the Dvorak keyboard layout.

  • Salvador Eduardo Tropea added a 320x100 VGA mode.

  • Implemented translucent and lit sprite and RLE sprite drawing functions for the truecolor modes.

  • Updated the sound setup utility.

  • The dat utility can now output makefile dependencies for automatically rebuilding the file when any of the source data changes.

  • Fixed some problems with the RGB <-> HSV conversion functions.

  • Truecolor image loading and grabber support.

  • Phil Frisbie provided some code to detect the CPU type.

  • Michal Mertl added 24 bit graphics modes. Hurrah!

  • Added functions for playing streams of digital audio data.

  • Chris La Mantia contributed a bitmap icon GUI object.

  • Doug Eleveld added a text box GUI object, plus an improved help system for the grabber.

  • Added support for UK and AZERTY keyboard layouts. More can easily be added if you send me the appropriate scancode -> ASCII mapping tables...

  • Added get_align_matrix(), qtranslate_matrix(), and qscale_matrix() functions.

  • Added a draw_character() function for using sprites as monochrome pixel masks.

  • It is now safe to pass the same matrix as both input and output to the matrix_mul() function.

  • Paul Bartrum contributed some ellipse drawing functions.

  • Added some callbacks to the MIDI driver, allowing you to hook your own code into MIDI notes or marker events.

  • Added a function to measure mouse movement in terms of mickeys (difference since the last call) as well as in absolute screen coordinates.

  • VolkerOth made the d_edit_proc objects able to scroll, if the string is larger than the available space.

  • Added the ability to distinguish between the left and right Control and Alt keys.

  • Fabian Nunez added support for the extra keys on a Microsoft keyboard.

  • Added void *dp2 and void *dp3 fields to the dialog structure. This ought not to break any existing code, but will let you store a lot more data when creating custom objects.

  • The packfile functions can now directly open and read from datafile member objects, using fake filenames in the form "filename.dat#obj_name". This means that all the Allegro file access routines (eg. load_pcx() and set_config_file()) can now read from datafile objects as well as separate files.

  • Added miditest and digitest programs to allow more rigorous testing of the sound routines and patch sets, and a vesainfo program to check which video modes are available on any given card.

  • Jan Hubicka wrote a faster version of create_rgb_table().

  • The grabber now scales the bitmap preview if the image is too large to fit onto the screen.

  • Jorrit Rouwe provided a new and much cooler set of FM instrument definitions for the Adlib MIDI driver.

  • Added a function to load .IBK patch sets for use by the Adlib driver.

  • Added a wrapper allegro/ directory around the contents of the zip file, so it can now be safely unzipped into the main djgpp directory.

  • Richard Mitton added support for 6-button joysticks.

  • Truecolor (15, 16, and 32 bit) graphics modes.

  • Vastly improved sound routines (more flexible API, now supports up to 32 simultaneous voices on the SB, sample-based MIDI playback driver, can reverse samples, volume/pan/pitch sweep effects, MIDI commands can be output on the fly as well as played from MIDI files, and lots of other goodies).

  • It is now possible to update the status of GUI dialogs incrementally from your own control loops, with an update_dialog() function, rather than completely transferring control to do_dialog().

  • Compressed files (including grabber datafiles) can now be encypted with a password.

  • Added a masked_blit() function, that skips zero pixels.

  • Added code to detect being run under Linux DOSEMU, and use the less demanding version of the timer code if this is the case.

  • Added a standardised configuration mechanism. The format for saved joystick calibration information has changed, so existing joystick files are no longer valid.

  • Added a textprintf() routine, which uses a printf() style format string.

  • Added a TexInfo version of the documentation (thanks for the help, Francois!)

  • Jonas Petersen added a save_bmp() function, and support for the OS/2 BMP format.

Changes from 2.11 to 2.2 (Feb 1997)

  • TBD/FeR added tweaked 320x600 and 360x600 resolutions to the mode-X driver.

  • Matthew Bowie added support for 4-button joysticks.

  • Dave Thomson added RGB <-> HSV conversion functions.

  • Added a 'freeze_mouse_flag' variable, that can be used to lock the pointer to a specific position.

  • Added a 'key_led_flag' variable, that can be used to prevent the keyboard LED's updating in response to the capslock, numlock, and scroll-lock keys.

  • The midi player now resets midi_pos to -1 when the music finishes playing.

  • Adrian Oboroc wrote an LBM loader.

  • Fonts can now contain characters above ASCII 127.

  • Chris Wigman made a better intro animation for the demo game.

  • Added translucency, color blending, and lighting routines (based on code by Owen Embury and ideas by Nathan Albury).

  • Added 3d math and matrix manipulation functions.

  • Added texture mapped and gouraud shaded polygon drawers.

  • Tim Gunn contributed code for reading and writing TGA files.

  • Fixed clamping problems with rotating non-circular sprites.

  • Added scrollbars to the GUI listbox object.

  • Seymour Shlien wrote a bezier spline drawing function.

  • Added fixed point fadd() and fsub() functions, which check for overflow.

  • Added pack_fseek() and chunk manipulation functions to the file routines.

  • Improved datafile structure and grabber program.

  • Wrote a utility to convert grabber datafiles into linkable asm code.

  • Salvador Eduardo Tropea improved the keyboard routines (better handling of extended scancodes, keyboard LED support, capslock and numlock, and alt+numpad input).

  • Fixed the packfile functions and file selector to work with long filenames under win95.

  • Seymour Shlien contributed a BMP reader.

  • Added a hook function to the keyboard code, allowing you to use the GUI code without installing the keyboard handler.

  • Fixed a lockup caused by trying to access non-existent floppy drives.

  • Francois Charton wrote a driver for Paradise graphics cards.

  • Chris La Mantia contributed a radio button GUI dialog object and added a D_DISABLED object flag.

  • Markus F.X.J. Oberhumer fixed the Video-7 scrolling function.

  • Converted the docs into HTML format.

  • Added code to detect Windows NT.

  • Mark Habersack added support for newer Trident chipsets.

  • Did some more work on the VBE/AF driver (it now works, but still doesn't support accelerated hardware features).

  • Fixed bugs in the WAV sample reader and FLIC player.

  • Added special 'windows friendly' mode to the timer code. You can now even run demo.exe under Windows 3.1!

  • Reorganised directory structure, to allow for a Linux version. The output liballeg.a is now found in lib/djgpp.

  • Added support for 8x16 BIOS format fonts.

  • Fixed a problem with overflow when rotating large sprites.

  • Fixed a problem with restoring the text mode screen height after running Allegro programs.

Changes from 2.1 to 2.11 (Nov 1996)

  • Fixed bug in bank.S.

  • install_mouse() now sets the range to (0,0,SCREEN_W,SCREEN_H).

  • install_sound() does not automatically set the volume to maximum.

  • Added ++ and -- operators to class fix.

  • Makefile now copies liballeg.a to lib, and allegro.h to include.

  • Made a few changes to work under LFN=y (if you use unzip or winzip instead of pkunzip).

  • Added manifest.

  • Clarified installation instructions.

Changes from 2.0 to 2.1 (June 1996)

  • Mode-X support (thanks to Jonathan Tarbox and Dominique Biesmans for suggesting and then helping to implement this).

  • Compiled sprites.

  • Jonathan Tarbox contributed an FLI/FLC player.

  • Added patterned drawing modes.

  • Added a vertical retrace interrupt simulator.

  • polygon() can now handle concave and self-intersecting shapes. I also changed the parameters a bit. Sorry if this breaks your old code, but it's more efficient the new way...

  • Added stretch_sprite().

  • Wrote a floodfill() routine.

  • More flexible palette fade routines.

  • Added set_volume() to the sound code.

  • David Calvin wrote a sound setup utility.

  • Improved the GUI. Added popup/dropdown menus, joystick input, three button alert boxes, better handling of arrow key focus movement, a new keyboard shortcut object (d_keyboard_proc()), and '&' markers in strings to display keyboard shortcuts. The GUI can also now be used with fonts other than the standard 8x8 default, by altering the global 'font' pointer.

  • Fabian Nunez added support for the CH Flightstick Pro joystick (looks cool: I want one :-) and 3-button mice.

  • The keyboard handler now responds to the state of the ctrl and alt keys, and there is a new simulate_keypress() function.

  • Mark Wodrich added sub-bitmaps, which share their memory with a parent bitmap but can be positioned anywhere within it, and have their own clipping rectangles.

  • Mark also modified the mouse driver to double-buffer the pointer (so it doesn't flicker any more), and added a set_mouse_sprite_focus() function.

  • Added set_mouse_range() and set_mouse_speed() functions.

  • Thanks (again) to Mark Wodrich, the grabber can now import GRX .FNT files.

  • The grabber can now make backups when saving datafiles, and it only writes the datafile headers if their contents have changed, to prevent unnecessary recompilation.

  • Added a text_height() function.

  • The fixed point inverse sin and inverse cos functions now use lookup tables, which makes them a lot faster.

  • Reorganised the directory structure, added some example programs, and improved the documentation.

Changes from 2.0 beta to release (March 1996)

  • Marcel de Kogel fixed some problems with the MPU-401 driver. It now actually works :-)

  • Marcel also provided some better drum sounds for the Adlib driver.

  • Inlined the fmul() and fdiv() functions.

  • Much faster fsqrt(), taken from Arne Steinarson's fix-float library.

  • Added inline bmp_write_line(), bmp_read_line(), and _putpixel() functions.

  • The keyboard routines now support the emergency abort sequence ctrl+alt+del, and there are signal handlers to make sure Allegro will shut down cleanly if your program crashes.

  • Wrote new irq wrappers that can deal with reentrant interrupts.

  • Added joystick routines (based on code provided by Jonathan Tarbox and Marcel de Kogel).

  • Moved some functions to different files and juggled things about so the linker can do a better job. If you don't use the sound stuff, or don't use any graphics functions, now they won't be linked into your executable.

  • Marcel de Kogel manged to locate my (embarrassingly stupid :-) mistake which was preventing the VESA 2.0 linear framebuffer driver from working.

  • Various other performance enhancements and bug fixes.

Changes from 1.x to 2.0 beta (Jan/Feb 1996)

  • Dropped all the Borland code. A couple of months ago I ran out of disk space, and it was with great satisfaction the I executed the command 'deltree /y c:\bc4'. It was a horrible compiler, and I'm glad it's dead.

  • Added SVGA support. As a result it no longer makes sense for allegro_init() to put the system into mode 13h, so you will be in text mode until you call set_gfx_mode().

  • Added sound code (background MIDI music and sample mixing).

  • Added support for proportional fonts (of any size) as well as the old 8x8 fixed size ones.

  • XOR drawing mode.

  • There is no longer such a thing as a SPRITE structure. The sprite drawing code now draws bitmaps onto other bitmaps, which is a much more flexible way of doing things. The datafile reader will convert all your old sprites to bitmaps as it loads them in, so the only practical difference this is likely to make is that the sprite drawing routines can't draw opaque sprites any more (but you can use a blit instead).

  • show() and get_sprite() no longer exist: use blit() instead.

  • Added flipped and rotated sprite draw routines.

  • Added bitmap scaling.

  • Added RLE sprites.

  • drawsprite() has been renamed to draw_sprite().

  • textmode() has been renamed to text_mode(), to avoid conflicts with definitions in conio.h.

  • All the file access functions have been renamed from the stdio syntax to pack_fopen(), pack_getc(), etc, so they can now be mixed with stdio code.

  • Added pack_fgets() and pack_fputs().

  • The port_callback pointer no longer exists.

  • Removed polyline() (who ever used it?), and added a polygon(), which draws a filled convex polygon with an arbitrary number of vertices.

  • Added do_line() and do_circle() functions, which call a user-supplied function for each pixel that needs to be drawn.

  • Added a default keyboard interface to the GUI routines, allowing the selection of objects with the arrow keys and <enter>.

  • Added several new GUI messages and flags. In particular there are now messages for tracking mouse cursor movement, an idle message, a special return value for the MSG_CHAR message which allows an object to override the default keyboard handling, and a flag which hides the object.

  • There are new GUI routines to centre a dialog on the screen and to alter the colors used by the standard alert and file selector dialogs.

  • The file selector now takes a third parameter specifying which file extensions to display.

  • The timer routines now have better than millisecond accuracy, and it is possible to alter the speed of a user timer callback in realtime (by reinstalling it with a different speed value).

  • Removed the _RGB struct and paltorgb() functions. RGB's are now stored directly in the hardware format, with each value in the range 0-63.

  • Added functions to get and set single palette entries as well as entire palettes.

  • Added DPMI memory locking code.

  • Wrote a C++ 'fix' class which overloads a lot of operators, providing an easy way to use the fixed point routines.

  • There are probably lots of other things that I have forgotten about.


Allegro Contributors

The Hall of Fame

I hope I've remembered everyone who ought to be mentioned here. If your name should be included, my apologies, and please tell me so I can correct the oversight!

Contributors

A.Cottrell (andrewc at dbworld dot net dot au).
Changed the grabber to use a more robust (locale-independent) date format.

Adrian Oboroc (doba at corefx dot com).
Wrote the LBM loader.

Alex Demko (alex_demko at mbnet dot mb dot ca).
Suggested lots of improvements to the datafile system, and provided code for handling the 8x16 BIOS font format.

Alessandro Monopoli (almonopo at tin dot it).
Added the Italian translation of the system messages.

Andreas Kluge (bitland at aol dot com).
Wrote the Ensoniq Soundscape driver and fixed division bugs in the fix class.

Andrei Ellman (ae-a at wackonet dot fsnet dot co dot uk).
Contributed the polygon_z_normal() function and suggested some additions to the docs.

Andrew Ellem (krand at ican dot net).
Wrote the original version of the digital audio streaming code.

Andrew Geers (andy at geerswj dot clara dot net).
Added the -ppassword and -nosound options to the grabber, scrolling support in the image viewer, and the flipped rotated sprite routines.

Andy Goth (andygoth at vetec dot com).
Made the gfx_card config variable more flexible, added the 256x256 tweaked VGA mode, and wrote the d_text_list_proc() dialog object.

Angelo Mottola (a dot mottola at libero dot it).
Added the BeOS joystick, MIDI and windowed graphics drivers, added mouse wheel, display switching and close button support for BeOS, and wrote the DGA2 driver and close button support for X. Contributed a bfixicon utility. Added triple buffering support to the BeOS port and added fetch_mode_list() to the BeOS and DGA2 fullscreen drivers. And, oh, contributed the QNX port too.

Annie Testes (annie at kezako dot net).
Added font_height, render_char, char_length hooks to FONT_VTABLE. Fixed several glitches in the unicode support. Added a pack_fdopen() function. Caught a misordering in the X system shutdown. Found ASCII strings that needed to be converted. Fixed some device name strings in the setup program. Fixed a bug with patterned drawing in the C version and another one with asynchronous I/O mode restoring under Linux.

Antoine Mathys (mmathys at bluewin dot ch).
Added the Swiss keyboard mapping.

Anton Ragnarsson (anton dot ragnarsson at swipnet dot se).
Contributed the Swedish keyboard mapping table.

Antti Haapala (ztane at lyseo dot edu dot ouka dot fi).
Fixed the setup program to display the right frequency list for each type of soundcard, and contributed the Finnish translation of the system messages.

Antti Koskipaa (antti dot koskipaa at nic dot fi).
Wrote the DOS driver for WSS (Windows Sound System) cards.

Arne Steinarson (arst at ludd dot luth dot se).
The fixed point square root routine came from his fix-float library.

Attila Szilagyi (attilabox at hotmail dot com).
Fixed SVGAlib horizontal scrolling.

Ben Chauveau (bendomc at worldnet dot fr).
Added support for Tseng ET6000 cards (now available as part of the FreeBE/AF project).

Ben Darnell (bdarnell at vnet dot net).
Put together the 2.11 release of Allegro while I was away from the net, and wrote the original version of the Allegro FAQ.

Ben Davis (entheh at users dot sf dot net).
Added set_volume_per_voice(), made silent voices continue playing, and fixed other minor bugs in the mixer. Fixed a bug in create_rgb_table(). Adapted polygon functions to handle two coincident vertices. Added the set_window_close_button() and set_window_close_hook() framework. Added support for timers with parameters under Windows. Documented the non-standard behaviour of pack_feof().

Benjamin Joel Stover (stovertech at intellisys dot net).
Wrote the initial version of the fullscreen X-Windows graphics driver.

Benny Colyn (email unknown).
Added a Dutch translation.

Bertrand Coconnier (bcoconni at club-internet dot fr).
Modified routines in poly3d.c for subpixel and subtexel accuracy. Speed enhancements in polygon functions. Fixed blending in C version of atex_lit scanline functions, added scanline subdivisions in C scanline functions and Z-buffer polygon functions. Merged in Calin Andrian's P3D library.

Burton Radons (loth at gec dot net).
Optimised the truecolor pixel blending function, converted the blenders to the new single-handler format, and added the range of Photoshop-compatible blender functions.

Calin Andrian (calin at ibd dot dbio dot ro).
Wrote the truecolor, MMX, 3DNow!, masked lit mode, translucent and Z-buffered polygon rendering routines, the clip3d_f() function, and also the scanline sorting functions for 3D scene rendering, and his P3D addon library was merged in.

Calvin French (frenchc at home dot com).
Added the -w (always update) switch to dat.exe.

Carsten Schmidt (email unknown).
Wrote the the initial version of the Linux GGI driver.

Carsten Sorensen (csorensen at ea dot com).
Wrote the the ESS AudioDrive soundcard driver.

Cloud Wu (cloudwu at 263 dot net).
Optimised the truecolor pixel blending functions.

Chris Graham.
Suggested to add a new flag for Windows NTFS compressed files.

Chris Jones (cj at jibblers dot plus dot com).
Worked around a problem with DOS file attributes under Win2k.

Chris La Mantia (celamantia at home dot com).
Wrote the d_radio_proc(), d_icon_proc(), and d_slider_proc() dialog objects, added the D_DISABLED flag, improved the GUI handling of different font heights, and added the right aligned text functions.

Chris Robinson (crobin_99 at yahoo dot com).
Wrote the fixed point clip3d() function.

Christian Schueler (cschueler at gmx dot de).
Changed the optimisation settings for better performance.

Daniel Nilsson (daniel7 at algonet dot se).
Enlarged the starfield in exstars, and fixed an incorrect range in exlights.

Daniel Schlydler (daniel at dascdev dot net).
Fixed problems with get_executable_name() under Windows.

David A. Capello (dacap at users dot sourceforge dot net).
Made dotted_rect() avoid bank switches. Fixed a problem with lost GUI mouse clicks. Made d_menu_proc steal/return focus when activated/deactivated and fixed a problem with submenus.

David Kuhling (dkuelhin at hell1og dot be dot schule dot de).
Optimised the fsqrt() routine, and added fhypot().

Dave Thomson (gameskitchen at geocities dot com).
Added the RGB <-> HSV conversion routines, the autocrop function to the grabber, and wrote the 3d starfield example program (exstars.exe).

David Calvin (calvid at rpi dot edu).
Wrote the original version of the sound setup utility.

Deepak T (coolbool at gmx dot net).
Fixed clipping in three C sprite drawing routines.

Dmitriy Kazimirow (mariann at mail dot ru).
Provided the Russian keyboard mapping and message translation files.

Dominique Biesmans (Dominique dot Biesmans at ping dot be).
Wrote the mode-X version of draw_sprite() and the mode-X <-> linear blitting functions.

Doug Eleveld (D dot J dot Eleveld at anest dot azg dot nl).
Wrote the d_textbox_proc() dialog object and the new grabber help system.

Eduard Bloch (edi at gmx dot de).
Fixed a freeze caused by the ESD detection code, fixed a bad behaviour of the config routines, and suggested better ways to find the path to the executable in Unix.

Edward Boone (Lucien dot Boone at ping dot be).
Provided scancode mapping tables for the AZERTY keyboard layout.

Elias Pschernig (eliaspschernig at aon dot at).
Added a COLORCONV_KEEP_TRANS mode. Contributed the wfixicon utility. Contributed several enhancements to the grabber. Fixed a bug in midi_seek(). Added support to use the saved window position for initial window placing under Windows. Optimized the load_bitmap() function family when no palette is specified and documented the feature. Revamped the cross-compilation section of docs/build/mingw32.txt.

Eric Botcazou (ebotcazou at multimania dot com).
Made the DGA driver work better in 8bpp and 32bpp modes, improved the DirectX windowed driver and Windows graphics subsystem, partially revamped the Unicode API and added uszprintf(), added file_select_ex(), the unified al_find*() interface, an Unicode example, a new filetest, rewrote the fixdll script, revamped the Borland C++ build process, fixed lots of bugs and did truckloads more work on the Windows port too.

Erik Sandberg (eriksandberg at geocities dot com).
Optimised the 8 bit draw_sprite() and draw_trans_sprite() functions, and helped with the Swedish message translation.

Ettore Perazzoli (ettore at comm2000 dot it).
Optimised the linear -> mode-X blitting function.

Evert Glebbeek (eglebbk at dds dot nl).
Put set_gfx_mode on a diet, added a config entry for specifying the card to be used for GFX_AUTODETECT_WINDOWED, added a '-fullscreen' switch to the grabber, added the detection of SunOS/Solaris and added configure options for x86 processor optimisations on Unix systems.

Fabian Nunez (faybs at iafrica dot com).
Added support for the CH Flightstick Pro and Logitech Wingman Extreme joysticks, 3-button mice, and the extended keys on a Microsoft keyboard.

Fabrizio Gennari (faybs at iafrica dot com).
Contributed the DB9 and TurboGraFXoystick drivers.

Francois Charton (deef at pobox dot oleane dot com).
Wrote the Paradise graphics driver (now available as part of the FreeBE/AF project), improved the VGA palette setting code, and helped with the TexInfo conversion of the docs.

Frodo Baggins (l41273 at alfa dot ist dot utl dot pt).
Made the Portuguese keyboard mapping.

Garret Thomson (g at sirsonic dot com).
Wrote the music used in the demo game.

George Foot (gfoot at users dot sourceforge dot net).
Did a great deal of work on the Linux console version. Also wrote the AWE32 driver, added the MIDI pause/seek functions, and provided the basis of the SoundFont reader used in the pat2dat utility. Fixed the C fceil() function and added the ffloor() function.

Gorka Olaizola (olsago at jet dot es).
Added the Redhat RPM .spec file.

Greg Hackmann (hacker at ididitmyway dot com).
Contributed the Borland C++ Builder port.

Grzegorz Adam Hankiewicz (gradha at users dot sourceforge dot net).
Wrote several of the example programs, suggested the "compress" makefile target, translated the docs and system error messages into Spanish, suggested the idea of embedding the setup utility into other programs, wrote some documentation and corrected the .texi generation to improve texi2dvi output, improved the makedoc utility, added reload_config_texts(), added the email address mangling code and did plenty of other things too.

Grzegorz Godlewski.
Contributed a Polish localization patch and added support for lower and upper altgr tables.

Grzegorz Ludorowski (pajonk at ajax dot umcs dot lublin dot pl).
Wrote several of the example programs, and made the intro animation and graphics for the demo game.

Guilherme Silveira (thedarkage at geocities dot com).
Modified the file selector to only list valid drive letters.

Gunter Ladwig (gladwig at iname dot com).
Wrote the OS/2 detection routines and added the three-button mouse emulation.

Haruhiko Okumura, 12-2-404 Green Heights, 580 Nagasawa, Yokosuka 239, JP.
Wrote the original version of the LZSS compression code.

Hein Zelle (hein at icce dot rug dot nl).
Revamped the cross-compilation section of docs/build/mingw32.txt.

Henrik Schmidt (hbs at ks dot informatik dot uni-kiel dot de).
Found a workaround for the switching problem under Windows, made gcc pass '-h' instead of '-soname' to the linker and replaced '-L' by '-h' in shell comparisons so as not to break on Solaris.

Henrik Stokseth (hstokset at tiscali dot no).
Contributed a native Mingw32 build which can also be built with a cross-compiler and the Cygwin compiler. Much improved OS detection. Added get_gfx_mode_list() and methods for querying the VGA, Mode-X, Xtended, VESA, VBE/AF and DIRECTX drivers for a list of possible GFX modes. Rewrote the mode-selector to use get_gfx_mode_list(). Rewrote/updated some scripts and reworked the build system many times.

Igor Gnip (gnipi at mindnever dot org).
Removed the requirements for fileutils on DOS/Windows platforms and added the detection of MSYS to the MingW32 port.

Isaac Cruz (icruzbal at teleline dot es).
Fixed a bug with accelerated drawing onto sub bitmaps of DirectDraw surfaces, added the GFX_DIRECTX_WIN driver, fixed a Windows sub bitmap locking bug, added Windows desktop_color_depth and yield_timeslice routines, and made extensive modifications to other aspects of the Windows code.

Ivan Baldo (lubaldo at adinet dot com dot uy).
Wrote the 15/16 bit dithering code and optimised the sprite rotation routines.

James Arthur (jaa at arfa dot clara dot net).
Documented the Photoshop-style truecolor blender routines.

James Hyman (frooge at mindless dot com).
Added support for quoted strings in the get_config_argv() function, and the dithering code for paletted images.

Jan Bruun Andersen (jba-dk at users dot sourceforge dot net).
Fixed a compilation problem with Cygwin.

Jan Hubicka (hubicka at horac dot ta dot jcu dot cz).
Vastly improved the speed of the create_rgb_table() function.

Jason Wilkins (fenix at io dot com).
Wrote the quaternion math routines, and contributed the BeOS port.

Javier Gonzalez (xaviergonz at hotmail dot com).
Corrected mouse movement speed, made allegro_message() use title from set_window_title(), added close button hook support and improved switching in Windows, fixed bad clearing of subbitmaps, and made bug reports and suggestions for improvement. Contributed bidirectional looping support, backward playing support and bugfixes for the DirectSound driver, and did plenty of other things too.

Jim Flynn (jflynn at pacbell dot net).
Removed floating point calculations from the AWE32 MIDI driver.

Joaquin Hierro Diaz (Joaquin dot Hierro dot Diaz at fresno dot csic dot es).
Made the mapping table for Spanish keyboards.

Joerg Rueppel (sharky-x at gmx dot net).
Added more flexible wildcard matching for object names in dat.exe, and the find_datafile_object() function.

Johan Peitz (d98peitz at dtek dot chalmers dot se).
Fixed and enhanced the Win32 joystick driver. Contributed an 'Alex the Allegator' icon.

Johan Venter (leonjventer at bigpond dot com).
Fixed some problems with the RSXNT and Mingw32 makefiles.

Jonas Petersen (joXonoX at berlin dot snafu dot de).
Added the save_bmp() function, and support for the OS/2 BMP format.

Jonathan Tarbox (jonattar at rocketmail dot com).
Wrote the mode-X setup code, the FLI/FLC player, and contributed parts of the joystick handler.

Jorrit Rouwe (j dot rouwe at cpedu dot rug dot nl).
Provided a new and much cooler set of FM instrument definitions for the Adlib MIDI driver.

Jose Antonio Luque (skylord at LatinMail dot com).
Improved the Windows joystick driver, and optimised the 16 bit blit() and masked_blit() functions.

Joshua Heyer (joshua_heyer at yahoo dot com).
Wrote the original version of the OSS sound driver.

Keith Gerdes (kwg at softhome dot net).
Fixed the DirectDraw overlay mode driver.

Kerry High (khigh01 at umr dot edu).
Contributed the SNES joypad driver.

Kester Maddock (dmaddock at xtra dot co dot nz).
Wrote the Wingman Warrior joystick driver.

Knut Pape (Knut_Pape at t-online dot de).
Improved the Mingw32 readme file.

Krzysztof Krzyzaniak (eloy at arrakis dot cs dot put dot poznan dot pl).
Wrote the load_voc() function.

Laurence Withers (lwithers at users dot sf dot net).
Added destroy hook to font structure, worked on const-correctness throughout the library, implemented the new FONT structure, made some modules avoid linking dependencies and added a '-windowed' switch to the grabber.

Lee Killough (email unknown).
Added the low-level hook routine to the keyboard handler, and fixed a couple of bugs.

Lennart Rolland (chimeni at hotmail dot com).
Contributed the Norwegian message translation.

Lisa Parratt (lisa at thecommune dot org dot uk).
Spotted a BSDism that IRIX doesn't like@all and added IRIX detection.

Lorenzo Petrone (_lano_ at libero dot it).
Contributed the gfxinfo utility and added two FAQ entries.

Lucas Vignoli Reis (lucasvr at bestway dot com dot br).
Added the Portuguese (Brazil) message translation and keyboard mapping.

Magnus Henoch (mange at freemail dot hu).
Made the gfx mode selector keep the current selection as much as possible.

Maiolino Carmelo (cmaiolino at ctonline dot it).
Added the Italian keyboard mapping table.

Manni Heumann (manfred dot heumann at uni-bielefeld dot de).
Fixed some problems with the German keyboard mapping table.

Marcel de Kogel (m dot dekogel at student dot utwente dot nl).
Not content with fixing my broken MPU-401 driver, Marcel went on to provide a set of vastly improved drum sounds for the OPL driver, to help me sort out some problems with reentrant interrupts, to supply the half of the joystick code that didn't come from Jonathan, and to locate a stupid mistake in my VESA linear framebuffer code.

Marcel Smit (marcel dot athlon at hccnet dot nl).
Corrected a bug that caused errors when drawing persp. correct polys facing the screen. Made the show_video_bitmap() method of the Windows windowed driver wait for a vsync.

Marco Campinoti (marco at etruscan dot li dot it).
Added 15 and 24 bit support to the native Tseng ET4000 driver (now available as part of the FreeBE/AF project).

Marco Marmulla (Viper005 at usa dot net).
Added 16 bit support to the load_voc() routine.

Marian Dvorsky (mdvorsky at dodo dot sk).
Wrote the Windows GDI interface routines.

Marius Fodor (iceman at teleport dot com).
Added support for the Sidewinder and Gravis GamePad Pro.

Marek Habersack (grendel at ananke dot amu dot edu dot pl).
Did the original Linux console port (brave man: this was the first ever work done on porting Allegro away from DOS), which is the basis of the code we are still using today. Added support for the more recent Trident chipsets (now available as part of the FreeBE/AF project).

Mark Wodrich (mwodric at eleceng dot uct dot ac dot za).
The brain behind sub-bitmaps, flicker-free mouse pointers, and the ability to import GRX .FNT files into the grabber.

Markus F.X.J. Oberhumer (markus dot oberhumer at jk dot uni-linz dot ac dot at).
Fixed the Video-7 scrolling function (now available as part of the FreeBE/AF project), optimised the color mapping routines, and made many useful suggestions like the addition of a vid_phys_base field to the graphics driver structure.

Martijn Versteegh (m dot versteegh at hccnet dot nl).
Added the config hook extension mechanism.

Mathieu Lafon (mlafon at ifhamy dot insa-lyon dot fr).
Added the French keyboard mapping, support for the Pause/PrtScr keys, and changed the key[] table to a normal/extended bitfield.

Matt Witherspoon (spoon at vt dot edu).
Fixed a bug in the scroll() method of the Linux SVGAlib driver.

Matthew Bowie (catcat at nmt dot edu).
Added support for 4-button joysticks.

Matthew Leverton (matthew at leverton dot cc).
Fixed a bug with mouse mickeys in windowed mode under Windows. Fixed a problem with al_find*() and NTFS partitions under Windows. Added missing header files to be installed by the Windows binary distribution, made the DOS/Windows makefiles use 'copy /B' instead of 'copy', added the detection of left-hand mouse configuration under Windows and fixed a bug with pack_fgets().

Maxime Carey (werfu at users dot sourceforge dot net).
Contributed the Canada (French) keyboard mapping file.

Michael Bevin (michael dot bevin at stonebow dot otago dot ac dot nz).
Optimised the create_trans_table() function.

Michael Bukin (M dot A dot Bukin at inp dot nsk dot su).
Ported the whole thing to Unix/X, and contributed a _lot_ of patches to improve the portability, robustness, and performance of pretty much the entire library.

Michael Rickmann (mrickma at gwdg dot de).
Ported the Windows code to Mingw32.

Michael Tanczos (webmaster at logic-gate dot com).
Fixed some bugs in the FLIC player.

Michal Mertl (mime at eunet dot cz).
Wrote all the 24 bit graphics code, the optimised palette generation function, and a fair amount of the other truecolor stuff too (bitmap scaling, image loading, etc).

Nathan Albury, aka Rubicant (gt4558a at prism dot gatech dot edu).
Improved the fire routine in examples/exflame.c (my original version didn't really look very much like flames :-) and gave me some extremely useful ideas about how to implement translucency.

Neil Townsend (neil at robots dot ox dot ac dot uk).
Improved the accuracy of the timer routines, and added the callback parameters.

Nicholas Davies(master_goodbytes at hotmail dot com).
Made the fix class not trigger warnings with gcc -Weffc++.

Nick Kochakian (nickk at worldnet dot att dot net).
Wrote the DirectSound input driver.

Ole Laursen (98zOLaw at aalborghus dot dk).
Contributed the Danish keyboard mapping table and system message translation, and made the Unicode utolower() and utoupper() functions understand the entire 16 bit character set.

Olly Betts (olly at muscat dot co dot uk).
Modified the djgpp makefile to support cross-compiling on a Linux machine.

Oscar Giner (O_giner at hotmail dot com).
Added the Catalan translation, corrected the Spanish translation and fixed a conflict between the magic main and the MFC.

Owen Embury (owen at gememail dot demon dot co dot uk).
Wrote part of the translucency/lighting code.

Owen Rudge (alleg at orudge dot freeuk dot com).
Contributed a DLL version resource script and a mkdata.bat script.

Ove Kaaven (ovek at arcticnet dot no).
Fixed a bug in the ATI mach64 driver (now available as part of the FreeBE/AF project), added native truecolor and linear framebuffer support to the ATI driver, contributed the Norwegian keyboard mapping, and added MIDI and sample input features to the MPU and SB drivers respectively.

Patrick Hogan (patter at iname dot com).
Wrote the draw_gouraud_sprite() function, and made Windows audiostreams work properly.

Paul Bartrum (bartrum at xtra dot co dot nz).
Contributed the ellipse drawing functions.

Paul Furber (paul at sprintlink dot co dot za).
Provided the floating point apply_matrix_f() function.

Paul Hampson (Paul dot Hampson at Pobox dot Com).
Improved and fixed some problems in the SNES gamepad driver.

Paul Pinault (diskaleg at infonie dot fr).
Translated the system error messages into French.

Pavlos Touboulidis (gtoub at otenet dot gr).
Made file_select() able to include or exclude files based on their attributes.

Pedro Cardoso (pcardoso at viriato dot ipv dot pt).
Contributed the tweaked 80x80 VGA mode.

Peter Cech (7cech at nw dot fmph dot uniba dot sk).
Added grabber support for the 8x8 BIOS font format, and support for hot-swapping between a custom keyboard layout and the standard US mapping. Optimised the alpha sprite blending routines. Added non-ASCII space recognition to uisspace().

Peter Monks (pmonks at iname dot com).
Wrote the Video-7 graphics driver (now available as part of the FreeBE/AF project), and showed me how to set up the unchained 640x400 mode.

Peter Palotas (blizzar at hem1 dot passagen dot se).
Added the keyboard callback routine.

Peter Pavlovic (Peter dot Pavlovic at st dot fmph dot uniba dot sk).
Added the Slovak keyboard mapping and message translation, stopped the DOS file selector from listing virtual drives, did the same for the Windows file selector, improved the support for accented character maps in the keyboard driver, and made aesthetic modifications to the GUI menu system.

Peter Puck (zaqhaq at netscape dot net).
Helped with the Mingw32 native build.

Peter Wang (tjaden at users dot sourceforge dot net).
Added the mouse_z wheel input support to the Linux code, fixed problems with the ESD sound driver, wrote the ALSA sound driver, wrote the BeOS sound driver, added OSS MIDI and sample input support, added banked mode support to the SVGAlib driver, wrote the X DGA mode switching code, improved the Linux joystick driver, X11 fullscreen, DGA2 and DGA driver, added pthread timers under Linux/Unix and did loads of other things too.

Phil Frisbie, Jr. (pfrisbie at geocities dot com).
Wrote the CPU type detection code.

Philipp Thomas (pthomas at suse dot de).
Fixed all comparisons between signed and unsigned types, thus allowing to build with -W -Wno-unused on Unix systems, fixed the compilation on x86-64, fixed all function prototypes, thus allowing to build with -Wstrict-prototypes on Unix systems, and added the German translation to the RPM spec file.

Przemek Podsiadly (ppodsiad at elka dot pw dot edu dot pl).
Added hicolor versions of the 3d polygon code.

Revin Guillen (revin at phylo dot com).
Added the position_dialog() function.

Richard Davies (richard at debaser dot force9 dot co dot uk).
Added support for PSX and N64 joypads.

Richard Mitton (100740 dot 1271 at compuserve dot com).
Added support for 6-button joysticks, and wrote the 12-bit color example program (ex12bit.c).

Richard Reeve (r dot e dot reeve at stir dot ac dot uk).
Fixed a silly mistake with gcc 3.0.x detection.

Robert J. Ragno (rjr at mit dot edu).
Wrote the Gravis GrIP driver, and made some improvements to the Wingman, PSX, and throttle input code.

Robert J. Ohannessian (voidstar at ifrance dot com).
Added MMX optimisation for the 8 and 16 bit clear() functions, and fixed bad clearing of subbitmaps. Also added SSE detection and optimized some masked_blits with SSE instructions. Added some routines to the unified color convertor and made some of them more robust. Revamped the retrieval mechanism of CPU capabilities. Did plenty of other things too.

Roberto Alfonso (rpgrca at labint dot frba dot utn dot edu dot ar).
Added an srand() call in the demo game.

Robin Burrows (rburrows at bigfoot dot com).
Provided a new page flipping code for the DirectDraw subsytem, added a Windows sound driver using the Allegro mixer and another using waveOut. Fixed two glitches in the DirectDraw code.

Romano Signorelli (romanos at bigfoot dot com).
Added an arc plotting routine.

Ronaldo Hideki Yamada (r dot yamada at uol dot com dot br).
Contributed the Macintosh port of Allegro.

S.Sakamaki (emt at geocities dot co dot jp).
Added the VESA 3.0 refresh rate control code.

S.Suzuki (s-suz at sunfield dot ne dot jp).
Wrote the IF-SEGA /PCI, /PCI2, and /ISA joystick interface drivers.

Salvador Eduardo Tropea (salvador at inti dot edu dot ar).
Improved the keyboard routines (better handling of extended scancodes, keyboard LED support, capslock and numlock, and alt+numpad input), contributed the 320x100 VGA graphics mode, added support for proper 16 bit sample mixing, fixed compilation on GCC 3.x and made numerous other useful suggestions, contributions and bugfixes.

Santeri Saarimaa (gridle at mbnet dot fi).
Made the Finnish keyboard mapping.

Sask Allegro (sask_allegro at iespana dot es).
Added support for more than two joysticks in the Windows port.

Scott Harrison (scotth at calderauk dot com).
Added the OpenDOS detection code.

Sean Gugler (sean at epal dot com).
Added the set_leds() function.

Seunghwan Ji.
Made makedoc output correct html and rtf files for Korean.

Seymour Shlien (seymour at dgbt dot doc dot ca).
Contributed the Windows BMP file reader, bezier spline drawer, and justified text plotting function.

Shawn Hargreaves (shawn at talula dot demon dot co dot uk).
Progenitor. Wrote everything that wasn't written by somebody else.

Stefan Eilert (seilert at rz dot Uni-Osnabrueck dot DE).
Added support for a second joystick.

Stefan Schimanski (1Stein at gmx dot de).
Wrote the original Windows version pretty much single-handedly.

Stefan T. Boettner (virtual dot man at t-online dot de).
Wrote the Linux SVGAlib driver.

Stepan Roh (src at srnet dot cz).
Added a Czech keyboard mapping and system message translation, the Latin Extended-A characters in the default font, and the codepage support in the textconv utility, fixed some problems with the ESD sound driver, and helped make Allegro build better on some Unix platforms. Fixed const related problems in C versions of ASM routines.

Stephen Kittelson (stickman2000 at juno dot com).
Made bugfixes and tweaks to the keyboard system.

Sven Sandberg (svens at it dot uu dot se).
Fixed a problem with save_bitmap() rounding the image widths, optimised the create_light_table() function, optimised the fixed point trig routines, provided the Swedish message translations, improved the file selector sorting algorithm, optimised the spline routines, added the ustrrchr() function, improved the usprintf() handling of floats, changed the Z-buffer API, improved rotation functions and provided other bugfixes.

TBD/FeR (tbd at usa dot net).
Added the 320x600 and 360x600 resolutions to the mode-X driver.

Teijo Hakala (teijo dot hakala at imnetti dot fi).
Added wheel support to the Windows mouse driver.

Tero Parvinen (Tero dot Parvinen at hut dot fi).
Designed most of the new sound API.

Theuzifan Sumachingun (uzi at simauria dot upv dot es).
Improved the cpu detection for Cyrix chips and made the file selector only list valid drive letters.

Thomas Klausner (wiz at danbala dot ifoer dot tuwien dot ac dot at).
Added NetBSD detection.

Thomas Wolf (two at chello dot at).
Corrected some errors in the German keyboard mapping, and added the German translation of the system messages.

Tim Bird (tbird at caldera dot com).
Worked on the Linux console port.

Tim Gunn (timgunn at eastwind dot com dot au).
Wrote the TGA reading/writing routines.

Timothy Terriberry (sundance at sprintmail dot com).
Fixed several bugs in the RGB <-> HSV conversion routines.

Tom Breton (tob at world dot std dot com).
Added the functionality selection #ifndefs to allegro.h.

Tom Fjellstrom (tfjellstrom at home dot com).
Wrote the ALSA MIDI driver.

Tom Novelli (tnovelli at cyber3 dot servtech dot com).
Wrote the original version of the digital MIDI driver.

Tom St Denis (tomstdenis at yahoo dot com).
Fixed clipping of transparent objects.

Tomohiko Sugiura (tmsugi at d4 dot dion dot ne dot jp).
Added the KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT and other keys to the input handler, and organised getting the IF-SEGA joystick drivers by S.Suzuki merged into my codebase. Added more aggressive Sidewinder joystick driver.

Ville Skyttä (scop at users dot sourceforge dot net).
Fixed a problem with make install libdir= and modules on Unix systems.

Vincent Penquerc'h (lyrian at kezako dot net).
Added the D_DIRTY flag and mouse button press/release events to the GUI system, optimised the 256 to truecolor blitting code to avoid repeated conversions of the palette table, added scare_mouse_area(), added the yield_timeslice() function, added the update selection function to the grabber, added the XCRP and YCRP properties to datafiles in general, and made various other bugfixes and improvements. Responsible for the big header split up, and did loads other stuff too.

VolkerOth (VolkerOth at aol dot com).
Integrated the concepts of scrolling and edit_proc objects.

Thanks!

First, a big thank you to all the people who help me test and debug this code. It sometimes gets frustrating to receive hundreds of messages saying "it doesn't work!", but they are useful all the same...

Andre Baresel (baresel at informatik dot hu-berlin dot de), and Craig Jackson (Craig dot Jackson at launchpad dot unc dot edu), provided a tremendous amount of information about SB hardware.

Benji York (Benji at cookeville dot com).
Provided hardware information for the Gravis GamePad Pro.

Charles Mac Donald (cgfm2 at hooked dot net).
Showed me how to set some cool tweaked VGA and mode-X resolutions.

Charles Sandmann (sandmann at clio dot rice dot edu), DJ Delorie (dj at delorie dot com), Eli Zaretskii (eliz at is dot elta dot co dot il), and everyone else who has contributed to djgpp. I love it.

C. Schwerdtfeger (schwerdt at physics dot ubc dot ca), for his help (and enourmous patience!) in getting the SB Pro-I MIDI driver to work.

Finn Thoegersen, Nordbanevej 3 C, DK-7800 Skive, Denmark.
Most of my SVGA hardware information came from his VGADOC package.

Eric Jorgensen (smeagol at rt66 dot com).
Varmint's Audio Tools (VAT) gave me many useful ideas about how to play MIDI files.

Jamie O'Connell (JamieOConnell at msn dot com).
Several of the new Adlib drum patches, and the specifications for the .IBK file format, came from his SBTimbre package.

Jean-Paul Mikkers (mikmak at stack dot urc dot tue dot nl).
MikMod was the source of a lot of information about programming the SB, and also gave me the idea of dynamically reprogramming the PIT to get a really high resolution timer.

Joel H. Hunter (jhunter at kendaco dot telebyte dot com).
His SB library for djgpp is excellent, and helped me a lot.

John Pollard (74723 dot 1626 at compuserve dot com).
The FM instrument definitions are based on his MID-KIT library.

Kendall Bennett and all the other cool people@SciTech Software.
These guys gave the world UniVBE, the VBE/AF API, and a lot of free information and example code. Plus they very kindly sent me a copy of the VBE/AF spec when I wanted one.

Kris Heidenstrom (kheidens at actrix dot gen dot nz).
His PC timing FAQ was a big help.

Mark Feldman.
It goes without saying that the PCGPE was an invaluable resource.

Michael Abrash.
You just gotta love that man...

Paul Fenwick (bg914 at freenet dot carleton dot ca).
Various bits of the mode-X code (notably the split screen stuff) came from his XLIBDJ library.

powerjaw (powerjaw at dnai dot com).
Sent me a Sidewinder gamepad so I could fix some problems with the driver for it. What a cool thing to do...

Robert Grubbs (rwgrubbs at vt dot edu).
Provided hardware information for the Sidewinder joypad.

Robert Schmidt (robert at stud dot unit dot no).
The register values for the 400x* mode-X resolutions came from his TWEAK program.

Tom Grandgent (tgrand at canvaslink dot com).
Organised and hosted the Allegro mailing list. Hurrah!

Vladimir Arnost (xarnos00 at dcse dot fee dot vutbr dot cz).
Provided hardware specs for the OPL3 chip.

Frank Zappa, Mike Keneally, Pink Floyd, the Doors, Tori Amos, and all the other great musicians who provide me with things to listen to while I am programming.

My parents, John and Nancy.
I would never have made it through all those late night coding sessions without the cafetiere they gave me last Christmas :-)


Allegro FAQ

The Allegro FAQ

If the answer isn't here, ask and it will be added...

Contents

  • Trivial problems

    • How do I use it?
    • What is Allegro?
    • Where can I get it?

  • DJGPP problems

    • Compile errors scroll off the screen too quickly for me to read them!
    • I give up: I can't compile this! Can you send me a precompiled version?
    • Make doesn't work properly.
    • My djgpp installation is fine, but make still doesn't work properly.
    • What is this make program that I'm supposed to run?
    • When I run make, it asks me for some parameters. What do I type?
    • When I run make, it says "conflicting types for va_list".
    • When I run make, it says "makefile has modification time in the future".
    • When I run make, it says "virtual memory exhausted".
    • When I try to compile a program using Allegro, I get lots of errors like:

  • DOS problems

    • Does Allegro work under OpenDOS?
    • Does DOS Allegro work with the SB-Live soundcard?
    • Does the DOS version of Allegro work under Windows NT?
    • How can I extend the 256k limit on Mode-X video memory?
    • I get an "out of environment space" error when I run fix.bat or
    • Why does DOS Allegro play sounds so much quieter than in Windows?
    • Why doesn't it work with my video card?
    • Why not use some sort of dynamic linking system?

  • Windows problems

    • I get an "out of environment space" error when I run fix.bat or
    • I get an error about a "missing separator" when I run make!
    • I get an error about a missing WinMain() or main() function!
    • I get an error about an "unresolved external symbol _main"!
    • I get lots of compile errors about conflicting types for "struct BITMAP"!
    • I get lots of compile errors about things like "DDEDM_STANDARDVGAMODES"!
    • I get lots of compile errors about things like "LPDIRECTDRAWSURFACE2"!
    • In windowed mode artifacts are left on the desktop when the window
    • In windowed mode the screen stays black unless the window is placed
    • When I run make, it says "windres: no resources".

  • Unix problems

    • Compile errors scroll off the screen way too quickly for me to read them!
    • I get errors about "_mangled_main_address" being undefined!
    • When I try to use DGA2, I get "resolution not supported", but the X
    • When I try to use DGA2, the screen goes black and the PC completely

  • General problems

    • Can I use Allegro in my <whatever> commercial application?
    • Can I use Allegro with my <foobar> compiler?
    • How can I convert my graphics to all use the same 256 color palette?
    • How can I convert the documentation into Windows Help format?
    • How can I display several different images at the same time?
    • How can I fade the screen in a truecolor graphics mode?
    • How can I generate a random number?
    • How can I generate FLI or FLC format animations?
    • How can I make my game run at the same speed on any computer?
    • How can I make parts of my sprite transparent in truecolor modes?
    • How can I print out the documentation?
    • How can I take a screenshot of my Allegro program?
    • I can't get the 3D polygon functions to work!
    • I can't get the d_bitmap_proc() or d_icon_proc() GUI object to work!
    • I can't get the rotate_sprite() function to work!
    • I got the WIP patch, but I can't apply it.
    • I'm still confused. Where can I get help?
    • I'm trying to compile the grabber, but it doesn't work!
    • I tried using fade_in() and fade_out() with truecolor modes but nothing
    • My colors always come out wrong. And how can I make a greyscale palette
    • My program crashes all the time. Could this be a bug in Allegro?
    • Should I use regular bitmaps, RLE sprites, or compiled sprites?
    • What is this "Allegro WIP" that I see people talking about?
    • When I compile Allegro, make fails with something like `Error: operands
    • When I run the demo game, it says it can't find demo.dat.
    • When will <foobar> be finished? I can't wait...
    • Where can I find a set of instrument samples for the DIGMID driver?
    • Where can I find example source code, add-on packages, and tutorials?
    • Where can I get some fonts to use with Allegro?
    • Why can't Allegro read GIF files?
    • Why do I have a funny color border at the edges of my monitor?
    • Why doesn't busy waiting on the key array work? For example,
    • Why doesn't vsync() seem to work?
    • Why is it considered good coding practice to define PI as a constant,
    • Why not add a MOD playing function?
    • Why not add networking support?
    • Why not make a "lite" version of Allegro?
    • Will you ever add support for 3D accelerator hardware?

Trivial problems

  • What is Allegro?

    • See readme.txt.

  • Where can I get it?

    • From any SimTel mirror, in the directory gnu/djgpp/v2tk/, or from the Allegro homepage, http://alleg.sourceforge.net/.

  • How do I use it?

    • See allegro.txt.

DJGPP problems

  • What is this make program that I'm supposed to run?

    • Make is part of the standard djgpp distribution, in the file v2gnu/mak*b.zip (whatever the latest version number is). You can get this from http://www.delorie.com/djgpp/.

  • Make doesn't work properly.

    • Are you sure that you have installed djgpp correctly? Check the instructions in the djgpp readme.1st file, and in particular confirm that you have set the DJGPP environment variable and added the djgpp\bin directory to your path.

  • My djgpp installation is fine, but make still doesn't work properly.

    • Are you sure that you are using the GNU make program, and not some other version like the Borland one? If in doubt, run "make -v" and check that the GNU copyright message is displayed.

  • When I run make, it asks me for some parameters. What do I type?

    • You shouldn't be running make from the Win95 explorer! Bring up a DOS box, change to your Allegro directory, and type "make" at the command prompt.

  • When I run make, it says "makefile has modification time in the future".

    • Are you sure that your system time and date are set correctly? Alternatively you may have downloaded a fresh file made by someone in a more eastern timezone. In the latter case you can either wait a few hours, temporarily set your clock forward, or use a utility such as "touch" to change the timestamp of the files.

  • When I run make, it says "virtual memory exhausted".

    • As the error message suggests, you need to provide more memory for the compiler to use. The go32-v2 program will tell you how much is currently available. If you are running under DOS, try to free up more disk space for use as a swapfile. When using win95, increase the DPMI memory limit in the properties for your DOS session to 65535 (you'll have to type this in by hand, because the pulldown list doesn't go above 16384).

  • When I run make, it says "conflicting types for va_list".

    • As the error message suggests, there is a conflict between newer versions of gcc and older versions of the libc. You must upgrade your djdevxxx.zip package to the latest update (timestamp 11 August 2002) of DJGPP-2.03 or above.

  • When I try to compile a program using Allegro, I get lots of errors like:

    C:\TEMP\ccdaaaaa(.text+0x9):x.c: undefined reference to `allegro_init'
    C:\TEMP\ccdaaaaa(.text+0xe):x.c: undefined reference to `install_keyboard'

    • You haven't read the docs, have you? :-) You need to link your program with the library file, liballeg.a. First, make sure you have installed everything properly (running make should do this for you). Second, if you are compiling from the command prompt or with a makefile, add -lalleg to the end of your gcc command line, or if you are using Rhide, go to the Options/Libraries menu, type 'alleg' into the first empty field, and make sure the box next to it is checked.

  • I give up: I can't compile this! Can you send me a precompiled version?

    • No, sorry. For starters, liballeg.a is about 450k, but you'd probably also want various utilities like the grabber, sound setup, etc. And what about all the example programs? If I included compiled versions of everything, a binary distribution would be over 7 megs: way too big to be practical! More seriously though, there just isn't any reason why you can't build it yourself. A compiler is a deterministic process: given a particular input file and command line, it will always produce the same output. If this isn't working, you either have the wrong input files (ie. your copy of Allegro is broken in some way), or the wrong command line (it is hard to see how that could happen, since all you have to do is type "make"...) or your compiler is broken, ie. you didn't install djgpp properly. You need to find and fix the problem, not just sweep it under the carpet by getting someone else to compile Allegro for you...

  • Compile errors scroll off the screen too quickly for me to read them!

    • GNU tools write their error messages to the error stream, stderr. Unfortunately command.com is too stupid to know how to redirect this, but fortunately DJ was smart enough to work around that, so you can use his redir program to capture the output messages, for example "redir -eo make > logfile.txt".

DOS problems

  • Does the DOS version of Allegro work under Windows NT?

    • Your mileage may vary. Some people have reported problems, while others say that it works fine. I don't have access to NT myself, so there is nothing I can do about it either way, and to be honest I don't care very much. Use the Windows version of Allegro if you want to make Windows programs. If you want to run DOS programs, use DOS!

  • Does Allegro work under OpenDOS?

    • Yes, but with some caveats. If you are using the OpenDOS version of EMM386, you must disable their DPMI implementation (specify DPMI=OFF on the EMM386.EXE device line in your config.sys). You should also make sure the PIC=OFF flag is set, but this is the default so it won't be a problem unless you have specifically enabled it.

  • How can I extend the 256k limit on Mode-X video memory?
    I have two megs in my card.

    • You can't. The limit is imposed by the VGA hardware, not by Allegro. To access more than 256k of video memory you need to use an SVGA mode, which means either switching to a higher resolution or getting a copy of the SciTech Display Doctor, which provides several low resolution SVGA modes.

  • Does DOS Allegro work with the SB-Live soundcard?

    • It does for some people, but not for others. The problem is that Creative Labs refuse to release any specs, so we don't know how to write a driver for it. Complain to them, or buy a different card from a more reasonable manufacturer.

  • Why does DOS Allegro play sounds so much quieter than in Windows?

    • This might be because you have the volume set very low: try changing this in the setup program. Also, Allegro is mixing several sounds into a single output buffer, unlike the Windows sound player that only plays one sample at a time, so each individual sound can only get a smaller percentage of the total output volume. This is just the price you pay for multiple output channels. If you don't like it, use the setup program to tweak the number of channels: this can be any power of two less than or equal to 64, and the smaller you make it, the louder the sound will be. Alternatively, use set_volume_per_voice(), described in the docs. This will enable you to adjust the overall volume of Allegro's digital sound output.

  • Why doesn't it work with my video card?

    • Try using a FreeBE/AF driver (http://www.talula.demon.co.uk/freebe/), or the commercial SciTech Display Doctor (http://www.scitechsoft.com). If it still doesn't work, post a description of your problem to the Allegro mailing list, along with a copy of the output from running the afinfo and vesainfo programs.

  • Why not use some sort of dynamic linking system?

    • The VBE/AF interface already provides this for the video drivers: see the FreeBE/AF project on http://www.talula.demon.co.uk/freebe/. For more general things like the sound, VESA, and mode-X routines, this would be very difficult to do because the drivers depend on a lot of helper functions from the core lib. The djgpp DXE format is nowhere near flexible enough to support this, and I don't want to make Allegro dependent on any other dynamic linking packages.

  • I get an "out of environment space" error when I run fix.bat or
    vcvars32.bat!

    • Well duh, you need to increase the size of your environment then :-) You can do this by changing the settings for your DOS box (click the system menu and select "properties"), or at startup in your config.sys file (eg. "shell=c:\command.com /e:8192 /p").

Windows problems

  • I get an "out of environment space" error when I run fix.bat or
    vcvars32.bat!

    • Well duh, you need to increase the size of your environment then :-) You can do this by changing the settings for your DOS box (click the system menu and select "properties"), or at startup in your config.sys file (eg. "shell=c:\command.com /e:8192 /p").

  • I get an error about a "missing separator" when I run make!

    • Make sure that you don't have a semi-colon appended to your MSVCDIR variable if you are using MSVC, to your MINGDIR variable if you are using Mingw32 or to your BCC32DIR variable if you are using BCC.

  • I get lots of compile errors about things like "LPDIRECTDRAWSURFACE2"!

    • You need to tell your compiler how to find the DirectX include files and libraries: put the DirectX SDK /include and /lib directories in the compiler/linker path. Alternatively, if you don't want to modify any configuration stuff, you can simply copy the files from the DirectX SDK /include and /lib directories to the corresponding ones for your compiler.

  • I get lots of compile errors about things like "DDEDM_STANDARDVGAMODES"!

    • You need to upgrade to a more recent version of the DirectX SDK, at least version 5, which you can get from the Microsoft Developer site.

  • When I run make, it says "windres: no resources".

    • If an anti-virus software (Norton or McAfee for example) is running in the background on your computer, try to disable it temporarily.

  • I get an error about a missing WinMain() or main() function!

    • You need to write END_OF_MAIN() just after your main() function. Allegro uses this, along with some preprocessor magic, to turn a normal main() function into a Windows-style WinMain() entrypoint.

  • I get an error about an "unresolved external symbol _main"!

    • Make sure you're building a Windows GUI Application, and not a Windows Console Application. This is a setting when you create the project in MSVC or Borland C++ Builder. This is specified by the '-tW' flag for the Borland C++ command line compiler. Either that, or define the preprocessor symbol ALLEGRO_USE_CONSOLE prior to including Allegro headers if you really need the console for your program.

  • I get lots of compile errors about conflicting types for "struct BITMAP"!

    If your program directly includes Win32 API header files, see the "Windows specifics" section of the documentation. If your program only includes header files of the C++ standard library, you're very likely trying to compile it with gcc 3.x for Mingw32; if so, define the symbol __GTHREAD_HIDE_WIN32API on the compiler command line: g++ -D__GTHREAD_HIDE_WIN32API program.cpp -lalleg

  • In windowed mode artifacts are left on the desktop when the window
    is moved or when another window is placed on top of it.

    Disable direct updating for the DirectX windowed driver by using the dedicated configuration variable. See the 'Configuration routines' section in the docs and the allegro.cfg template file for more detailed informations.

  • In windowed mode the screen stays black unless the window is placed
    under another window on the desktop.

    • Disable direct updating for the DirectX windowed driver by using the dedicated configuration variable. See the 'Configuration routines' section in the docs and the allegro.cfg template file for more detailed informations.

Unix problems

  • I get errors about "_mangled_main_address" being undefined!

    • You need to write END_OF_MAIN() just after your main() function. Allegro uses this, along with some preprocessor magic, to get a copy of your argv[] parameters (it needs those for various internal things).

  • Compile errors scroll off the screen way too quickly for me to read them!

    • You need to redirect stderr into a file, so you can view them later. The method for doing this depends on your shell: if you are using a Bourne-style shell like bash, try "make 2> logfile.txt".

  • When I try to use DGA2, I get "resolution not supported", but the X
    server does actually support that resolution !

    • There are two possible reasons: 1) DGA2 may support different resolutions/color depths than X, run the gfxinfo program to know what combinations you can use, 2) You may have a buggy DGA2 implementation, see next question.

  • When I try to use DGA2, the screen goes black and the PC completely
    halts!

    • You are probably using a XFree86 server with a very buggy DGA2 implementation, such as 4.0.3 (shipped with Red Hat 7.1 for example). Upgrading to 4.1.0 will probably solve your problem. You can obtain it from ftp://ftp.xfree86.org/pub/XFree86/4.1.0/binaries/ selecting the directory suited to your platform and following the instructions you find in the Install file.

General problems

  • I'm trying to compile the grabber, but it doesn't work!

    • The grabber needs to be linked with the code in datedit.c. But you shouldn't have to worry about doing this by hand: just run "make" and that will build everything for you.

  • When I compile Allegro, make fails with something like `Error: operands
    given don't match any known 386 instruction' or `Error: no such instruction `maskmovq %mm3, %mm1''.

    • You need to update your version of GNU binutils. See readme.txt to find out what the minimum required version you need is.

  • Can I use Allegro with my <foobar> compiler?

    • Not unless <foobar> is mentioned in readme.txt as one of the supported platforms. You could port it, but that is usually a lot of work. If <foobar> is a 16 bit DOS compiler like Borland C, you might as well just forget the idea :-)

  • What is this "Allegro WIP" that I see people talking about?

    • WIP stands for "work in progress", and refers to any changes that are more recent than the last official release. WIP versions of the library can be obtained as patches from the Allegro website (http://alleg.sourceforge.net/), and are usually quite stable, although obviously not so well tested as a final release version.

  • I got the WIP patch, but I can't apply it.

    • Do you have a copy of patch.exe? If not, go and get it from the same place that you downloaded the rest of djgpp: this tool is a standard part of the compiler distribution. If you do have the patch program but it isn't working properly, make sure that you are installing the patch over the top of an unmodified copy of whatever Allegro version it is intended to update (this will usually be the most recent official release from before the WIP was made, but check the text file that comes with the WIP to be sure).

  • When I run the demo game, it says it can't find demo.dat.

    • That file is distributed separately in the WIP versions. It is here: http://alleg.sourceforge.net/wip.html. (alldata.zip)

  • How can I display several different images at the same time?
    When I show the second one it messes up the palette for the first.

    • This is just the way that the video hardware works: there can only be one palette in use at any given moment. Either convert your images so they all use the same palette, or switch to a truecolor graphics mode.

  • How can I convert my graphics to all use the same 256 color palette?

    • See the Allegro.cc homepage (http://www.allegro.cc/) for some utilities, for example FixPal and Smacker.

  • My colors always come out wrong. And how can I make a greyscale palette
    with 256 different shades?

    • The VGA hardware only uses 6 bits for each color component, which means the red, green, and blue values in the palette structure range from 0 to 63, not all the way up to 255. That gives you a potential 2^18 = 262144 different colors, or 64 shades of grey. If you need more than this you could try using VESA function 0x4F08 to select an 8 bit wide DAC, but Allegro doesn't support this directly and I don't know how reliable it will be across different hardware.

  • Why do I have a funny color border at the edges of my monitor?

    • When you are in a 256 color mode, the VGA card displays color #0 around the border of the display area (in truecolor modes it displays black). Your funny color will go away if you change the palette so that color #0 is black.

  • How can I fade the screen in a truecolor graphics mode?

    • With great difficulty :-) There is no such easy trick as just altering the palette, so you will have to repeatedly redraw the image in a lighter or darker form. You could draw black translucent rectangles over the screen to darken it down, or use draw_lit_sprite() to tint a bitmap while copying it to the screen, but be warned that these operations are expensive and will require a fast PC!

  • I tried using fade_in() and fade_out() with truecolor modes but nothing
    happened. What am I doing wrong?

    • fade_in() and fade_out() only work in 8-bit paletted modes. One of the ways to fade a bitmap in is to loop through all the pixels and change them individually. An alternative is to draw lots of translucent black boxes over the screen. However, these methods can be slow. The example exxfade.c demonstrates how to fade between two bitmaps. You could modify this so it fades in or out from/to a black screen. See also the previous question.

  • How can I generate FLI or FLC format animations?

    • See the Allegro.cc homepage (http://www.allegro.cc/) for some utilities, for example DTA and Smacker. Also, you can use ASE (Allegro Sprite Editor, http://ase.sourceforge.net/), which allows drawing/editing each frame of the animation and save it as a FLI. Or you can use The GIMP (http://www.gimp.org/) along with it's GFli plugin, using layers as frames, and saving your work as "file.fli". The GIMP allows you to edit existent FLI files too.

  • How can I make parts of my sprite transparent in truecolor modes?
    I don't understand what the docs mean by "bright pink"...

    • In your favourite paint program, get hold of the RGB sliders and drag the red and blue ones up as far as they go (usually to 255, but this will depend on what units your software uses), and the green one right down to zero. The result is a special shade of Magic Pink, or as some people prefer to call it, magenta.

  • I can't get the 3D polygon functions to work!

    • Remember that the vertex positions are stored in fixed point format, so you must use the itofix() macro or shift your coordinates 16 bits to the left.

  • I can't get the rotate_sprite() function to work!

    • Remember that the angle of rotation is stored in fixed point format, so you must use the itofix() macro or shift your coordinates 16 bits to the left. For example, rotate_sprite(bmp, spr, x, y, itofix(32)) will rotate the graphic by 45 degrees.

  • I can't get the d_bitmap_proc() or d_icon_proc() GUI object to work!

    • You are probably trying to initialise the dialog structure with a pointer to your bitmap, right? That won't work because the dialog is created at compile time, but the bitmap is only loaded at runtime, so the compiler doesn't yet know where it will be located. You need to fill in the dialog structure with a NULL pointer, and then copy the real bitmap pointer into the dp field as part of your program init code, after you've loaded the bitmap into memory.

  • Should I use regular bitmaps, RLE sprites, or compiled sprites?

    • It depends on exactly what you are doing. If your images are totally opaque, there is no advantage to using an RLE sprite, and it will probably be faster to use a regular bitmap with the blit() function. If your graphics contain masked areas, an RLE sprite will almost always be both smaller and faster than the draw_sprite() function. Compiled sprites are in general quite a bit faster than both the others for masked images, and slightly faster for opaque graphics, but this is far more variable. They are at their best with small sprites, on older machines and in mode-X, and may actually be slower than blit() when using SVGA modes on a pentium (the large size of a compiled sprite is very bad for the cache performance).

  • How can I make my game run at the same speed on any computer?

    • You need to make sure the game logic gets updated at a regular rate, but skip the screen refresh every now and then if the computer is too slow to keep up. This can be done by installing a timer handler that will increment a global variable at your game logic speed, eg:

          volatile int speed_counter = 0;

      void increment_speed_counter()
      {
         speed_counter++;
      }

      END_OF_FUNCTION(increment_speed_counter)

      void play_the_game()
      {
         LOCK_VARIABLE(speed_counter);
         LOCK_FUNCTION(increment_speed_counter);

         install_int_ex(increment_speed_counter, BPS_TO_TIMER(60));

         while (!game_over) {
            while (speed_counter > 0) {
               update_game_logic();
               speed_counter--;
            }

            update_display();
         }
      }

  • How can I take a screenshot of my Allegro program?

    • Add a call to save_bitmap() somewhere in your code. See the save_bitmap() documentation for a discussion of one common pitfall when doing this, and some example code.

  • How can I generate a random number?

    • Call srand(time(NULL)) at the beginning of your program, and then use rand()%limit to obtain a pseudo-random number between 0 and limit-1.

  • Why not make a "lite" version of Allegro?
    I don't need any of the sound, maths, or GUI routines...

    • There is no need. The linker will only include the parts of the library that you actually use, so if you don't call any of, say, the texture mapping or FLIC playing functions, they will be left out of your executable. This doesn't work perfectly because a lot of the Allegro code uses tables of function pointers that cause some unnecessary routines to be linked in, so the majority of the graphics functions will be included in every executable, but I have tried to keep this to a minimum. See allegro.txt for information about more precise ways to remove some of the graphics and sound drivers.

  • Will you ever add support for 3D accelerator hardware?

    • No. I think this sort of hardware support would be most useful as part of a proper 3D API, which Allegro is not, and will never be. If you want to do some work on this, the MESA library (a free implementation of OpenGL) is IMHO the place to start.

  • Why not add a MOD playing function?

    • Several very good ones already exist, for instance the JGMOD package. See the audio library extensions section on the Allegro.cc website (http://www.allegro.cc/). You are not allowed to suggest that one of these libraries be merged into Allegro, because this topic has already been done to death on the mailing list and I am tired of it.

  • Why not add networking support?

    • That would be a lot of work, and I don't have time to do it myself. There are several networking packages currently in development or floating around on the net, though, and in my opinion this sort of code is more useful as an external library than it would be as part of Allegro.

  • Why can't Allegro read GIF files?

    • Unisys has a patent on the LZW compression algorithm that is used by the GIF format. I want everything in Allegro to be freely usable without any restrictions whatsoever, which means I can't include any code that is subject to licensing or the payment of royalties.

  • My program crashes all the time. Could this be a bug in Allegro?

    • Perhaps. Try to isolate the smallest fragment of code that is able to reproduce the problem, and I'll have a look at it. If you can send me a 10 line program, I will fix it. 100 lines, and I can probably fix it. 1000 lines, and I don't have a chance :-)

  • Can I use Allegro in my <whatever> commercial application?

    • Sure. See the giftware terms in readme.txt. I don't mind what you do with it, and there are no problems with commercial usage.

  • When will <foobar> be finished? I can't wait...

    • Whenever it is done! A little encouragement is always welcome, but I don't have any completion deadlines and I'm not going to make one up for you :-) As soon as it is finished, it will be released.

  • Where can I get some fonts to use with Allegro?

    • The grabber can import directly from GRX or BIOS format .fnt files, or you can draw them onto a .pcx image using any paint program. See http://www.talula.demon.co.uk/ttf2pcx/ for a utility that will convert Windows TrueType fonts into this .pcx format.

  • Where can I find a set of instrument samples for the DIGMID driver?

    • See the Allegro homepage (http://alleg.sourceforge.net/) for some links. You can use Gravis patches (.pat format), or SoundFont 2.0 (.sf2) files, but the latter must be converted into a patches.dat file with the pat2dat utility.

  • How can I convert the documentation into Windows Help format?

    • You need to download the makertf conversion utility (ftp://ftp.coast.net/Coast/win3/winhelp/mkrtf104.zip), and the Windows Help compiler (ftp://ftp.microsoft.com/Softlib/MSLFILES/HC505.EXE). Make a temporary directory, copy the allegro.txi file from the allegro/docs dir, and run the commands "makertf --no-warn allegro.txi -o allegro.rtf -J allegro.hpj" followed by "hcp allegro.hpj". The second command will give a lot of warnings, but they can safely be ignored.

  • How can I print out the documentation?

    • The allegro.rtf file can be read directly into Microsoft Word and printed from there, but you should right-click and update the table of contents and index fields to fill them with the correct data first. Alternatively you can install the TeX package and use the tex and dvips programs to convert allegro.txi into Postscript format.

  • Where can I find example source code, add-on packages, and tutorials?

    • Check the Allegro.cc homepage, http://www.allegro.cc/. If you have anything to add to this, please post the URL!

  • Why is it considered good coding practice to define PI as a constant,
    rather than just using the value 3.141592 in my code?

    • It simplifies the maintenance of your program, in case the value of PI ever needs to be changed. Also it will make your program more portable to other compilers that use different values of PI.

  • Why doesn't vsync() seem to work?

    • A number of graphics cards have buggy or incomplete VESA implementations, and often the vsync() function is not implemented. For examples on flicker-free drawing, look at the code for the demo game, which uses a variety of methods to draw itself.

  • Why doesn't busy waiting on the key array work? For example,
    "while (!key[KEY_ENTER]);" doesn't work.

    • If the code works without optimisations, then it could be the compiler's fault. You can try beating the compiler into submission, for example:

          while (!key[KEY_ENTER])
         yield_timeslice();

    For this case, however, it would be better to use readkey() instead. Or consider upgrading or downgrading your compiler.

  • I'm still confused. Where can I get help?

    • See http://alleg.sourceforge.net/maillist.html.


What to do when your Allegro program doesn't work

Contents

  • Introduction
  • Part 1 - who is the culprit?
  • Part 2 - when Allegro is at fault
  • Part 3 - when your program crashes
  • Part 4 - things people don't do (but should)
  • Part 5 - asking for help
  • Part 6 - learn from my mistakes
  • Part 7 - wording your plea
  • Part 8 - a model of perfection

Introduction

When things go wrong, it often seems like a good idea to ask other people for help. Fortunately for people in this situation, there are many people (both Allegro developers and users) who are happy to spend their time answering support questions of this type, but there are various things you can do to make this process work more efficiently. This document describes some steps to take whenever you have a problem with an Allegro program, suggesting ways that you can try to solve it yourself, and also giving some tips about when/how to ask for help. Following these guidelines will make life easier both for the helper (because all the relevant information will be presented to them in a concise and useful way), and for the helpee (because they are more likely to get a prompt and accurate reply).

Part 1 - who is the culprit?

Is the problem a bug in Allegro, or in your code? To find out, try running the Allegro test programs, in particular the test.exe (for graphics related problems), the play.exe (for soundcard troubles), and the entire contents of the examples directory (for anything that is going wrong). If you can't reproduce the problem with any of these, it is probably your fault, in which case you should skip to part 3 below.

If the problem is related to DOS graphics modes, you should start by getting a copy of Display Doctor from http://www.scitechsoft.com/. If this fixes the trouble, it almost certainly means that your original VESA driver was broken in some way. I'm not interested in hearing reports about problems of this type: there is nothing I can do to fix them, so I'm afraid your only option is to get a better VESA driver, either by hassling the manufacturer to fix their bugs, buying Display Doctor, or writing a FreeBE/AF driver for your card (see http://www.talula.demon.co.uk/freebe/).

Part 2 - when Allegro is at fault

If you still think the problem lies with Allegro, post a system report containing a description of the problem, what platform and library version you are using, your hardware specs, and a list of exactly which programs you were able to reproduce the problem with (it is important to know not only what programs had trouble, but also which ones worked correctly, if any).

If the problem is related to DOS graphics modes, you should also post the output from running the afinfo and vesainfo programs (the short version is enough unless you are explicitly asked to add the -v switch: all that extra data isn't usually needed). Try running the test.exe program with various Allegro drivers (any native drivers that you think might work with your card, VESA 2.0, and the VESA 1.x driver), and in various video modes, and report exactly what modes and color depths cause problems. If you are able to use any SVGA resolutions at all, run test.exe with the Autodetect option and report the entire text that it displays in the middle of the screen.

If the problem is related to the DOS sound system, try using the setup program to manually configure your card. You may need to manually enter the hardware parameters, and if it is an SB clone card, try selecting some earlier breed of SB card than whatever it is autodetecting (SB Pro, SB 2.0, or SB 1.0). If you are still unable to get anything working, your post should include the name and descriptions of whatever digital and MIDI sound drivers are being autodetected (this information is displayed by the play.exe program).

Part 3 - when your program crashes

When a djgpp program crashes, you will usually get a stack traceback looking something like:

      Exiting due to signal SIGSEGV
      General Protection Fault at eip=00001eca
      [snip]

      Call frame traceback EIPs:
        0x00001eca
        0x00001590
        0x00001aea
This information tells you exactly where the crash occurred. To make sense of it, you should compile your program with debugging information (using the -g switch), and then run "symify program.exe" while this traceback is displayed onscreen. That will change the traceback to something along the lines of:

      Call frame traceback EIPs:
        0x00001eca   _strcpy+14
        0x00001590   _main+56, line 7 of t.c
        0x00001aea   ___crt1_startup+138
In this case, you can see that the crash occurred in the strcpy() function, which was called at line 7 of the main() function in the t.c source file. Now you just have to go to that line, have a look at whatever you are doing there, and change it to be correct :-)

Note: if the crash happens deep inside an Allegro function, this traceback may not be so useful. When this happens you can recompile Allegro with debugging information (see the readme file), and then link your program with the debugging library version.

Note 2: even when this crash traceback points to one of the Allegro functions, that does not necessarily mean the Allegro routine is at fault. Anything will crash if you pass it invalid parameters, so unless you can duplicate the problem in one of the Allegro example programs, you should start out by assuming that it is a case of operator error and double-check exactly what you are passing to the Allegro function.

When your Allegro compiled Linux/Unix program crashes, you will usually get a not very meaningful message along with a core dump:

      Shutting down Allegro due to signal #11
      Segment violation (core dumped)
Look at your filesystem: there should be a file named core or something similar with information telling you exactly where the crash occurred. If there is no core, check your environment settings, under bash this is done with the 'ulimit -a' command. Usually 'ulimit -c unlimited' somewhere in your login scripts should work fine.

Just like with djgpp, to make sense of the core, you should compile your program with debugging information (using the -g switch), and then run the GNU debugger on it "gdb binary core". That will load the debugger, print some information about linked binaries and leave you at a prompt. Now you can get the full backtrace:

      (gdb) backtrace
      #0  0x08065237 in utf8_getx (s=0xbffffc5c) at ./src/unicode.c:347
      #1  0x0806953f in ustrzcpy (dest=0x0, size=2147483646, src=0x0) at ./src/unicode.c:1770
      #2  0x08057575 in _mangled_main () at t.c:9
      #3  0x0806c9bf in main (argc=1, argv=0xbffffd14) at ./src/unix/umain.c:39
      #4  0x4015414f in __libc_start_main () from /lib/libc.so.6
In this case, you can see that the crash occurred in the ustrzcpy() function, which was called at line 9 of the main() function in the t.c source file. Now you just have to go to that line, have a look at whatever you are doing there, and change it to be correct :-)

Note that the crash happened deep inside an Allegro function, which is also revealed by the traceback. However, the binary was linked against a static debug version of Allegro, we wouldn't have had so much luck with a non debug or dynamically linked version.

Since gdb is an interactive debugger, you could also select a frame and check out the values of the variables, to see better who is the culprit:

      (gdb) frame 2
      #2  0x08057575 in _mangled_main () at t.c:9
      9          ustrcpy(p1, p2);
      (gdb) list
      4
      5       int main(void)
      6       {
      7          char *p1 = 0, *p2 = 0;
      8          allegro_init();
      9          ustrcpy(p1, p2);
      10         return 0;
      11      }
      12      END_OF_MAIN()
      (gdb) print p1
      $1 = 0x0
      (gdb) print p2
      $2 = 0x0
Yuck! Playing with NULL values doesn't really pay off. Ok, while this was a slightly out-of-the-can example, you surely get the point. Remember to check out GDB's manual to learn about more useful commands and/or how to debug your program while it's running and many other things.

Part 4 - things people don't do (but should)

One of the most common errors made by programmers is to neglect to check the return value from a function that may fail. Such an error will often lead to unexpected and downright unusual errors, making for a debugging nightmare. There are many functions in and out of Allegro that may or may not work depending on varying circumstances. They are, however, nice enough to let you know whether or not they were successful through documented return values.

Whenever you call a function that might fail (most importantly set_gfx_mode(), install_sound(), and anything that loads data from the disk), it is _essential_ that you check the return code from this, and respond accordingly.

Another commonly forgotten but important tool is to use whatever option enables strict warnings for your compiler (gcc uses -Wall), when compiling your code. Any warnings reported by this option will almost certainly represent errors in your program, and should be fixed before doing anything else. When using gcc, a useful trick is to compile with the -O setting as well, because this causes gcc to examine the program's actions in more detail, enabling more useful warnings. You should normally disable optimisation while debugging, though. Although it gives better compile time warnings, it is likely to upset any debugging tools that you later try to use.

Part 5 - asking for help

Ok, so you've tried everything described above, and your program still doesn't work. You have no idea what to do next, so it is time to cast yourself unto the mercies of the net, in hopes of finding some kind of wise man, seer, or oracle that holds an answer for your question...

The best place to ask is the Allegro mailing list: see readme.txt for details. Please remember that this is an Allegro-specific list, though. Problems relating to the C language or djgpp compiler belong in other forums (comp.lang.c and comp.os.msdos.djgpp respectively).

Both the Allegro and djgpp mailing lists are archived, and can be searched via their respective homepages. It is very likely that you will be able to find a solution to your problem by looking through the answers to past questions, which will save you needing to post a query at all.

In accordance with proper netiquette, it is assumed that when you post to any forum on the Internet you have at least consulted the relevant documentation first, if not read it in its entirety. If the problem you are having is worth asking hundreds of people the answer for, then it is certainly worth taking a few minutes to try to solve the problem yourself. Allegro is extensively and painstakingly documented and it is considered a prerequisite to posting that you have not only read the text, but examined the example programs as well.

Part 6 - learn from my mistakes

What not to do, Part One:

      "My program crashes. Please tell me why."
Yes, people really do sometimes send me questions like this :-) Despite years of practice I am still totally unable to read minds, so this is a very pointless thing to ask. In order to get help with a problem you must describe it in enough detail that other people will be able to understand and reproduce it: this usually means posting some of your source code.

What not to do, Part Two:

      "I've got a problem with my program. I'm attaching a 500k zip file
      containing ten thousand lines of source code and all the graphics and
      sound data: can you please debug it and tell me what the trouble is?"
After wasting the time and phone bills to download such a huge file, it is unlikely that anyone will even _want_ to help you, let alone invest the amount of time it would take to read and understand such a huge mess of information. You must try to isolate a smaller chunk of code that demonstrates the trouble: the smaller you can make it, the more chance that someone will be able to help you with it. Remember that you are asking other people to do you a favour, so it is your responsibility to make this process as easy for them as you possibly can.

Part 7 - wording your plea

The most important thing is to include code that can be compiled and tested by the person reading your message. Don't just post your entire program: try to extract a small section that includes the specific lines causing your problem, or reproduces the trouble in a simpler way (you will often find that you can locate the error yourself in the process of making this simpler version, so it is a good exercise in itself). This code should be a small but complete program that can actually be compiled and run, because it is very hard to debug incomplete code fragments.

It is best to include the code directly in the text of your email message, because it is easier for people to read this than if they have to extract it from an attachment.

Ideally your example should avoid using any external graphics and data files. It is ok to include a small (max 2k) zip containing such information, or failing that a description of what other files it needs (eg. "put a 32x32 .pcx file called 'tile.pcx' into the same directory as the program). If there is no way that you can simplify things this far, you should upload the program and data to a website and then just post that URL in your message.

You should say what gcc command line you used to build the program, and this should include the -Wall switch.

Describe what you intended this program to do (it may not be instantly obvious to other people), and also what it really does when you run it. There is usually no need to post the actual crash traceback (other people can duplicate this for themselves as long as they are able to compile and run your code), but you should say whether you do get such a traceback, or a lockup, or just incorrect results (and if so, in exactly what way they differ from what you were expecting). It is useful to mark your source with a comment to show what line the crash traceback points to.

Any other information that you can include may also be useful. Most importantly a brief machine description, information about any relevant drivers, and your Allegro version (please don't just say "WIP", but give the exact date if you are using anything other than an official numbered release),

Part 8 - a model of perfection

For reference, here is an example of what I would consider to be an ideal problem report:

   I'm having some trouble using the hicolor video modes in my program,
   although they work fine with the Allegro tests. I'm using Allegro 3.0
   with djgpp 2.02 (gcc version 2.8.1) on a p166, running under win95 and
   using the builtin VESA 2.0 driver, which the vesainfo program describes
   as "Matrox Graphics Inc.".

   This program is supposed to select a 640x480 16 bit resolution, draw a
   blue rectangle near the top left corner of the screen, and then wait for
   a keypress before quitting, but I just get a General Protection Fault
   when I run it.

   I compile it using "gcc -Wall t.c -o t.exe -lalleg", and don't get any
   warnings.

   --- cut here, t.c ---

   #include <stdio.h>
   #include <allegro.h>

   void main()
   {
      BITMAP *bmp = screen;

      install_keyboard();

      if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
         printf("Error setting video mode\n");
         return;
      }

      set_color_depth(16);

      /* crashes during this rectangle call! */
      rectfill(bmp, 32, 32, 64, 64, 0x001F);

      readkey();
   }


ABI compatibility information

     ______   ___    ___
    /\  _  \ /\_ \  /\_ \
    \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
     \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
      \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
       \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
        \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
                                       /\____/
                                       \_/__/

                ABI compatibility information.

         See readme.txt for a more general overview.

Introduction

Once Allegro 4.0 is released, we plan to maintain Application Binary Interface compatibility for the rest of the 4.0.x series. For example, that means you will be able to use a executable compiled using version 4.0.10 with a version 4.0.42 dynamic linker library, or even 4.0.0.

"Whew," you sigh, "I don't have to put allxxxx.dll in my zips anymore."

Ultimately, yes. However, there are some guidelines (rules) you should (must) follow, otherwise things will not work, and you will get angry emails from users and from us (the Allegro "Be Good" Mafia).

Note: ABI compatibility will only be _actively_ maintained for Windows, Linux and BeOS on x86 architectures.

Windows notes

If you don't need a modified version of Allegro then just link your program against an officially blessed non-WIP, non-CVS, non-dodgy version and chocolate chip cookies will fall from the sky. Don't disable any features (eg. colour depths, drivers) in the DLL.

If you require a modified version of Allegro, then please either statically link, or pick a non-standard name for the Allegro DLL. For example, it would be bad mojo to distribute a modified version of Allegro under a name such as all40.dll or alleg40.dll. Instead, call it something like alcustom.dll. Even better, statically link.

For the people who use vanilla Allegro, we will provide a set of "reference" DLLs. If your binary works with those then everything is fine. If you want to distribute Allegro DLLs with your program (usually a good idea), we recommend you distribute our DLLs instead of ones you compiled yourself. We trust you will bodge something up.

Linux notes

To make sure an Allegro binary compiled on your machine will work on another machine, do not disable any "features" with `configure'. Your copy of Allegro must have assembly routines, threads, modules, all colour depths and X11 support enabled, amongst other things. If in doubt, leave it at the default setting.

When you are ready to distribute your binary, run "ldd <mybinary>". It should say something like:

liballeg.so.4.0 => /usr/local/lib/liballeg.so.4.0 (0xdeadbeaf)

It should NOT say:

liballeg.so.4.0.0 => /usr/local/lib/liballeg.so.4.0.0 (0xdeadbeaf)

If you see the latter, that would mean users with later versions of Allegro would not be able to run your binary.

See also the Windows section if you need to use a modified version of Allegro.

For people packaging Allegro for redistribution: Drivers that are built as dynamically loaded modules may be disabled or left out, but all others should be left in. Examples of drivers that are _not_ dynamically loaded include: VBE/AF, DGA1, OSS digital, OSS MIDI. In short, if a program built against a copy of default-options Allegro will work with your final library, all is goodly.

BeOS notes

Most of the things discussed in the Windows notes apply here. In particular, you're encouraged to use a non-WIP, non-CVS unmodified official version of the library, in which case your program should run without problems on foreign machines.

Final notes

Providing source is still better than not providing source. Binaries are good, however, if your code sucks and only you (with the help of witchcraft) can compile it.

If you provided binaries in the past using WIP versions of Allegro, we politely request that you recompile your program using a stable version of Allegro. (Unless, of course, you'd prefer to sleep with the fishes.)

And oh, don't make your compiler generate i686-only code or anything stupid like that.


Allegro Hacker's Guide

The Allegro Hacker's Guide

This is a guide to some of the internal workings of Allegro, for people who are interested in hacking on it. This document is far from complete, and may not always be 100% accurate. Remember that when in doubt, the sources are always the definitive reference. Suggestions for what to include in this document will be very welcome: there is far too much code for me to go over it all in any kind of detail, so I want to concentrate on the things that people find most confusing...

Contents

  • Coding Style
  • Build Process
  • Header Files
  • Definitions
  • Unicode Support
  • Asm Routines
  • Other Stuff
  • How to contribute patches

Coding Style

I'm not going to be a fascist about this, but it does make life easier if all the code uses a consistent layout. If you are going to write and maintain more than one complete source file of your own, I think you are entitled to do that however you like, but for smaller contributions, I will probably reformat your code to fit in with my existing style. It will obviously save me time if you write it this way in the first place, hence this description:

Basic Allegro style: K&R, with 3 space indentation. On disk, though, tab stops are 8 spaces, so if for example a line was indented by 12 spaces, this would be saved out as either 12 space characters or 1 tab and 4 spaces, not as 4 tabs. If your editor can't handle the difference between 3 char internal and 8 char external tab stops, either get a better editor or use indent to clean up after yourself. The indent.pro file included with the Allegro distribution comes close to getting this layout right, but doesn't quite manage it, so some things still need to be cleaned up by hand.

Preprocessor defines and structure names are UPPER_CASE. Function and variable names are lower_case. MixedCaseNames are evil and should not be used. That silly m_pHungarian notation is _really_ evil and should not even be thought about.

All symbols should be declared as static unless that is absolutely not possible, in which case they should be prefixed with an underscore.

Functions look like this:

/* foobar:
 *  Description of what it does.
 */
void foobar(int foo, int bar)
{
   /* do some stuff */
}
Three blank lines between functions.

Conditionals look like:

   if (foo) {
      /* stuff */
   }
   else {
      /* stuff */
   }
The only time when something comes on the same line after a closing brace is at the end of a do/while loop, eg:

   do {
      /* stuff */
   } while (foo);
Case statements look like this:

   switch (foo) {

      case bar:
         /* stuff */
         break;

      default:
         /* stuff */
         break;
   }
Examples of where to put spaces:

   char *p;
   if (condition) { }
   for (x=0; x<10; x++) { }
   function(foo, bar);
   (BITMAP *)data[id].dat;
All sources should begin with the standard header:

/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Brief description of what this file does.
 *
 *      By Author.
 *
 *      Cool stuff added by Someone Else.
 *
 *      Stupid bug fixed by a Third Person.
 *
 *      See readme.txt for copyright information.
 */
Author credits should be added in chronological order, and email addresses should not be included: those can be found in the main credits file, and if they only exist in one place, it is easier to update them when people change address.

People only need to be listed in the source file header if they've made a significant contribution to it (one-line fixes don't count), but no matter how small their addition, they must be added to the docs/thanks._tx file. This is sorted alphabetically by name. If they are already in it, update the text to describe the new addition, otherwise make a new entry for the new contributor. Also, anything more than very tiny modifications should be added to the docs/changes._tx file, which grows from the top in reverse chronological order. This file should briefly describe both the nature of the modification and who did it.

Build Process

This is very different depending on whether you are using autoconf or a fixed makefile. For most platforms, though, the fixup script (eg. fixdjgpp.bat), will create a small makefile, which defines MAKEFILE_INC to the make of another file (eg. makefile.dj), and then includes makefile.all. This contains a lot of generic rules, and includes the file named in MAKEFILE_INC to provide additional platform-specific information. The actual source files are listed in makefile.lst.

There are three library targets: alleg (release), alld (debugging), and allp (profiling). Objects go in obj/compiler/version/, where version is one of alleg, alld, or allp. Libraries go in lib/compiler/. A few generated things (asmdefs.inc, mmxtest.s, etc), go in the root of obj/compiler/. Dependencies are generated by "make depend", and go in obj/compiler/version/makefile.dep, which is included by makefile.all.

When you run "make clean", this only deletes harmless generated files like the objects. "make distclean" strips you right back to the original distribution, including getting rid of the test executables and the library itself. For the ultimate in personal hygene, run "make veryclean", which will wipe absolutely all generated files. After doing this, you will have to run "make depend" before you can build the library, and also "fixdll.bat" if you are working on a Windows platform.

To pass long commandlines to the MSVC and Watcom linkers, the program runner.exe is compiled using gcc, so make can pass it a decent number of arguments. This just saves the parameters into a temporary file, and then invokes the real command using that as an argument file.

All the makefiles currently use gcc for dependency generation, because this is easier than trying to get MSVC or Watcom to output the right info.

The symbol LIBRARY_VERSION, defined at the top of the makefile.ver, is used for including a version number in things like the DLL filename.

Header Files

allegro.h lives in the include/ directory. It is only a placeholder which includes other headers which live in the include/allegro/ tree. The reason for this slightly odd approach is that allegro.h can include things like "allegro/keyboard.h", which will work both in-situ within the build directory, and if we copy allegro.h to the system include directory and the other headers into system_include/allegro/. This avoids cluttering the system directories with lots of our headers, while still allowing programs to just #include <allegro.h>, and also makes it possible for people to access keyboard stuff with #include <allegro/keyboard.h>.

base.h includes alconfig.h, which checks the current platform and includes a helper header for this compiler (aldjgpp.h, almsvc.h, alwatcom.h, etc). That helper header defines a bunch of macros describing the system, emulates whatever things are needed to make the code compile properly, and optionally defines ALLEGRO_EXTRA_HEADER and ALLEGRO_INTERNAL_HEADER if it is going to need any other platform-specific includes.

After including the platform header, the rest of alconfig.h defines a lot of generic helper macros to their default values, but only if the platform header hasn't already overridden these to something specific.

Every module-specific header contains structure definitions and function prototypes. At the end of the file, it may include a header from the include/allegro/inline/ directory which defines related inline routines. If inline asm is supported, this can include in turn asm.inl which imports routines from one of the compiler-specific files al386gcc.h, al386vc.h and al386wat.h; otherwise C versions are used instead. The header alinline.h is a placeholder which includes all the headers defining inline functions.

If ALLEGRO_EXTRA_HEADER is defined, allegro.h includes this at the very end. This is used to include one of the files aldos.h, alwin.h, etc, which define platform-specific things like ID values for the hardware drivers. Unlike the platform files included from the top of allegro.h, these are specific per-OS rather than per-compiler, so the same alwin.h can be used by both MSVC and MinGW32. They describe library functions that relate to this platform, while the earlier header described the basic language syntax.

aintern.h is like the internal.h in earlier Allegro versions, defining routines that are shared between multiple sources, but that we don't generally want user programs to see.

On platforms which have specific, non-portable API routines of their own, these should go in a special header in the root of the include directory, eg. winalleg.h. This can be included by user programs that want to access these routines, while making it very clear to them that by including this header, they are writing non-portable code.

Definitions

All header function prototypes should use the macro AL_FUNC(). Inline routines use the macro AL_INLINE(). Global variables use AL_VAR() or AL_ARRAY(). Global pointers to functions use AL_FUNCPTR(). Pointers to functions which are passed as parameters to other routines or stored in a structure typedef use AL_METHOD(). This may seem like something of an overkill, but it gives us a lot of flexibility to add DLL import/export specifiers, calling convention markers like __cdecl, and even to mangle symbol names on some compilers. If you forget to use these macros, your code won't work on some platforms.

This only applies to header files, though: you can write normal code in the C sources.

The symbol ALLEGRO_SRC is defined while compiling library source files. If you want to inline a function in one of your sources, use the INLINE macro. To declare a zero-sized array in terminal position inside a structure, use the ZERO_SIZE_ARRAY(type, name) macro. To use 64 bit integers, declare a LONG_LONG variable (this won't be defined on all platforms). To do things with filenames, check the macros ALLEGRO_LFN, OTHER_PATH_SEPARATOR, and DEVICE_SEPARATOR. See the headers for details.

Unicode Support

Do not assume that strings are ASCII. They aren't. If you assume they are, your code might work for a while as long as people are only using it with UTF-8 data, but it will die horribly as soon as someone tries to run it with 16 bit Unicode strings, or Chinese GB-code, or some strange MIME format, etc. Whenever you see a char * being passed around, you must be aware that this will actually contain text in whatever format is currently selected, so you have to be damn careful when manipulating strings. Don't ever forget and call a regular libc routine on them!

Use the Unicode functions for all your text manipulation: see the docs for details. When allocating a scratch string on the stack, assume that each character will occupy at most four bytes: this will give you more than enough space for any of the current encoding schemes.

If you want to specify a constant string, use the function uconvert_ascii("my string", buf) to obtain a copy of "my string" in the current encoding format. If buf is NULL, this will use an internal static buffer, but the converted string will be overwritten by the next call to any format conversion routines, so you shouldn't pass it down into other library functions. Normally you should provide the conversion space yourself, allocating buf as a temporary object on the stack.

To convert the other way (eg. before passing an Allegro string to an OS routine that expects ASCII data), call uconvert_toascii(mystring, buf).

For any messages that may be seen by the user, you can call get_config_text("my ascii string") instead of uconvert_ascii(). This will return a pointer to persistent memory (so it is ok to keep the string around indefinitely), after converting into the current text encoding format. This function is cool because it saves you having to bother allocating space for the converted data, and because it allows the string to be replaced by the translations in language.dat. You should be sure to always pass a constant string to get_config_text(), rather than any generated text or data from other string variables: this is so that the findtext.sh script can easily locate all the strings that need to be translated.

Hardware drivers should initialise their name and desc fields to the global empty_string, and store an ASCII driver name in their ascii_name field. The framework code will automatically translate and convert this value, storing the result in both the name and desc fields. For most drivers this will be enough, but if you want to provide a more detailed description, it is up to your driver to set this up from their init routine, and take care of all the required conversions.

Asm Routines

Structure offsets are defined in asmdef.inc, which is generated by asmdef.c. This allows the asm code to use human readable names for the structure members, and to automatically adjust whenever new fields are added, so it will always exactly match the layout of the C structures.

Asm code should use the macro FUNC(name) to declare the start of a routine, and GLOBL(name) whenever it wants to refer to an external symbol (eg. a C variable or function). This is to handle name mangling in a portable way (COFF requires an underscore prefix, ELF does not).

You can modify %ds and %es from asm, as long as you put them back. If USE_FS and FSEG are defined, you can also change %fs, otherwise this is not required and you can safely use nearptr access for everything.

Don't assume that the MMX opcodes will be supported: not every assembler version knows about these. Check the ALLEGRO_MMX macro, and be sure to give up gracefully if these instructions are not available.

Other Stuff

Any portable routines that run inside a timer handler or input callback must be sure to lock all the code and data that they touch. This is done by placing an END_OF_FUNCTION(x) or END_OF_STATIC_FUNCTION(x) after each function definition (this is not required if you declare the function as INLINE, though), and then calling LOCK_FUNCTION() somewhere in your init code. Use LOCK_VARIABLE() to lock global variables, and LOCK_DATA() to lock allocated memory.

Any modules that have cleanup code should register their exit function by calling _add_exit_func(). This will ensure that they are closed down gracefully no matter whether the user calls allegro_exit(), falls off the bottom of main(), or the program dies suddenly due to a runtime error. You must call _remove_exit_func() from inside your shutdown routine, or you will find yourself stuck in an endless loop.

How to contribute patches

Once you are willing to contribute that beautiful hack which does what everybody has been waiting for, the fix for that hideous bug which has been driving you mad for several nights, the nice improved documentation you would have liked to read in the manual for the first time, etc, you have already done the hardest part. Now you only need a way to let the Allegro developers merge your changes in the main distribution.

You could probably send your patch to one of the people working on Allegro, but this is not very safe, it depends on the person you chose being available and willing to do the work for you. The best you can do is to send your patch to the Allegro Developers mailing list. Read the readme.txt file for information on how to subscribe to this list. Alternatively, updated subscription instructions should always be available at http://alleg.sourceforge.net/maillist.en.

Sending your patches to the mailing list instead of a single person is good, because all the subscribed developers can take a look at your modifications, suggest improvements, or find problems, which you can discuss on the same mailing list, letting other developers join the conversation when they consider appropriate. If the modifications are good, they will probably be accepted and merged in the WIP version for the next release. If you aren't lucky, or your patch still needs some work, you will be told why it's not accepted, or what you have to do to improve it. If you aren't subscribed to the list, remember to tell it in your email.

If you have obtained Allegro from an existent release, stable or unstable, you will have all the source code contained in some archive format. You will need it, because to create a patch you need two versions of each modified file, the original version, and your modified version. You will also need the diff tool, which is used to create the patches. This tool is usually packaged as a standalone package in most GNU/Linux distributions with the same name. For DOS, you can get a port from http://www.delorie.com/djgpp/. Just choose a mirror from http://www.delorie.com/djgpp/getting.html, enter the v2gnu directory and download the difxxb.zip package. While you are at it, you can also get a tool named patch (patxxb.zip), which is used to apply patches generated by diff, in case you have to apply the patches somebody else sends to you. Install the binaries in some directory of your path, so that you can use them from anywhere.

If you are planing to modify only one file, you will usually copy this file to the same name in the same directory with the appended extension '.old' before starting to work on it. After you have made your modifications to the file, and verified that they please you, go to the directory containing the modified and original files and type at the prompt:

   diff -u file.c.old file.c > patch
This command will generate a text file which contains the differences between both files in unified output format. Open it with your prefered editor and verify that it contains the modifications you wanted to do: lines you have added will be marked with a plus sign '+', lines you have removed will be marked with a minus sign '-'. If the file is bigger than a few kilobytes, compress it before sending to the developers mailing list, and of course remember to add an explanation of what the patch is meant to do, why it's needed, and any other information you consider relevant.

If the modifications you want to do are scattered through several files and/or directories, this form of patch generation is very tiresome for both ends (you, and the developers). So unpack a fresh copy of the Allegro source somewhere and move it to the parent directory where your current version is, after giving it another name of course, so as to obtain two complete sources trees side by side. Modify the files you wish in your working directory. Once you are finished, go back to the parent directory housing the two source trees and type:

   diff -ur fresh_original_directory working_directory > patch
The '-r' switch makes diff compare directories recursively. Again, do the previous steps of verifying your patch, compressing and sending with correct instructions. If your patch adds or removes files, you will have to add the '-N' switch, because by default diff will ignore files which are only in one of the trees. Of course, you might want to run a 'make clean' in your working directory before running this command, or you will include lots of generated files which have nothing to do with your patch. Or you could edit the resulting patch, but that can be error prone.

If you are working with the cvs version of Allegro which you can get from Sourceforge (http://sourceforge.net/projects/alleg/), you won't need to copy any files at all. Just modify the files you want, go to the root directory of the cvs copy and type:

   cvs diff -u > patch
Unlike the standalone diff, the cvs diff command will work recursively through the Allegro source tree, comparing each file against the Sourceforge repository. The patch will have slightly different headers, but that's ok, once you have it follow the previous process to send it to the developers mailing list. Of course, check cvs' manual for more information and options.


Allegro `const'-correctness

This is a short document about the introduction of `const'-correctness to Allegro. It details what changes have occurred to internal library code, the API changes (mainly transparent) and what you will need to do to adapt code to compile without warnings (again, mainly nothing).

Contents

  • Library changes
  • The AL_CONST preprocessor define
  • Allegro API changes
  • Callback functions and Pointers to Pointers
  • BITMAP objects
  • Finally...

Library changes

There are very few actual changes to the library code itself; only some symbol declarations and definitions have been altered to include AL_CONST. See below for a description of the AL_CONST preprocessor define. In a few places, some string was changed that should not have been - in these cases, the string is simply duplicated and then the duplicate is erased on exiting the function.

In all, there were very few changes to the library code.

The AL_CONST preprocessor define

In order to support compilers which don't know about the `const' keyword, or perhaps use a different keyword, the preprocessor symbol AL_CONST is used wherever `const' would normally be used. Note that in the documentation, I have used `const' for readability.

Allegro API changes

These are, generally speaking, totally transparent to the user. I did not change the behaviour of any function; only its parameter types. Basically, if you can pass it as type* ptr, then you can pass it as const type* ptr without any problem whatsoever. Note also that certain changes may remove warnings in your program as static strings, etc, are now treated as `const' by Allegro functions.

There are a few places, described below, where there will be an effect on existing code.

`const'-correctness is deemed important for two reasons. Firstly, it can increase code readability and comprehension of Allegro functions (for instance, you can see which parameters are altered and which are not). Secondly, it ensures that the Allegro code is not changing data which it should not be, and that client callback functions are not breaking Allegro by changing data they should not be.

Callback functions and Pointers to Pointers

Certain callback functions now have a different type - they take `const' pointers as opposed to non-`const' pointers. As far as I know, a compiler will issue a warning about incompatible pointer types. You should update your callback function to the new format (which will be listed in the main Allegro documentation).

Also, when passing a pointer to a pointer to an Allegro function which is declared as taking an AL_CONST type** ptr, you will need to cast your pointer to be `const' if it is not already. For instance:

int some_allegro_function(AL_CONST char** p);

void my_func(char** x)
{
    some_allegro_function((AL_CONST char**) x);
}

I realise that this is a change to the Allegro API, and that we are supposed to avoid those at all costs, but this is essentially fixing a bug in Allegro and changing behaviour. It also ensures that client-supplied callback functions are functioning correctly, and not altering data that they should not. Callback functions which do not treat relevant parameters as `const' are, in a small (but potentially signficant) way, broken.

Please note that for the Unicode function ugetx(), I have provided an alternative version ugetxc(), which takes a `const char**' parameter as opposed to a `char**' parameter. This is because it is valid to pass either a `char**' or a `const char**', but unfortunately there is no way to tell the compiler exactly what we mean.

BITMAP objects

Allegro represents both a screen bitmap and a memory bitmap by a single object; a BITMAP. Unfortunately, these two things can be very different. For instance, reading a pixel from a bitmap would not seem to change it, but if it is a screen bitmap we are reading from, then it is possible that some parameter of the video card is changed to select the correct line, etc.

Therefore, a const BITMAP parameter does not make sense, and is not used throughout the library. This is unfortunate, but I cannot see any way around it.

Finally...

I have only tested this myself on DJGPP 2.95.2, so if you have experiences of it not working (I have tried to get Linux and BeOS ports right, but I've no guarantee it worked...) email me the *exact* error message and I will fix it. You can also contact the Allegro conductors list; see `How to get help' in the Allegro documentation.

Email: lwithers@lwithers.demon.co.uk

Thanks for listening :-)


Conclusion

All good things must come to an end. Writing documentation is not a good thing, though, and that means it goes on for ever. There is always something I've forgotten to explain, or some essential detail I've left out, but for now you will have to make do with this. Feel free to ask if you can't figure something out.

Enjoy. I hope you find some of this stuff useful.

By Shawn Hargreaves.

http://alleg.sourceforge.net/


Allegro - a game programming library

     ______   ___    ___
    /\  _  \ /\_ \  /\_ \
    \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
     \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
      \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
       \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
        \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
                                       /\____/
                                       \_/__/     Version 4.0.3

                A game programming library.

             By Shawn Hargreaves, Apr 19, 2003.

                See the AUTHORS file for a
               complete list of contributors.

#include <std_disclaimer.h>

"I do not accept responsibility for any effects, adverse or otherwise, that this code may have on you, your computer, your sanity, your dog, and anything else that you can think of. Use it at your own risk."

Contents

  • Using Allegro
  • Unicode routines
  • Configuration routines
  • Mouse routines
  • Timer routines
  • Keyboard routines
  • Joystick routines
  • Graphics modes
  • Bitmap objects
  • Loading image files
  • Palette routines
  • Truecolor pixel formats
  • Drawing primitives
  • Blitting and sprites
  • RLE sprites
  • Compiled sprites
  • Text output
  • Polygon rendering
  • Transparency and patterned drawing
  • Converting between color formats
  • Direct access to video memory
  • FLIC routines
  • Sound init routines
  • Digital sample routines
  • MIDI music routines
  • Audio stream routines
  • Recording routines
  • File and compression routines
  • Datafile routines
  • Fixed point math routines
  • 3D math routines
  • Quaternion math routines
  • GUI routines
  • DOS specifics
  • Windows specifics
  • Unix specifics
  • BeOS specifics
  • QNX specifics
  • Differences between platforms
  • Reducing your executable size
  • Debugging
  • Makefile targets
  • Changes
  • Thanks
  • FAQ
  • Help
  • abi
  • aHack
  • const
  • Conclusion