______ ___ ___ /\ _ \ /\_ \ /\_ \ \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ /\____/ \_/__/ Version 4.2.0 A game programming library. By Shawn Hargreaves, Nov 05, 2005. See the AUTHORS file for a complete list of contributors. #include "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." ======================================= ============ Using Allegro ============ ======================================= 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 other functions that can be called before this one will be marked explicitly in the documentation, like set_config_file(). 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. Example: install_allegro(SYSTEM_AUTODETECT, &errno, atexit); This function returns zero on success and non-zero on failure (e.g. no system driver could be used). Note: in previous versions of Allegro this function would abort on error. 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. Note that after you call this function, other functions like destroy_bitmap() will most likely crash. This is a problem for C++ global destructors, which usually get called after atexit(), so don't put Allegro calls in them. You can write the destructor code in another method which you can manually call before your program exits, avoiding this problem. 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, some flavours of UNIX or MacOS X. 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(), install_sound() and other functions 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. Example: void abort_on_error(const char *message) { if (screen != NULL) set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("%s.\nLast Allegro error `%s'\n", message, allegro_error); exit(-1); } ... if (some_allegro_function() == ERROR_CODE) abort_on_error("Error calling some function!"); #define ALLEGRO_VERSION Defined to the major version of Allegro. From a version number like 4.1.16, this would be defined to the integer 4. #define ALLEGRO_SUB_VERSION Defined to the middle version of Allegro. From a version number like 4.1.16, this would be defined to the integer 1. #define ALLEGRO_WIP_VERSION Defined to the minor version of Allegro. From a version number like 4.1.16, this would be defined to the integer 16. #define ALLEGRO_VERSION_STR Defined to a text string containing all version numbers and maybe some additional text. This could be `4.1.16 (CVS)' for an Allegro version obtained straight from the CVS repository. #define ALLEGRO_DATE_STR Defined to a text string containing the year this version of Allegro was released, like `2004'. #define ALLEGRO_DATE Defined to an integer containing the release date of Allegro in the packed format `yyyymmdd'. Example: const int year = ALLEGRO_DATE / 10000; const int month = (ALLEGRO_DATE / 100) % 100; const int day = ALLEGRO_DATE % 100; allegro_message("Year %d, month %d, day %d\n", year, month, day); Macro AL_ID(a,b,c,d) This macro can be used to create a packed 32 bit integer from 8 bit characters, on both 32 and 64 bit machines. These can be used for various things, like custom datafile objects or system IDs. Example: #define OSTYPE_LINUX AL_ID('T','U','X',' ') Macro MAKE_VERSION(a, b, c) This macro can be used to check if some Allegro version is (binary) compatible with the current version. It is safe to use > and < to check if one version is more recent than another. The third number is ignored if the second number is even, so MAKE_VERSION(4, 2, 0) is equivalent to MAKE_VERSION(4, 2, 1). This is because of our version numbering policy since 4.0.0: the second number is even for stable releases, which must be ABI-compatible with earlier versions of the same series. This macro is mainly useful for addon packages and libraries. See the `ABI compatibility information' section of the manual for more detailed information. Example: /* Check if the current version is compatible with Allegro 4.2.0 */ #if (MAKE_VERSION(4, 2, 0) <= MAKE_VERSION(ALLEGRO_VERSION, \ ALLEGRO_SUB_VERSION, ALLEGRO_WIP_VERSION)) /* Allegro 4.2.0 compatibility */ #else /* Work-around */ #endif 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_DARWIN - Darwin OSTYPE_QNX - QNX OSTYPE_UNIX - Unknown Unix variant OSTYPE_BEOS - BeOS OSTYPE_MACOS - MacOS OSTYPE_MACOSX - MacOS X 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 *text_format, ...); Outputs a message, using a printf() format string. Usually you want to use this to report messages to the user in an OS independant way when some Allegro subsystem cannot be initialised. But you must not use this function if you are in a graphic mode, only before calling set_gfx_mode(), or after a set_gfx_mode(GFX_TEXT). Also, this function depends on a system driver being installed, which means that it won't display the message at all on some platforms if Allegro has not been initialised correctly. On platforms featuring a windowing system, it will bring up a blocking GUI message box. If there is no windowing system, it will try to print the string to a text console, attempting to work around codepage differences by reducing any accented characters to 7-bit ASCII approximations. Example: if (allegro_init() != 0) exit(1); if (init_my_data() != 0) { allegro_message("Sorry, missing game data!\n"); exit(2); } 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. Example: set_window_title("Allegro rules!"); int set_close_button_callback(void (*proc)(void)); On platforms that have a close button, this routine installs a callback function to handle the close event. In other words, when the user clicks the close button on your program's window or any equivalent device, 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 as the `proc' argument to this function to disable the close button functionality, which is the default state. Note that Allegro cannot intercept the close button of a DOS box in Windows. Also note that the supplied callback is also called under MacOS X when the user hits Command-Q or selects "Quit" from the application menu. Example: volatile int close_button_pressed = FALSE; void close_button_handler(void) { close_button_pressed = TRUE; } END_OF_FUNCTION(close_button_handler) ... allegro_init(); LOCK_FUNCTION(close_button_handler); set_close_button_callback(close_button_handler); ... while (!close_button_pressed) do_stuff(); Returns zero on success and non-zero on failure (e.g. the feature is not supported by the platform). int desktop_color_depth(); Finds out the currently selected desktop color depth. You can use this information to make your program use the same color depth as the desktop, which will likely make it run faster because the graphic driver won't be doing unnecessary color conversions behind your back. Under some OSes, switching to a full screen graphics mode may automatically change the desktop color depth. You have, therefore, to call this function before setting any graphics mode in order to retrieve the real desktop color depth. Example: allegro_init(); ... if ((depth = desktop_color_depth()) != 0) { set_color_depth(depth); } Returns the color depth or zero on platforms where this information is not available or does not apply. int get_desktop_resolution(int *width, int *height); Finds out the currently selected desktop resolution. You can use this information to avoid creating windows bigger than the current resolution. This is especially important for some windowed drivers which are unable to create windows bigger than the desktop. Each parameter is a pointer to an integer where one dimension of the screen will be stored. Under some OSes, switching to a full screen graphics mode may automatically change the desktop resolution. You have, therefore, to call this function before setting any graphics mode in order to retrieve the real desktop resolution. Example: int width, height; allegro_init(); ... if (get_desktop_resolution(&width, &height) == 0) { /* Got the resolution correctly */ } 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 the variables you provided for `width' and `height' are undefined. 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[]; On Intel PCs, contains the CPU vendor name if known. On Mac OSX systems this contains the PPC subtype name. On other platforms, this may be an empty string. You can read this variable after you have called check_cpu() (which is automatically called by allegro_init()). extern int cpu_family; Contains the Intel type, where applicable. Allegro defines the following CPU family types: CPU_FAMILY_UNKNOWN - The type of processor is unknown CPU_FAMILY_I386 - The processor is an Intel-compatible 386 CPU_FAMILY_I486 - The processor is an Intel-compatible 486 CPU_FAMILY_I586 - The processor is a Pentium or equivalent CPU_FAMILY_I686 - The processor is a Pentium Pro, II, III or equivalent CPU_FAMILY_ITANIUM - The processor is an Itanium processor CPU_FAMILY_POWERPC - The processor is a PowerPC processor CPU_FAMILY_EXTENDED - The processor type needs to be read from the cpu_model You can read this variable after you have called check_cpu() (which is automatically called by allegro_init()). extern int cpu_model; Contains the CPU submodel, where applicable. Allegro defines at least the following CPU family types (see include/allegro/system.h for a more complete list): CPU_FAMILY_I586: CPU_MODEL_PENTIUM, CPU_MODEL_K5, CPU_MODEL_K6 CPU_FAMILY_I686: CPU_MODEL_PENTIUMPRO, CPU_MODEL_PENTIUMII, CPU_MODEL_PENTIUMIIIKATMAI, CPU_MODEL_PENTIUMIIICOPPERMINE, CPU_MODEL_ATHLON, CPU_MODEL_DURON CPU_FAMILY_EXTENDED: CPU_MODEL_PENTIUMIV, CPU_MODEL_XEON, CPU_MODEL_ATHLON64, CPU_MODEL_OPTERON CPU_FAMILY_POWERPC: CPU_MODEL_POWERPC_x, for x=601-604, 620, 750, 7400, 7450 You can read this variable after you have called check_cpu() (which is automatically called by allegro_init()). Make sure you check the cpu_family and cpu_vendor so you know which models make sense to check. 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 FPU is available. CPU_IA64 - Running on Intel 64 bit CPU CPU_AMD64 - Running on AMD 64 bit CPU 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_SSE3 - Intel SSE3 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"); } You can read this variable after you have called check_cpu() (which is automatically called by allegro_init()). ================================================================= ============ Structures and types defined by Allegro ============ ================================================================= There are several structures and types defined by Allegro which are used in many functions (like the BITMAP structure). This section of the manual describes their useful content from a user point of view when they don't fit very well any of the existing manual sections, and redirects you to the appropiate section when it's already described there. Note that unless stated otherwise, the contents shown here are just for read only purposes, there might be other internal flags, but you shouldn't depend on them being available in past/future versions of Allegro. typedef long fixed This is a fixed point integer which can replace float with similar results and is faster than float on low end machines. Read chapter "Fixed point math routines" for the full explanation. 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 unsigned char *line[]; - pointers to the start of each line 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 `w' and `h' fields can be used to obtain the size of an existing bitmap: bmp = load_bitmap("file.bmp", pal); allegro_message("Bitmap size: (%dx%d)\n", bmp->w, bmp->h); 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 that of the clipping API, which takes inclusive coordinates for all four corners. All the values of this structure should be regarded as read-only, with the exception of the line field, whose access is described in depth in the "Direct access to video memory" section of the manual. If you want to modify the clipping region, please refrain from changing this structure. Use set_clip_rect() instead. typedef struct RLE_SPRITE int w, h; - width and height in pixels int color_depth; - color depth of the image 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. Read chapter "RLE sprites" for a description of the restrictions and how to obtain/use this structure. typedef struct COMPILED_SPRITE short planar; - set if it's a planar (mode-X) sprite short color_depth; - color depth of the image short w, h; - size of the 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. Read chapter "Compiled sprites" for a description of the restrictions and how to obtain/use this structure. 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 Read chapter "Joystick routines" for a description on how to obtain/use this structure. typedef struct JOYSTICK_BUTTON_INFO int b; - boolean on/off flag char *name; - description of this button Read chapter "Joystick routines" for a description on how to obtain/use this structure. typedef struct JOYSTICK_STICK_INFO int flags; - status flags for this input int num_axis; - how many axes do we have? (note the misspelling) JOYSTICK_AXIS_INFO axis[n]; - axis state information char *name; - description of this input Read chapter "Joystick routines" for a description on how to obtain/use this structure. typedef struct JOYSTICK_AXIS_INFO int pos; - analogue axis position int d1, d2; - digital axis position char *name; - description of this axis Read chapter "Joystick routines" for a description on how to obtain/use this structure. typedef struct GFX_MODE_LIST int num_modes; GFX_MODE *mode; Structure returned by get_gfx_mode_list, which contains an array of GFX_MODE structures. typedef struct GFX_MODE int width, height, bpp; Structure contained in GFX_MODE_LIST. #define PAL_SIZE Preprocessor constant equal to 256. typedef PALETTE RGB[PAL_SIZE] Allegro palettes are arrays of PAL_SIZE RGB entries. typedef struct RGB unsigned char r, g, b; Palette entry. It contains an additional field for the purpose of padding but you should not usually care about it. Read chapter "Palette routines" for a description on how to obtain/use this structure. typedef struct V3D fixed x, y, z; - position fixed u, v; - texture map coordinates int c; - color A vertex structure used by polygon3d and other polygon rendering functions. Read the description of polygon3d() for a description on how to obtain/use this structure. typedef struct V3D_f float x, y, z; - position float u, v; - texture map coordinates int c; - color Like V3D but using float values instead of fixed ones. Read the description of polygon3d_f() for a description on how to obtain/use this structure. typedef struct COLOR_MAP unsigned char data[PAL_SIZE][PAL_SIZE]; Read chapter "Transparency and patterned drawing", section "256-color transparency" for a description on how to obtain/use this structure. typedef struct RGB_MAP unsigned char data[32][32][32]; Read chapter "Converting between color formats" for a description on how to obtain/use this structure. 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 Read the description of al_findfirst for a description on how to obtain/use this structure. 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 Read chapter "Datafile routines", section "Using datafiles" for a description on how to obtain/use this structure. typedef struct MATRIX fixed v[3][3]; - 3x3 scaling and rotation component fixed t[3]; - x/y/z translation component Fixed point matrix structure. Read chapter "3D math routines" for a description on how to obtain/use this structure. typedef struct MATRIX_f float v[3][3]; - 3x3 scaling and rotation component float t[3]; - x/y/z translation component Floating point matrix structure. Read chapter "3D math routines" for a description on how to obtain/use this structure. typedef struct QUAT float w, x, y, z; Read chapter "Quaternion math routines" for a description on how to obtain/use this structure. 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 This is the structure which contains a GUI object. Read chapter "GUI routines" for a description on how to obtain/use this structure. 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 Structure used to hold an entry of a menu. Read chapter "GUI routines", section "GUI menus" for a description on how to obtain/use this structure. typedef struct DIALOG_PLAYER A structure which holds GUI data used internally by Allegro. Read the documentation of init_dialog() for a description on how to obtain/use this structure. typedef struct MENU_PLAYER A structure which holds GUI data used internally by Allegro. Read the documentation of init_menu() for a description on how to obtain/use this structure. typedef struct FONT A structure holding an Allegro font, usually created beforehand with the grabber tool or Allegro's default font. Read chapter "Fonts" for a description on how to load/destroy fonts, and chapter "Text output" for a description on how to show text. typedef struct BITMAP ZBUFFER Structure used by Allegro's 3d zbuffered rendering functions. You are not supposed to mix ZBUFFER with BITMAP even though it is currently possible to do so. This is just an internal representation, and it may change in the future. typedef struct SAMPLE int bits; - 8 or 16 int stereo; - sample type flag int freq; - sample frequency int priority; - 0-255 unsigned long len; - length (in samples) unsigned long loop_start; - loop start position unsigned long loop_end; - loop finish position void *data; - raw sample data A sample structure, which holds sound data, used by the digital sample routines. You can consider all of these fields as read only except priority, loop_start and loop_end, which you can change them for example after loading a sample from disk. The priority is a value from 0 to 255 (by default set to 128) and controls how hardware voices on the sound card 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. The variables loop_start and loop_end specify the loop position in sample units, and are set by default to the start and end of the sample. If you are creating your own samples on the fly, you might also want to modify the raw data of the sample pointed by the data field. The sample data are always in unsigned format. This means that if you are loading a PCM encoded sound file with signed 16-bit samples, you would have to XOR every two bytes (i.e. every sample value) with 0x8000 to change the signedness. typedef struct MIDI A structure holding MIDI data. Read chapter "Music routines (MIDI)" for a description on how to obtain/use this structure. typedef struct AUDIOSTREAM int voice; - the hardware voice used for the sample A structure holding an audiostream, which is a convenience wrapper around a SAMPLE structure to double buffer sounds too big to fit into memory, or do clever things like generating the sound wave real time. While you shouldn't modify directly the value of the voice, you can use all of the voice functions in chapter "Digital sample routines" to modify the properties of the sound, like the frequency. typedef struct PACKFILE A packfile structure, similar to the libc FILE structure. Read chapter "File and compression routines" for a description on how to obtain/use this structure. Note that prior to version 4.1.18, some internal fields were accidentally documented - but PACKFILE should be treated as an opaque structure, just like the libc FILE type. typedef struct PACKFILE_VTABLE int pf_fclose(void *userdata); int pf_getc(void *userdata); int pf_ungetc(int c, void *userdata); long pf_fread(void *p, long n, void *userdata); int pf_putc(int c, void *userdata); long pf_fwrite(const void *p, long n, void *userdata); int pf_fseek(void *userdata, int offset); int pf_feof(void *userdata); int pf_ferror(void *userdata); This is the vtable which must be provided for custom packfiles, which then can read from and write to wherever you like (eg. files in memory). You should provide all the entries of the vtable, even if they are empty stubs doing nothing, to avoid Allegro (or you) calling a NULL method at some point. typedef struct LZSS_PACK_DATA Opaque structure for handling LZSS compression. Read chapter "File and compression routines for a description on how to obtain/use this structure. typedef struct LZSS_UNPACK_DATA Opaque structure for handling LZSS decompression. Read chapter "File and compression routines for a description on how to obtain/use this structure. ========================================== ============ Unicode routines ============ ========================================== 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 four 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. `type' should be one of these 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); Finds out what text encoding format is currently selected. This function is probably useful only if you are writing an Allegro addon dealing with text strings and you use a different codepath for each possible format. Example: switch(get_uformat()) { case U_ASCII: do_something(); break; case U_UTF8: do_something_else(); break; ... } Returns the currently selected text encoding format. See the documentation of set_uformat() for a list of encoding formats. 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 list 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). Allegro will use the `table' parameter when it needs to convert an ASCII string to an Unicode string. But when Allegro converts an Unicode string to ASCII, it will use both parameters. First, it will loop through the `table' parameter looking for an index position pointing at the unicode value it is trying to convert (ie. the `table' parameter is also used for reverse matching). If that fails, the `extras' list is used. If that fails too, Allegro will put the character `^', giving up the conversion. Note that Allegro comes with a default `table' and `extras' parameters set internally. The default `table' will convert 8-bit characters to `^'. The default `extras' list reduces Latin-1 and Extended-A characters to 7 bits in a sensible way (eg. an accented vowel will be reduced to the same vowel without the accent). int need_uconvert(const char *s, int type, int newtype); Given a pointer to a string (`s'), a description of the type of the string (`type'), and the type that you would like this string to be converted into (`newtype'), 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 encoding format is currently selected. Example: if (need_uconvert(text, U_UTF8, U_CURRENT)) { /* conversion is required */ } Returns non-zero if any conversion is required or zero otherwise. int uconvert_size(const char *s, int type, int newtype); Finds out how many bytes are required to store the specified string `s' after a conversion from `type' to `newtype', including the mandatory zero terminator of the string. You can use U_CURRENT for either `type' or `newtype' as a shortcut to represent whatever text encoding format is currently selected. Example: length = uconvert_size(old_string, U_CURRENT, U_UNICODE); new_string = malloc(length); ustrcpy(new_string, old_string); Returns the number of bytes required to store the string after conversion. void do_uconvert(const char *s, int type, char *buf, int newtype, int size); Converts the specified string `s' 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. Example: char temp_string[256]; do_uconvert(input_string, U_CURRENT, temp_string, U_ASCII, 256); Note that, even for empty strings, your destination string must have at least enough bytes to store the terminating null character of the string, and your parameter size must reflect this. Otherwise, the debug version of Allegro will abort at an assertion, and the release version of Allegro will overrun the destination buffer. 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 `s' from `type' to `newtype', storing at most `size' bytes into the output `buf' (including the terminating null character), 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). As a convenience, if `buf' is NULL it will convert the string into an internal static buffer and the `size' parameter will be ignored. 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. The static buffer may hold less than 1024 characters, so you won't be able to convert large chunks of text. Example: char *p = uconvert(input_string, U_CURRENT, buffer, U_ASCII, 256); Returns a pointer to `buf' (or the static buffer if you used NULL) if a conversion was performed. Otherwise returns a copy of `s'. In any cases, you should use the return value rather than assuming that the string will always be moved to `buf'. 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. Example: int first_unicode_letter = ugetc(text_string); Returns the character pointed to by `s' in the current encoding format. int ugetx(char **s); int ugetxc(const char **s); Low level helper function for reading Unicode text data. ugetxc is provided for working with pointer-to-pointer-to-const char data. Example: char *p = string; int first_letter, second_letter, third_letter; first_letter = ugetx(&p); second_letter = ugetx(&p); third_letter = ugetx(&p); Returns the character pointed to by `s' in the current encoding format, and advances the pointer to the next character after the one just returned. int usetc(char *s, int c); Low level helper function for writing Unicode text data. Writes the character `c' to the address pointed to by `s'. Returns the number of bytes written, which is equal to the width of the character in the current encoding format. int uwidth(const char *s); Low level helper function for testing Unicode text data. 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. 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. Finds out if the character value `c' can be encoded correctly in the current format, which can be useful if you are converting from Unicode to ASCII or another encoding format where the range of valid characters is limited. Returns non-zero if the value can be correctly encoded, zero otherwise. int uoffset(const char *s, int index); Finds out the offset (in bytes from the start of the string) of the character at the specified `index' in the string `s'. A zero `index' parameter will return the first character of the string. If `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. Example: int from_third_letter = uoffset(text_string, 2); Returns the offset in bytes to the specified character. int ugetat(const char *s, int index); Finds out the character value at the specified `index' in the string. A zero `index' parameter will return the first character of the string. If `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. Example: int third_letter = ugetat(text_string, 2); Returns the character value at the specified index in the string. int usetat(char *s, int index, int c); Replaces the character at the specified index in 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). If `index' is negative, it counts backward from the end of the string. Example: usetat(text_string, 2, letter_a); Returns the number of bytes by which the trailing part of the string was moved. This is of interest only with text encoding formats where characters have a variable length, like UTF-8. int uinsert(char *s, int index, int c); Inserts the character `c' at the specified `index' in the string, sliding the rest of the data along to make room. If `index' is negative, it counts backward from the end of the string. Example: uinsert(text_string, 0, prefix_letter); Returns the number of bytes by which the trailing part of the string was moved. 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. If `index' is negative, it counts backward from the end of the string. Example: int length_in_bytes = ustrsizez(text_string); ... length_in_bytes -= uremove(text_string, -1); Returns the number of bytes by which the trailing part of the string was moved. int ustrsize(const char *s); Returns the size of the specified string in bytes, not including the trailing null character. int ustrsizez(const char *s); Returns the size of the specified string in bytes, including the trailing null character. 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. Example: char *temp_buffer = malloc(256 * uwidth_max(U_UTF8)); 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. Example: for (counter = 0; counter < ustrlen(text_string); counter++) { if (uisspace(ugetat(text_string, counter))) usetat(text_string, counter, '_'); } int uisdigit(int c); Returns nonzero if `c' is a digit. for (counter = 0; counter < ustrlen(text_string); counter++) { if (uisdigit(ugetat(text_string, counter))) usetat(text_string, counter, '*'); } char *ustrdup(const char *src) This functions copies the null-terminated string `src' into a newly allocated area of memory, effectively duplicating it. Example: void manipulate_string(const char *input_string) { char *temp_buffer = ustrdup(input_string); /* Now we can modify temp_buffer */ ... Returns the newly allocated string. This memory 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 a custom memory allocator function. char *ustrcpy(char *dest, const char *src); This function copies `src' (including the terminating null character into `dest'. You should try to avoid this function because it is very easy to overflow the destination buffer. Use ustrzcpy instead. Returns 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 even if `src' is bigger than `size'. Note that, even for empty strings, your destination string must have at least enough bytes to store the terminating null character of the string, and your parameter size must reflect this. Otherwise, the debug version of Allegro will abort at an assertion, and the release version of Allegro will overrun the destination buffer. Returns the value of `dest'. char *ustrcat(char *dest, const char *src); This function concatenates `src' to the end of `dest`'. You should try to avoid this function because it is very easy to overflow the destination buffer, use ustrzcat instead. Returns 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 even when `src' is bigger than `size'. Note that, even for empty strings, your destination string must have at least enough bytes to store the terminating null character of the string, and your parameter size must reflect this. Otherwise, the debug version of Allegro will abort at an assertion, and the release version of Allegro will overrun the destination buffer. Returns 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. In any case, `dest' is guaranteed to be null-terminated. Note that, even for empty strings, your destination string must have at least enough bytes to store the terminating null character of the string, and your parameter `size' must reflect this. Otherwise, the debug version of Allegro will abort at an assertion, and the release version of Allegro will overrun the destination buffer. 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. You should try to avoid this function because it is very easy to overflow the destination buffer. Use ustrzncat instead. 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'. Example: if (ustrncmp(prefix, long_string, ustrlen(prefix)) == 0) { /* long_string starts with prefix */ } 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. Example: if (ustricmp(string, user_input) == 0) { /* string and user_input are equal (ignoring case) */ } Returns zero if the strings are equal, a positive number if `s1' comes after `s2' in the ASCII collating sequence, else a negative number. int ustrnicmp(const char *s1, const char *s2, int n); This function compares up to `n' characters of `s1' and `s2', ignoring case. Example: if (ustrnicmp(prefix, long_string, ustrlen(prefix)) == 0) { /* long_string starts with prefix (ignoring case) */ } 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 *ustrlwr(char *s); This function replaces all upper case letters in `s' with lower case letters. Example: char buffer[] = "UPPER CASE STRING"; allegro_message(ustrlwr(buffer)); The return value is the value of `s'. char *ustrupr(char *s); This function replaces all lower case letters in `s' with upper case letters. Example: char buffer[] = "lower case string"; allegro_message(ustrupr(buffer)); The return value is the value of `s'. char *ustrchr(const char *s, int c); Finds the first occurrence of the character `c' in the string `s'. Example: char *p = ustrchr("one,two,three,four", ','); 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); Finds the last occurrence of the character `c' in the string `s'. Example: char *p = ustrrchr("one,two,three,four", ','); Returns a pointer fo 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 string `s2' in string `s1'. Example: char *p = ustrstr("hello world", "world"); 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'. Example: char *p = ustrpbrk("one,two-three.four", "-. "); 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. 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). Example: char *word; char string[]="some-words with dashes"; char *temp = ustrdup(string); word = ustrtok(temp, " -"); while (word) { allegro_message("Found `%s'\n", word); word = ustrtok(NULL, " -"); } free(temp); Returns a pointer to the token, or NULL if no more are found. 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. Example: char *word, *last; char string[]="some-words with dashes"; char *temp = ustrdup(string); word = ustrtok_r(string, " -", &last); while (word) { allegro_message("Found `%s'\n", word); word = ustrtok_r(NULL, " -", &last); } free(temp); Returns a pointer to the token, or NULL if no more are found. You can free the memory pointed to by `last' once NULL is returned. 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, 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. Example: char *endp, *string = "456.203 askdfg"; int number = ustrtol(string, &endp, 10); Returns the string converted as a value of type `long int'. If nothing was converted, returns zero with `*endp' pointing to the beginning of `s'. 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. Example: char *endp, *string = "456.203 askdfg"; double number = ustrtod(string, &endp); Returns the string converted as a value of type `double'. If nothing was converted, returns zero with *endp pointing to the beginning of s. const char *ustrerror(int err); This function returns a string that describes the error code `err', which normally comes from the variable `errno'. Example: PACKFILE *input_file = pack_fopen("badname", "r"); if (input_file == NULL) allegro_message("%s\nSorry!\n", ustrerror(errno)); Returns a pointer to a static string that should not be modified or freed. If you make subsequent calls to ustrerror(), the string will 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. You should try to avoid this function because it is very easy to overflow the destination buffer. Use uszprintf instead. 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. Example: char buffer[10]; int player_score; ... uszprintf(buffer, sizeof(buffer), "Your score is: %d", player_score); 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. You can use this function to implement printf like functions, also called variadic functions. You should try to avoid this function because it is very easy to overflow the destination buffer. Use uvszprintf instead. Returns the number of characters written, not including the terminating null character. 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. Example: #include void log_message(const char *format, ...) { char buffer[100]; va_list parameters; va_start(parameters, format); uvszprintf(buffer, sizeof(buffer), format, parameters); va_end(parameters); append_buffer_to_logfile(log_name, buffer); send_buffer_to_other_networked_players(multicast_ip, buffer); and_also_print_it_on_the_screen(cool_font, buffer); } void some_other_function(void) { log_message("Hello %s, are you %d years old?\n", "Dave", 25); } Returns the number of characters that would have been written without eventual truncation (like with uvsprintf), not including the terminating null character. ================================================ ============ Configuration routines ============ ================================================ 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. MacOS X also checks in the Contents/Resources directory of the application bundle, if any, before doing the checks above. 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 also extend the paths searched for allegro resources with set_allegro_resource_path(). You can store whatever custom information you like in the config file, along with the standard variables that are used by Allegro (see below). Allegro comes with a setup directory where you can find configuration programs. The standalone setup program is likely to be of interest to final users. It allows any user to create an `allegro.cfg' file without the need to touch a text editor and enter values by hand. It also provides a few basic tests like sound playing for soundcard testing. You are welcome to include the setup program with your game, either as is or with modified graphics to fit better your game. 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 and the usual platform-specific paths for configuration files. For example it will look for `/etc/allegro.cfg' under Unix. All pointers returned by previous calls to get_config_string() and other related functions are invalidated when you call this function! You can call this function before install_allegro() to change the configuration file, but after set_uformat() if you want to use a text encoding format other than the default. 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. The override config file will not only take precedence when reading, but will also be used for storing values. When you are done with using the override config file, you can call override_config_file with a NULL parameter, so config data will be directly read from the current config file again. Note: The override file is completely independent from the current configuration. You can e.g. call set_config_file, and the override file will still be active. Also the flush_config_file function will only affect the current config file (which can be changed with set_config_file), never the overriding one specified with this function. The modified override config is written back to disk whenever you call override_config_file. Example: override_config_file("my.cfg"); /* This will read from my.cfg, and if it doesn't find a * setting, will read from the current config file instead. */ language = get_config_string("system", "language", NULL); /* This will always write to my.cfg, no matter if the * settings is already present or not. */ set_config_string("system", "language", "RU"); /* This forces the changed setting to be written back to * disk. Else it is written back at the next call to * override_config_file, or when Allegro shuts down. */ override_config_file(NULL); Note that this function and override_config_data() are mutually exclusive, i.e. calling one will cancel the effects of the other. 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. The length of the block has to be specified in bytes. Example: /* Force German as system language, Spanish keyboard map. */ const char *override_data = "[system]\n" "language=DE\n" "keyboard=ES"; override_config_data(override_data, ustrsize(override_data)); Note that this function and override_config_file() are mutually exclusive, i.e. calling one will cancel the effects of the other. 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. Example: ... /* The user selects French from a language choice menu. */ reload_config_texts("FR"); 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. Example: int decode_encrypted_int(const char *name, int def) { ... } const char *decode_encrypted_string(const char *name, const char *def) { ... } void encode_plaintext_string(const char *name, const char *value) { ... } int main(int argc, char *argv[]) { ... /* Make it harder for users to tinker with the high scores. */ hook_config_section("high_scores", decode_encrypted_int, decode_encrypted_string, encode_plaintext_string); ... } END_OF_MAIN() int config_is_hooked(const char *section); Returns TRUE if the specified config section has been hooked. Example: if (config_is_hooked("high_scores")) { hook_config_section("high_scores, NULL, NULL, NULL); } const char *get_config_string(const char *section, const char *name, const char *def); Retrieves a string variable from the current config file. 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. Example: const char *lang = get_config_string("system", "language", "EN"); Returns a pointer to the constant string found in the configuration file. If the named variable cannot be found, or its entry in the config file is empty, the value of `def' is returned. 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. 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. Returns an argv style argument list and sets `argc' to the number of retrieved tokens. If the variable is not present, returns NULL and sets argc to zero. 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. 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. Note that if you are planning on distributing your game on the Unix platform there is a special issue with how to deal with the `language.dat' file. Read section "Files shared by Allegro" of the chapter "Unix specifics" to learn more about this. Returns a suitable translation if one can be found or a copy of the parameter if nothing else is available. 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(). Standard config variables ------------------------- 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 `es'. 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. If there is none for your language, you can create it using the English one as model, and even send it to the Allegro development team to include it in future releases. disable_screensaver = x Specifies whether to disable the screensaver: 0 to never disable it, 1 to disable it in fullscreen mode only and 2 to always disable it. Default is 1. 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. [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. disable_vsync = x Specifies whether to disable synchronization with the vertical blank when page-flipping (yes or no). Disabling synchronization may increase the frame rate on slow systems, at the expense of introducing flicker on fast systems. 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) EV - Event interfaces (EVDEV) 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 to zero or positive values, negative values will be ignored. 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 no. mouse_device = x Linux only: specifies the name of the mouse device file (eg. `/dev/mouse'). ev_absolute = x Linux only: specifies the mode for the default EV input: 0 - relative mode: pointer position changes if the input moves, 1 - absolute mode: pointer position is the input position. If unspecified, the mode is relative. If the device supports several tools (such as a graphic tablet), the default input is the mouse. If the device has only one tool (e.g. a normal mouse) the default input is this tool. All additionnal tools work in absolute mode. ev_min_x = x ev_max_x = x ev_min_y = x ev_max_y = x ev_min_z = x ev_max_z = x Linux only: for absolute EV inputs, minimum and maximum value. By default this information is autodetected. 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 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: card number and PCM device for the ALSA 0.5 sound driver. alsa_device = x Unix only: device name for the ALSA 0.9 sound driver. The format is [:,], for example: `hw:0,1'. alsa_mixer_device = x Unix only: mixer device name for the ALSA 0.9 sound driver. The default is "default". alsa_mixer_elem = x Unix only: mixer element name for the ALSA 0.9 driver. The default is PCM. 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: card number and device for the ALSA 0.5 midi driver. alsa_rawmidi_device = x Unix only: device for the ALSA 0.5 midi driver or device name for the ALSA 0.9 midi driver (see alsa_device for the format). jack_client_name = x Sets the name with which Allegro should identify itself to the Jack audio server. jack_buffer_size = x Forces a buffer size for the transfer buffer from Allegro's mixer to Jack. 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. ca_midi_quality = x MacOS X only: CoreAudio MIDI synthesizer rendering quality, from 0 to 127. Higher qualities sound better but increase the CPU work load. ca_midi_reverb = x MacOS X only: CoreAudio MIDI synthesizer reverberation intensity, from 0 to 5. 0 equals to a small room (low reverb), 5 to a plate (high reverb). 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 = 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 and Linux only: specifies the name of the joystick device to be used (as reported in the system joystick preferences under BeOS). The first device found is used by default. If you want to specify the device for each joystick, use variables of the form joystick_device_n, where n is the joystick number. throttle_axis = x Linux only: sets the 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 ============ ======================================== Allegro provides functions for reading the mouse state and displaying a mouse cursor on-screen. You can read the absolute position of the mouse and the state of the mouse buttons from global variables. Additionally, you can read the mouse position difference as mouse mickeys, which is the number of pixels the cursor moved since the last time this information was read. Allegro offers three ways to display the mouse cursor: Standard Allegro cursor Allegro is responsible for drawing the mouse cursor from a timer. Use set_mouse_sprite() and show_mouse() to define your own cursor and display it on the screen. You need to call scare_mouse()/unscare_mouse() to hide the mouse cursor whenever you draw to the screen. Custom operating system cursor (hardware cursor) Allegro will let the operating system draw the mouse cursor. Use set_mouse_sprite() and show_mouse() (or show_os_cursor) to define your own cursor and display it on the screen. Not all graphics drivers are capable of this and some may only be able to display cursors upto a certain size. Allegro will fall back on its own cursor drawing if it cannot let the OS handle this. On some platforms, the hardware cursor is incompatible with get_mouse_mickeys() and it is therefor disabled by default. In such cases you need to call enable_hardware_cursor() to enable it explicitly. Default operating system cursor Allegro will not draw its own cursor, but use the operating system default cursor. You can use the select_mouse_cursor() function to select the cursor shape to display. As with custom operating system cursors, you need to call enable_hardware_cursor() before you can use this. Or you can use the low level show_os_cursor() function. Not all drivers will support all functionality. See the platform specific information for more details. int install_mouse(); Installs the Allegro mouse handler. You must do this before using any other mouse functions. Returns -1 on failure, zero if the mouse handler is already installed (in which case this function does nothing) and the number of buttons on the mouse if the mouse handler has successfully been installed (ie. this is the first time a handler is installed or you have removed the previous one). Note that the number of mouse buttons returned by this function is more an indication than a physical reality. With most devices there is no way of telling how many buttons there are, and any user can override the number of mouse buttons returned by this function with a custom configuration file and the variable num_buttons. Even if this value is overriden by the user, the global mouse variables will still report whatever the hardware is sending. 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. void enable_hardware_cursor(void); After calling this function, Allegro will let the operating system draw the mouse cursor instead of doing it itself. This is not possible with all graphics drivers though: you'll need to check the gfx_capabilities flags after calling show_mouse() to see if this works. On some platforms, enabling the hardware cursor causes get_mouse_mickeys() to return only a limited range of values, so you should not call this function if you need mouse mickeys. void disable_hardware_cursor(void); After calling this function, Allegro will be responsible for drawing the mouse cursor rather than the operating system. On some platforms calling enable_hardware_cursor() makes the return values of get_mouse_mickeys() unreliable. After calling this function, get_mouse_mickeys() returns reliable results again. void select_mouse_cursor(int cursor); This function allows you to use the operating system's native mouse cursors rather than some custom cursor. You will need to enable this functionality by calling enable_hardware_cursor() beforehand. If the operating system does not support this functionality, or if it has not been enabled, then Allegro will substitute its own cursor images. You can change these substitute images using set_mouse_cursor_bitmap(). Note that the effects of this function are not apparent until show_mouse() is called. To know whether the operating system's native cursor is being used, or if Allegro has made a substitution, you can check the GFX_SYSTEM_CURSOR flag in gfx_capabilities after calling show_mouse(). The cursor argument selects the type of cursor to be displayed: MOUSE_CURSOR_NONE Selects an invisible mouse cursor. In that sense, it is similar to calling show_mouse(NULL); MOUSE_CURSOR_ALLEGRO Selects the custom Allegro cursor, i.e. the one that you set with set_mouse_sprite(). MOUSE_CURSOR_ARROW The operating system default arrow cursor. MOUSE_CURSOR_BUSY The operating system default `busy' cursor (hourglass). MOUSE_CURSOR_QUESTION The operating system default `question' cursor (arrow with question mark). MOUSE_CURSOR_EDIT The operating system default `edit' cursor (vertical bar). Example: /* initialize mouse sub-system */ install_mouse(); enable_hardware_cursor(); /* Set busy pointer */ select_mouse_cursor(MOUSE_CURSOR_BUSY); show_mouse(screen); /* Initialize stuff */ ... /* Set normal arrow pointer */ select_mouse_cursor(MOUSE_CURSOR_ARROW); void set_mouse_cursor_bitmap(int cursor, BITMAP *bmp); This function changes the cursor image Allegro uses if select_mouse_cursor() is called but no native operating system cursor can be used, e.g. because you did not call enable_hardware_cursor(). The cursor argument can be one of: MOUSE_CURSOR_ALLEGRO MOUSE_CURSOR_ARROW MOUSE_CURSOR_BUSY MOUSE_CURSOR_QUESTION MOUSE_CURSOR_EDIT but not MOUSE_CURSOR_NONE. The bmp argument can either point to a valid bitmap or it can be NULL. Passing a bitmap makes Allegro use that image in place of its own default substition (should the operating system's native cursor be unavailable). The bitmap must remain available for the duration in which it could be used. Passing NULL lets Allegro revert to its default substitutions. The effect of this function will not be apparent until show_mouse() is called. 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. Additional non standard mouse buttons might be available as higher bits in this variable. Usage 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 upper 16 bits and the Y in the lower 16 bits. 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. Example: int pos, x, y; pos = mouse_pos; x = pos >> 16; y = pos & 0x0000ffff; 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 graphics drawing 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. This is not needed if you are using a hardware cursor. 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 or OS 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. int show_os_cursor(int cursor); In case you do not need Allegro's mouse cursor API, which automatically emulates a cursor in software if no other cursor is available, you can use this low level function to try to display or hide the system cursor directly. The cursor parameter takes the same values as select_mouse_cursor. This function is very similar to calling enable_hardware_cursor, select_mouse_cursor and show_mouse, but will not try to do anything if no system cursor is available. The most common use for this function is to just call it once at the beginning of the program to tell it to display the system cursor inside the Allegro window. The return value can be used to see if this suceeded or not. On some systems (e.g. DirectX fullscreen) this is not supported and the function will always fail, and in other cases only some of the cursors will work, or in the case of MOUSE_CURSOR_ALLEGRO, only certain bitmap sizes may be supported. You never should use show_os_cursor together with the function show_mouse and other functions affecting it (select_mouse_cursor, enable_hardware_cursor, disable_hardware_cursor, scare_mouse, unscare_mouse). They implement the standard high level mouse API, and don't work together with this low level function. Returns 0 if a system cursor is being displayed after the function returns, or -1 otherwise. 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 Allegro's mouse pointer? No problem. Use this function to supply an alternative of your own. If you change the pointer and then want to get Allegro's 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 values of mickeyx and mickeyy will become negative if the mouse is moved left or up, respectively. 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. Note that the infinite movement may not work in windowed mode, since under some platforms the mouse would leave the window, and may not work at all if the hardware cursor is in use. 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. Note that even if the mouse has more than three buttons, only the first three can be trapped using a callback. ======================================== ============ Timer routines ============ ======================================== 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. Calling again this routine with the same timer handler as parameter allows you to adjust its speed. Returns zero on success, or a negative number if there is no room to add a new user timer. 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 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. Returns zero on success, or a negative number if there is no room to add a new user timer. Macro LOCK_VARIABLE(variable_name); Due to interrupts, you are required to lock all the memory used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example. Macro LOCK_FUNCTION(function_name); Due to interrupts, you are required to lock all the memory used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example. Macro END_OF_FUNCTION(function_name); Due to interrupts, you are required to lock all the code used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example. 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). extern volatile int retrace_count; If the retrace simulator is installed, this count is incremented on each vertical retrace; otherwise, if the refresh rate is known, the count is incremented at the same rate (ignoring retraces); otherwise, it is incremented 70 times a second. This provides a way of controlling the speed of your program without installing user timer functions. void rest(unsigned int time); This function waits for the specified number of milliseconds. Passing 0 as parameter will not wait, but just yield. This can be useful in order to "play nice" with other processes. Other values will cause CPU time to be dropped on most platforms. This will look better to users, and also does things like saving battery power and making fans less noisy. Note that calling this inside your active game loop is a bad idea, as you never know when the OS will give you the CPU back, so you could end up missing the vertical retrace and skipping frames. On the other hand, on multitasking operating systems it is good form to give up the CPU for a while if you will not be using it. void rest_callback(long time, void (*callback)()) Like rest(), but for non-zero values continually calls the specified function while it is waiting for the required time to elapse. If the provided `callback' parameter is NULL, this function does exactly the same thing as calling rest(). =========================================== ============ Keyboard routines ============ =========================================== 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). On DOS, Allegro requires the user to specify the language of the keyboard mapping because it is impossible to obtain this information from the OS, otherwise the default US keyboard mapping will be used. Allegro comes with a prepackaged `keyboard.dat' file which you can put along with your binary. If this file is present, Allegro will be able to extract the keyboard mapping information stored there. However, the end user still needs to select which keyboard mapping to use. This can be acomplished through the keyboard variable of the system section in a standard `allegro.cfg' configuration file. Read chapter "Configuration routines" for more information about this. 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. Note that on some platforms the keyboard won't work unless you have set a graphics mode, even if this function returns a success value before calling set_gfx_mode. This can happen in environments with graphic windowed modes, since Allegro usually reads the keyboard through the graphical window (which appears after the set_gfx_call). Example: allegro_init(); install_timer(); install_keyboard(); /* We are not 100% sure we can read the keyboard yet! */ if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) abort_on_error("Couldn't set graphic mode!") /* Now we are guaranteed to be able to read the keyboard. */ readkey(); 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_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. However, you might want to call this during runtime if you want to change the keyboard mapping on those platforms were keyboard mappings are needed. You would first modify the configuration variable holding the keyboard mapping and then reinstall the keyboard handler. Example: remove_keyboard(); /* Switch to Spanish keyboard mapping. */ set_config_string("system", "keyboard", "es"); install_keyboard(); 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 KEY_EQUALS_PAD, KEY_BACKQUOTE, KEY_SEMICOLON, KEY_COMMAND Finally, you may notice an `odd' behaviour of the KEY_PAUSE key. This key only generates an interrupt when it is pressed, not when it is released. For this reason, Allegro pretends the pause key is a `state' key, which is the only way to make it usable. 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_COMMAND_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 Example: if (key[KEY_W]) { if (key_shifts & KB_SHIFT_FLAG) { /* User is pressing shift + W. */ } else { /* Hmmm... lower case W then. */ } } int keypressed(); Returns TRUE if there are keypresses waiting in the input buffer. You can use this to see if the next call to readkey() is going to block or to simply wait for the user to press a key while you still update the screen possibly drawing some animation. Example: while (!keypressed()) { /* Show cool animated logo. */ } /* So he skipped our title screen. */ 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. You can see if there are queued keypresses with keypressed(). 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: int val; ... val = readkey(); if ((val & 0xff) == 'd') /* by ASCII code */ allegro_message("You pressed 'd'\n"); if ((val >> 8) == KEY_SPACE) /* by scancode */ allegro_message("You pressed Space\n"); if ((val & 0xff) == 3) /* ctrl+letter */ allegro_message("You pressed Control+C\n"); if (val == (KEY_X << 8)) /* alt+letter */ allegro_message("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. You can see if there are queued keypresses with keypressed(). 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. Example: int val, scancode; ... val = ureadkey(&scancode); if (val == 0x00F1) allegro_message("You pressed n with tilde\n"); if (val == 0x00DF) allegro_message("You pressed sharp s\n"); You should be able to find Unicode character maps at http://www.unicode.org/. Remember that on DOS you must specify a custom keyboard map (like those found in `keyboard.dat') usually with the help of a configuration file specifying the language mapping (keyboard variable in system section of `allegro.cfg'), or you will get the default US keyboard mapping. int scancode_to_ascii(int scancode); Converts the given scancode to an ASCII character for that key (mangling Unicode values), 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. The lookup cannot be done for keys like the F1-F12 keys or the cursor keys, and some drivers will only return approximate values. Generally, if you want to display the name of a key to the user, you should use the scancode_to_name function. Example: int ascii; ... ascii = scancode_to_ascii(scancode); allegro_message("You pressed '%c'\n", ascii); const char *scancode_to_name(int scancode); This function returns a string pointer containing the name of they key with the given scancode. This is useful if you e.g. let the user choose a key for some action, and want to display something more meaningful than just the scancode. Example: char const *keyname = scancode_to_name(scancode); allegro_message("You pressed the %s key.", keyname); 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(). Example: simulate_keypress(KEY_SPACE << 8); if (readkey() == (KEY_SPACE << 8)) allegro_message("You simulated Alt+Space\n"); 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(). Example: /* We ignore the scancode simulation. */ simulate_ukeypress(0x00DF, 0); if (ureadkey(&scancode) == 0x00DF) allegro_message("You simulated sharp s\n"); 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. Example: int enigma_scrambler(int key) { /* Add one to both the scancode and ascii values. */ return (((key >> 8) + 1) } END_OF_FUNCTION(enigma_scrambler) ... install_timer(); LOCK_FUNCTION(enigma_scrambler); install_keyboard(); keyboard_callback = enigma_scrambler; Note that this callback will be ignored if you also set the unicode keyboard callback. 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. Example: int silence_g_key(int key, int *scancode) { if (key == 'g') { *scancode = 0; return 0; } return key; } END_OF_FUNCTION(silence_g_key) ... install_timer(); LOCK_FUNCTION(silence_g_key); install_keyboard(); keyboard_ucallback = silence_g_key; Note that this keyboard callback has priority over the non unicode callback. If you set both, only the unicode one will work. 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 (including keyboard repeat rate) and releases. It will be passed a raw keyboard scancode byte (scancodes are 7 bits long), with the top bit (8th 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. Example: volatile int key_down, key_up; void keypress_watcher(int scancode) { if (scancode & 0x80) { key_up = 1; } else { key_down = 1; } } END_OF_FUNCTION(keypress_watcher) ... install_timer(); LOCK_FUNCTION(silence_g_key); LOCK_VARIABLE(key_down); LOCK_VARIABLE(key_up); install_keyboard(); keyboard_lowlevel_callback = keypress_watcher; /* Disable keyboard repeat to get typewriter effect. */ set_keyboard_rate(0, 0); ... while (game_loop) { if (key_down) { key_down = 0; /* Play sample of typewriter key press. */ } if (key_up) { key_up = 0; /* Play sample of typewriter key release. */ } } 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. Example: /* Cycle led indicators. */ set_leds(KB_SCROLOCK_FLAG); rest(1000); set_leds(KB_CAPSLOCK_FLAG); rest(1000); set_leds(KB_NUMLOCK_FLAG); rest(1000); set_leds(-1); Note that the led behaviour cannot be guaranteed on some platforms, some leds might not react, or none at all. Therefore you shouldn't rely only on them to communicate information to the user, just in case it doesn't get through. 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. Usually you want to use this in your program before reading keys to avoid previously buffered keys to be returned by calls to readkey() or ureadkey(). 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 ============ =========================================== Unlike keyboard or mouse input, which are usually read through hardware interrupts by Allegro, joystick input functions have to be polled because there are no hardware interrupts for them on most platforms. This doesn't mean that you have to poll the joysticks on each line of code you want to read their values, but you should make sure to poll them at least once per frame in your game loop. Otherwise you face the possibility of reading stale incorrect 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. Example: textout_centre_ex(screen, font, "Center the joystick and press a key", SCREEN_W/2, SCREEN_H/2, red_color, -1); readkey(); if (install_joystick(JOY_TYPE_AUTODETECT) != 0) abort_on_error("Error initialising joystick!"); 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. Example: do { /* Get joystick input */ poll_joystick(); /* Process input for the first joystick */ if (joy[0].button[0].b) first_button_pressed(); if (joy[0].button[1].b) second_button_pressed(); ... } while(!done); 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 axes, 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 axes do we have? (note the misspelling) 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); As parameter pass the number of joystick you want to calibrate. 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); textprintf_ex(..., "%s, and press a key\n", msg); readkey(); if (calibrate_joystick(i) != 0) { textprintf_ex(..., "oops!\n"); readkey(); exit(1); } } } Returns zero on success, non-zero if the calibration could not be performed successfully. 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, non-zero if the data could not be saved. 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 ============ ======================================== Graphics modes are the common denominator for most Allegro programs. While it is possible to write platform specific programs using Allegro which don't set a graphic mode through the routines provided in this chapter, these are not very common. The first thing to note is that due to the wide range of supported platforms, a graphic mode is the only way to safely communicate with the user. When Allegro was a DOS only library (versions 3.x and previous), it was frequent for programmers to use functions from the C standard library to communicate with the user, like calling printf() before setting a graphic mode or maybe scanf() to read the user's input. However, what would happen for such a game running under Windows where there is no default console output or it may be hidden from the user? Even if the game compiled successfully, it would be unplayable, especially if there was vital information for the user in those text only messages. Allegro provides the allegro_message() function to deal with this problem, but this is not a very user friendly method of communicating with the user and its main purpose is displaying small error like messages when no graphic mode is available. Therefore, the first thing your Allegro program should do is set a graphic mode, and from there on, use Allegro's text output routines to display messages to the user, just like `allegro/examples/exhello.c' does. Setting a graphic mode involves deciding how to allocate the memory of the video card for your program. On some platforms this means creating a virtual screen bigger than the physical resolution to do hardware scrolling or page flipping. 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 (hardware scrolling). 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) With a virtual screen bigger than the visible screen you can perform smooth CPU inexpensive scrolling: you draw your graphics once, and then only tell the video card to show a different portion of the screen. However, virtual screens are not supported on all platforms, and on some they might be emulated through software, losing any performance. On top of that, many video cards only allow horizontal scrolling in steps of 32 bytes. This is not a problem if your game runs in 24 or 32 bit, but it tends to mean jerky scrolling for other color depths. The other reason you could use virtual screens for is page flipping. This means showing one portion of the virtual screen while your program draws to the hidden one. When you finish, you show the part you have been drawing to and repeat the process with the area now hidden. The result is a perfectly smooth screen update without flickering or other graphical artifacts. Scrolling manually to one part of the video memory is one non portable way to accomplish this. The portable way is to use functions like create_system_bitmap(), create_video_bitmap(), show_video_bitmap(), etc. These functions divide the memory of the video card in areas and switch between them, a feature supported on all platforms and video cards (given that they have enough memory for the screen resolutions you asked for). The last thing you need to know about setting a graphic mode are drivers. Each platform has a number of graphic drivers wich support a different range of hardware or behave in different ways. To avoid cluttering your own code with #ifdefs and dealing with drivers added after you release your program, Allegro provides several so called magic drivers. These magic drivers don't really exists, they wrap around a specific kind of functionality. The magic drivers you can use are: GFX_AUTODETECT: Allegro will try to set the specified resolution with the current color depth in fullscreen mode. Failing that, it will try to repeat the same operation in windowed mode. If the call to set_gfx_mode() succeeds, you are guaranteed to have set the specified resolution in the current color depth, but you don't know if the program is running fullscreen or windowed. GFX_AUTODETECT_FULLSCREEN: Allegro will try to set the specified resolution with the current color depth in fullscreen mode. If that is not possible, set_gfx_mode() will fail. GFX_AUTODETECT_WINDOWED: Allegro will try to set the specified resolution with the current color depth in a windowed mode. If that is not possible, set_gfx_mode() will fail. When it comes to windowed modes, the `specified resolution' actually means the graphic area your program can draw on, without including window decorations (if any). Note that in windowed modes running with a color depth other than the desktop may result in non optimal performance due to internal color conversions in the graphic driver. Use desktop_color_depth() to your advantage in these situations. GFX_SAFE: Using this driver Allegro guarantees that a graphic 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. GFX_TEXT: Closes any previously opened graphics 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. 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. Example: set_color_depth(32); if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) { abort_on_error("Couldn't set a 32 bit color resolution"); } Note that the screen color depth won't change until the next successful call to set_gfx_mode(). int get_color_depth(void); Returns the current pixel format. This can be very useful to know in order to write generic functions which select a different code path internally depending on the color depth being used. Note that the function returns whatever value you may have set previously with set_color_depth(), which can be different from the current color depth of the screen global variable. If you really need to know the color depth of the screen, use bitmap_color_depth(). 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. Example: request_refresh_rate(60); if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) abort_on_error("Couldn't set graphic mode!"); if (get_refresh_rate() != 60) abort_on_error("Couldn't set refresh rate to 60Hz!"); 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, made up from the GFX_MODE_LIST structure, which has the following definition: typedef struct GFX_MODE_LIST { int num_modes; GFX_MODE *mode; } GFX_MODE_LIST; The mode entry points to the actual list of video modes. typedef struct GFX_MODE { int width, height, bpp; } GFX_MODE; This list of video modes 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. Returns a pointer to a list structure of the type GFX_MODE_LIST or NULL if the request could not be satisfied. void destroy_gfx_mode_list(GFX_MODE_LIST *mode_list); Removes the mode list created by get_gfx_mode_list() from memory. Use this once you are done with the generated mode list to avoid memory leaks in your program. 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 one of the Allegro magic drivers (read introduction of chapter "Graphics modes") 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 color depth of the graphic mode has to be specified before calling this function with set_color_depth(). 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. 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 may end up creating a virtual screen much larger than the one you request. Allowed sizes are driver dependent and some drivers do not allow virtual screens that are larger than the visible screen at all: don't assume that whatever you pass will always 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). Currently, using a big virtual screen for page flipping is considered bad practice. There are platforms which don't support virtual screens bigger than the physical screen but can create different video pages to flip back and forth. This means that, if you want page flipping and aren't going to use hardware scrolling, you should call set_gfx_mode() with (0,0) as the virtual screen size and later create the different video pages with create_video_bitmap(). Otherwise your program will be limited to the platforms supporting hardware scrolling. 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. Returns zero on success. On failure returns a negative number and stores a description of the problem in allegro_error. 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. 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 switch 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. Returns zero on success, invalidating at the same time all callbacks previously registered with set_display_switch_callback(). Returns -1 if the requested mode is not currently possible. 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. You can install several switch callbacks, but no more than eight on any platform. Returns zero on success, decreasing the number of empty callback slots by one. Returns -1 if the request is impossible for the current platform or you have reached the maximum number of allowed callbacks. 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(). You can safely call this function even if the callback you want to remove is not installed. int get_display_switch_mode(); Returns the current display switching mode, in the same format passed to set_display_switch_mode(). int is_windowed_mode(void); This function can be used to detect wether or not set_gfx_mode() selected a windowed mode. Example: if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) abort_on_error("Couldn't set graphic mode!"); if (is_windowed_mode()) { /* Windowed mode stuff. */ } else { /* Fullscreen mode stuff. */ } Returns true if the current graphics mode is a windowed mode, or zero if it is a fullscreen mode. You should not call this function if you are not in graphics 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_SYSTEM_CURSOR Indicates that the mouse cursor is the default system cursor, not Allegro's custom cursor. 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, -1 otherwise. 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). 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 with set_clip_rect(). Mode-X scrolling is reliable and will work on any card, other drivers may not work or not work reliably. See the platform-specific section of the docs for more information. 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(). Returns zero on success. Returns non-zero if the graphics driver can't handle hardware scrolling or the virtual screen is not large enough. 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. Triple buffering is only possible with certain drivers: 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, non-zero otherwise. 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. Returns non-zero if it is still waiting to take place, and zero if the requested scroll 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. 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() by default. This can be adjusted with the "disable_vsync" config key in the [graphics] section of allegro.cfg. Example: int current_page; BITMAP *video_page[2]; ... /* Create pages for page flipping */ video_page[0] = create_video_bitmap(SCREEN_W, SCREEN_H); video_page[1] = create_video_bitmap(SCREEN_W, SCREEN_H); current_page = 0; ... /* draw the screen and flip pages */ draw_screen(video_page[current_page]); show_video_bitmap(video_page[current_page]); current_page = (current_page+1)%2; ... Returns zero on success and non-zero on failure. 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(). Example: int current_page; BITMAP *video_page[3]; ... /* Create pages for page flipping */ video_page[0] = create_video_bitmap(SCREEN_W, SCREEN_H); video_page[1] = create_video_bitmap(SCREEN_W, SCREEN_H); video_page[2] = create_video_bitmap(SCREEN_W, SCREEN_H); current_page = 0; ... /* draw the screen and flip pages */ draw_screen(video_page[current_page]); do { } while (poll_scroll()); request_video_bitmap(video_page[current_page]); current_page = (current_page+1)%3; ... Returns zero on success and non-zero on failure. 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. ======================================== ============ Bitmap objects ============ ======================================== 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 two bytes per pixel, in 24-bit modes 3 bytes per pixel and in 32-bit modes 4 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. Read chapter "Direct access to video memory" 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(), so you should never attempt to destroy it yourself. 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 video or system bitmap, 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). Warning: Make sure not to destroy a bitmap before all of its sub-bitmaps, otherwise bad things will happen when you try to access one of these sub-bitmaps. 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. For example, to draw a pixel onto the screen you would write: putpixel(screen, x, y, color); Or to implement a double-buffered system: /* Make a bitmap in RAM. */ BITMAP *bmp = create_bitmap(320, 200); /* Clean the memory bitmap. */ clear_bitmap(bmp); /* Draw onto the memory bitmap. */ putpixel(bmp, x, y, color); /* Copy it to the screen. */ blit(bmp, screen, 0, 0, 0, 0, 320, 200); Warning: be very careful when using this pointer at the same time as any bitmaps created by the create_video_bitmap() function (see the description of this function for more detailed information). And never try to destroy it with destroy_bitmap(). #define SCREEN_W; #define SCREEN_H; Global defines that return the width and height of the screen, or zero if the screen has not been initialised yet. Example: char buf[100]; ... uszprintf(buf, sizeof(buf), "The screen size is %d x %d pixels", SCREEN_W, SCREEN_H); #define VIRTUAL_W; #define VIRTUAL_H; Global defines that return the width and height of the virtual screen, or zero if the screen has not been initialised yet. Example: char buf[100]; ... uszprintf(buf, sizeof(buf), "The virtual screen size is %d x %d pixels", SCREEN_W, SCREEN_H); BITMAP *create_bitmap(int width, int height); Creates a memory bitmap sized width by height. 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(). The minimum height of the BITMAP must be 1 and width can't be negative. Example: /* Create a 10 pixel tall bitmap, as wide as the screen. */ BITMAP *bmp = create_bitmap(SCREEN_W, 10); if (!bmp) abort_on_error("Couldn't create bitmap!"); /* Use the bitmap. */ ... /* Destroy it when we don't need it any more. */ destroy_bitmap(bmp); Returns a pointer to the created bitmap, or NULL if the bitmap could not be created. Remember to free this bitmap later to avoid memory leaks. 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). Example: /* Create screen sized bitmap in 32 bits per pixel. /* BITMAP *bmp = create_bitmap_ex(32, SCREEN_W, SCREEN_H); if (!bmp) abort_on_error("Couldn't create bitmap!"); /* Use the bitmap. */ ... /* Destroy it when we don't need it any more. */ destroy_bitmap(bmp); Returns a pointer to the created bitmap, or NULL if the bitmap could not be created. Remember to free this bitmap later to avoid memory leaks. 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. Returns a pointer to the created sub bitmap, or NULL if the sub bitmap could not be created. Remember to free the sub bitmap before freeing the parent bitmap to avoid memory leaks and potential crashes accessing memory which has been freed. BITMAP *create_video_bitmap(int width, int height); Allocates a video memory bitmap of the specified size. 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(). Read the introduction of this chapter for a comparison with other types of bitmaps and other specific details. Warning: video memory bitmaps are usually allocated from the same space as the screen bitmap, so they may overlap with it; it is therefore not a good idea to use the global screen at the same time as any surfaces returned by this function. Returns a pointer to the bitmap on success, or NULL if you have run out of video ram. Remember to destroy this bitmap before any subsequent call to set_gfx_mode(). BITMAP *create_system_bitmap(int width, int height); Allocates a system memory bitmap of the specified size. Read the introduction of this chapter for a comparison with other types of bitmaps and other specific details. Returns a pointer to the bitmap on success, NULL otherwise. Remember to destroy this bitmap before any subsequent call to set_gfx_mode(). void destroy_bitmap(BITMAP *bitmap); Destroys a memory bitmap, sub-bitmap, video memory bitmap, or system bitmap when you are finished with it. If you pass a NULL pointer this function won't do anything. See above for the restrictions as to when you are allowed to destroy the various types of bitmaps. 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). Example: switch (bitmap_color_depth(screen)) { case 8: /* Access screen using optimized 8-bit code. */ break; default: /* Use generic slow functions. */ break; } 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). A frequent use of this function is to clear a bitmap with the mask color so you can later use this bitmap with masked_blit() or draw_sprite() after drawing other stuff on it. Example: /* Replace mask color with another color. */ for (y = 0; y h; y++) for (x = 0; x w; x++) if (getpixel(bmp, x, y) == bitmap_mask_color(bmp)) putpixel(bmp, x, y, another_color); 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_planar_bitmap(BITMAP *bmp); Returns TRUE if bmp is a planar (mode-X or Xtended mode) screen bitmap. int is_linear_bitmap(BITMAP *bmp); Returns TRUE if bmp is a linear bitmap, i.e. a bitmap that can be accessed linearly within each scanline (for example a memory bitmap, the DOS VGA or SVGA screen, Windows bitmaps, etc). Linear bitmaps can be used with the _putpixel(), _getpixel(), bmp_write_line(), and bmp_read_line() functions. Historically there were only linear and planar bitmaps for Allegro, so is_linear_bitmap() is actually an alias for !is_planar_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! Note that if you are using hardware accelerated VRAM->VRAM blits, you should not call acquire_bitmap(). 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_rect(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 onto. Nothing will be drawn to positions outside this space. This function sets the clipping rectangle for the specified bitmap. Pass the coordinates of the top-left and bottom-right corners of the clipping rectangle in this order; these are both inclusive, i.e. set_clip_rect(bitmap, 16, 16, 32, 32) will allow drawing to (16, 16) and (32, 32), but not to (15, 15) and (33, 33). Drawing operations will be performed (at least partially) on the bitmap as long as the first coordinates of its clipping rectangle are not greater than the second coordinates and its intersection with the actual image is non-empty. If either condition is not fulfilled, drawing will be turned off for the bitmap, e.g. set_clip_rect(bmp, 0, 0, -1, -1); /* disable drawing on bmp */ Note that passing "out-of-bitmap" coordinates is allowed, but they are likely to be altered (and so the coordinates returned by get_clip_rect() will be different). However, such modifications are guaranteed to preserve the external effect of the clipping rectangle, that is not to modify the actual area of the image that it is ok to draw onto. void get_clip_rect(BITMAP *bitmap, int *x1, int *y1, int *x2, int *y2); Returns the clipping rectangle for the specified bitmap. void add_clip_rect(BITMAP *bitmap, int x1, int y1, int x2, int y2); Sets the clipping rectangle of the specified bitmap as the intersection of its current clipping rectangle and the rectangle described by the four coordinates. void set_clip_state(BITMAP *bitmap, int state) Turns on (if state is non-zero) or off (if state is zero) clipping for the specified bitmap. Turning clipping off 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. int get_clip_state(BITMAP *bitmap) Returns non-zero if clipping is turned on for the specified bitmap and zero otherwise. int is_inside_bitmap(BITMAP *bmp, int x, int y, int clip); Returns non-zero if point (x, y) lies inside the bitmap. If `clip' is non-zero, the function compares the coordinates with the clipping rectangle, that is it returns non-zero if the point lies inside the clipping rectangle or if clipping is disabled for the bitmap. If `clip' is zero, the function compares the coordinates with the actual dimensions of the bitmap. ============================================= ============ Loading image files ============ ============================================= 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. The palette data will be stored in the second parameter, which should be an array of 256 RGB structures. 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. Example: BITMAP *bmp; PALETTE palette; ... bmp = load_bitmap("image.pcx", palette); if (!bmp) abort_on_error("Couldn't load image.pcx!"); ... destroy_bitmap(bmp); Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_bmp(const char *filename, RGB *pal); Loads an 8-bit, 16-bit, 24-bit or 32-bit Windows or OS/2 BMP file. Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_bmp_pf(PACKFILE *f, RGB *pal); A version of load_bmp() which reads from a packfile. Example: PACKFILE *packfile; BITMAP *bmp; packfile = pack_fopen("mybitmap.bmp", F_READ); if (!packfile) abort_on_error("Couldn't open mybitmap.bmp"); bmp = load_bmp_pf(packfile, pal); if (!bmp) abort_on_error("Error loading mybitmap.bmp"); Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_lbm(const char *filename, RGB *pal); Loads a 256-color IFF ILBM/PBM file. Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_pcx(const char *filename, RGB *pal); Loads a 256-color or 24-bit truecolor PCX file. Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_pcx_pf(PACKFILE *f, RGB *pal); A version of load_pcx() which reads from a packfile. Example: PACKFILE *packfile; BITMAP *bmp; packfile = pack_fopen("mybitmap.pcx", F_READ); if (!packfile) abort_on_error("Couldn't open mybitmap.pcx"); bmp = load_bmp_pf(packfile, pal); if (!bmp) abort_on_error("Error loading mybitmap.pcx"); Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. 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. Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. BITMAP *load_tga_pf(PACKFILE *f, RGB *pal); A version of load_tga() which reads from a packfile. Example: PACKFILE *packfile; BITMAP *bmp; packfile = pack_fopen("mybitmap.tga", F_READ); if (!packfile) abort_on_error("Couldn't open mybitmap.tga"); bmp = load_bmp_pf(packfile, pal); if (!bmp) abort_on_error("Error loading mybitmap.tga"); Returns a pointer to the bitmap or NULL on error. Remember that you are responsible for destroying the bitmap when you are finished with it to avoid memory leaks. 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. 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); Returns non-zero on error. int save_bmp(const char *filename, BITMAP *bmp, const RGB *pal); Writes a bitmap into a 256-color or 24-bit truecolor BMP file. Returns non-zero on error. int save_bmp_pf(PACKFILE *f, RGB *pal); A version of save_bmp which writes to a packfile. int save_pcx(const char *filename, BITMAP *bmp, const RGB *pal); Writes a bitmap into a 256-color or 24-bit truecolor PCX file. Returns non-zero on error. int save_pcx_pf(PACKFILE *f, RGB *pal); A version of save_pcx which writes to a packfile. 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. Returns non-zero on error. int save_tga_pf(PACKFILE *f, RGB *pal); A version of save_tga which writes to a packfile. 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). The functions you supply must follow the same prototype as load_bitmap() and save_bitmap(). Example: BITMAP *load_dump(const char *filename, RGB *pal) { ... } int save_dump(const char *filename, BITMAP *bmp, const RGB *pal) { ... } register_bitmap_file_type("dump", load_dump, save_dump); 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-bit to 15-bit COLORCONV_8_TO_16 // expand 8-bit to 16-bit COLORCONV_8_TO_24 // expand 8-bit to 24-bit COLORCONV_8_TO_32 // expand 8-bit to 32-bit COLORCONV_15_TO_8 // reduce 15-bit to 8-bit COLORCONV_15_TO_16 // expand 15-bit to 16-bit COLORCONV_15_TO_24 // expand 15-bit to 24-bit COLORCONV_15_TO_32 // expand 15-bit to 32-bit COLORCONV_16_TO_8 // reduce 16-bit to 8-bit COLORCONV_16_TO_15 // reduce 16-bit to 15-bit COLORCONV_16_TO_24 // expand 16-bit to 24-bit COLORCONV_16_TO_32 // expand 16-bit to 32-bit COLORCONV_24_TO_8 // reduce 24-bit to 8-bit COLORCONV_24_TO_15 // reduce 24-bit to 15-bit COLORCONV_24_TO_16 // reduce 24-bit to 16-bit COLORCONV_24_TO_32 // expand 24-bit to 32-bit COLORCONV_32_TO_8 // reduce 32-bit RGB to 8-bit COLORCONV_32_TO_15 // reduce 32-bit RGB to 15-bit COLORCONV_32_TO_16 // reduce 32-bit RGB to 16-bit COLORCONV_32_TO_24 // reduce 32-bit RGB to 24-bit COLORCONV_32A_TO_8 // reduce 32-bit RGBA to 8-bit COLORCONV_32A_TO_15 // reduce 32-bit RGBA to 15-bit COLORCONV_32A_TO_16 // reduce 32-bit RGBA to 16-bit COLORCONV_32A_TO_24 // reduce 32-bit RGBA to 24-bit 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-color to hi/truecolor COLORCONV_REDUCE_TO_256 // reduce hi/truecolor to 256-color COLORCONV_EXPAND_15_TO_16 // expand 15-bit hicolor to 16-bit COLORCONV_REDUCE_16_TO_15 // reduce 16-bit hicolor to 15-bit COLORCONV_EXPAND_HI_TO_TRUE // expand 15/16-bit to 24/32-bit COLORCONV_REDUCE_TRUE_TO_HI // reduce 24/32-bit to 15/16-bit COLORCONV_24_EQUALS_32 // convert between 24- and 32-bit COLORCONV_TOTAL // everything to current format COLORCONV_PARTIAL // convert 15 <-> 16-bit and // 24 <-> 32-bit COLORCONV_MOST // all but hi/truecolor <-> 256 COLORCONV_DITHER // dither during all color reductions COLORCONV_KEEP_ALPHA // convert everything to current format // unless it would lose alpha information 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. int get_color_conversion(); Returns the current color conversion mode. ========================================== ============ Palette routines ============ ========================================== 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; It contains an additional field for the purpose of padding but you should not usually care about it. 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 PAL_SIZE RGB structures, where PAL_SIZE is a preprocessor constant equal to 256. 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 (which can be turned off by defining the ALLEGRO_NO_COMPATIBILITY symbol before including Allegro headers). 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. Example: RGB rgb; ... vsync(); set_color(192, &rgb); 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 (retrace_proc, which is now deprecated). If you really must use _set_color from retrace_proc, note that it should only be used under DOS, in VGA mode 13h and mode-X. Some 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. Example: BITMAP *bmp; PALETTE palette; ... bmp = load_bitmap(filename, palette); if (!bmp) abort_on_error("Couldn't load bitmap!"); set_palette(palette); 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. Example: PALETTE palette; ... /* Modify the first 16 entries. */ change_first_16_colors(palette); /* Now update them waiting for vsync. */ set_palette_range(palette, 0, 15, 1); void get_color(int index, RGB *p); Retrieves the specified palette entry. Example: RGB color; ... get_color(11, &color); 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. Example: PALETTE pal; ... get_palette(pal); 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, int 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, int 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. void fade_in_range(const PALETTE p, int speed, int from, int 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. void fade_out_range(int speed, int from, int 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. 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). Note that this function will block your game while the fade is in effect, and it won't work right visually if you are not in an 8 bit color depth resolution. 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(). If you call select_palette() again, however, the internal buffer will be overwritten. 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 fills the palette parameter with 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[PAL_SIZE]); 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. Returns the number of different colors recognised in the provided bitmap, zero if the bitmap is not a truecolor image or there wasn't enough memory to perform the operation, and negative if there was any internal error in the color reduction code. extern PALETTE default_palette; The default IBM BIOS palette. This will be automatically selected whenever you set a new graphics mode. The palette contains 16 basic colors plus many gradients between them. If you want to see the values, you can write a small Allegro program which saves a screenshot with this palette, or open the grabber tool provided with Allegro and create a new palette object, which will use this palette by default. 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 :-) The contents of this palette are 16 colors repeated 16 times. Color entry zero is equal to color entry 16, which is equal to color entry 24, etc. Index Color RGB values 0 White 63 63 63 1 Red 63 0 0 2 Green 0 63 0 3 Yellow 63 63 0 4 Blue 0 0 63 5 Pink 63 0 63 6 Cyan 0 63 63 7 Grey 16 16 16 8 Light grey 31 31 31 9 Light red 63 31 31 10 Light green 31 63 31 11 Light yellow 63 63 31 12 Light blue 31 31 63 13 Light pink 63 31 63 14 Light cyan 31 63 63 15 Black 0 0 0 ================================================= ============ Truecolor pixel formats ============ ================================================= 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). Example: /* 16 bit color version of green. */ int green_color = makecol16(0, 255, 0); Returns the requested RGB triplet in the specified color depth. 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. Example: /* Regardless of color depth, this will look green. */ int green_color = makecol(0, 255, 0); Returns the requested RGB triplet in the current color depth. 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. Example: /* Compose the green color for 15 bit color depth. */ int green_15bit = makecol_depth(15, 0, 255, 0); Returns the requested RGB triplet in 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. Returns the requested RGBA quadruplet. 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). Example: int pixel1, pixel2; /* The following two color values MAY be different. */ pixel1 = makecol16_dither(255, 192, 64, 0, 0); pixel2 = makecol16_dither(255, 192, 64, 1, 0); Returns the RGB value dithered for the specified coordinate. 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). Example: int r, g, b, color_value; color_value = _getpixel15(screen, 100, 100); r = getr15(color_value); g = getg15(color_value); b = getb15(color_value); 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. Example: int r, g, b, color_value; color_value = getpixel(screen, 100, 100); r = getr(color_value); g = getg(color_value); b = getb(color_value); 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. Example: int r, g, b, color_value, bpp; bpp = bitmap_color_depth(bitmap); color_value = getpixel(bitmap, 100, 100); r = getr_depth(bpp, color_value); g = getg_depth(bpp, color_value); b = getb_depth(bpp, color_value); 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. Example: set_color_depth(32); ... set_palette(desktop_palette); /* Put a pixel with the color 2 (green) of the palette */ putpixel(screen, 100, 100, palette_color[2]); #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 ============ ============================================ Except for _putpixel(), all these routines are affected by the current drawing mode and the clipping rectangle of the destination bitmap. Unless specified otherwise, all coordinates for drawing operations are inclusive, and they, as well as lengths, are specified in pixel units. void clear_bitmap(BITMAP *bitmap); Clears the bitmap to color 0. void clear_to_color(BITMAP *bitmap, int color); Clears the bitmap to the specified color. Example: /* Clear the screen to red. */ clear_to_color(bmp, makecol(255, 0, 0)); 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. Example: putpixel(screen, 10, 30, some_color); 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 (ignoring the clipping rectangle), otherwise the value of the pixel in the color format of the bitmap. Warning: -1 is also a valid value for pixels contained in 32-bit bitmaps with alpha channel (when R,G,B,A are all equal to 255) so you can't use the test against -1 as a predicate for such bitmaps. In this cases, the only reliable predicate is is_inside_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. Returns the value of the pixel in the color format you specified. 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). Note: vline() is implemented as an alias to another function. See ALLEGRO_NO_VHLINE_ALIAS in the `Differences between platforms' section for details. 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). Note: hline() is implemented as an alias to another function. See ALLEGRO_NO_VHLINE_ALIAS in the `Differences between platforms' section for details. 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(). Example: void draw_dust_particle(BITMAP *bmp, int x, int y, int d) { ... } do_line(screen, 0, 0, SCREEN_W-1, SCREEN_H-2, dust_strength, draw_dust_particle); 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 fastline(BITMAP *bmp, int x1, int y1, int x2, int y2, int color); Faster version of the previous function. Note that pixel correctness is not guaranteed for this function. 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). Example: int points[12] = { 50, 50, 100, 100, 100, 150, 50, 200, 0, 150, 0, 100 }; ... clear_to_color(screen, makecol(255, 255, 255)); polygon(screen, 6, points, makecol(0, 0, 0)); 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(). Example: void draw_explosion_ring(BITMAP *bmp, int x, int y, int d) { ... } do_circle(screen, SCREEN_W/2, SCREEN_H/2, SCREEN_H/16, flame_color, draw_explosion_ring); 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(). Example: void draw_explosion_ring(BITMAP *bmp, int x, int y, int d) { ... } do_ellipse(screen, SCREEN_W/2, SCREEN_H/2, SCREEN_H/16, SCREEN_H/32, flame_color, draw_explosion_ring); 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. Example: void draw_explosion_ring(BITMAP *bmp, int x, int y, int d) { ... } arc(screen, SCREEN_W/2, SCREEN_H/2, itofix(-21), itofix(43), 50, flame_color, draw_explosion_ring); 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. Example: /* Draw a black arc from 4 to 1 o'clock. */ arc(screen, SCREEN_W/2, SCREEN_H/2, itofix(-21), itofix(43), 50, makecol(0, 0, 0)); 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. Read the description of calc_spline() for information on how to build 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 ============ ============================================== As far as Allegro is concerned, a bitmap and a sprite are the same thing, but to many people the two words imply slightly different things. The function draw_sprite() is called so rather than draw_bitmap() partly because it indicates that it uses a masked drawing mode (if it existed, you could expect draw_bitmap() to be a simple block copy), and partly for historical reasons. In Allegro 1.0 there were actually different structures for sprites and bitmaps, each with their own set of abilities. Allegro 2.0 merged these into a single more flexible structure, but retained some names like draw_sprite(). In wider (non-Allegro) terms, the two words can mean quite different things. Generally you can say that sprites are a subset of bitmaps, but even that isn't true in 100% of cases. BITMAP: a widely accepted term that will be understood by anyone even remotely connected with computer graphics. It simply means an image built up from a grid of pixels, ie. just about any picture that you are likely to come across on a computer (vector graphics formats are the exception, but those must be rendered into a bitmap format before they can be displayed by most hardware). A more accurate term but slightly rarer term with the same meaning is "pixmap" (pixel-map). SPRITE: a particular usage of bitmapped images, restricted to video games (other types of programmer probably won't be familiar with this term). Originally on machines like the C64, sprites were a hardware feature that allowed a number of small bitmap images to be loaded into special registers, and they could then be superimposed over the main graphics display and moved around just by modifying the position register. They were used for the moving objects (player and enemy characters), and enabled the C64 to do much more impressive things than would have been possible if all the drawing had to be done directly by the puny CPU. Later on, a lot of old C64 programmers upgraded to machines like the Atari ST, which didn't have any special sprite hardware, but they carried on referring to their main moving objects as sprites (the routine to draw such a thing would obviously be called draw_sprite()). A sprite is really just a bitmap graphic which is drawn onto the screen, but when you call it a sprite rather than a bitmap, this suggests it is a gameplay element that can move freely around the world rather than being a static part of the environment, and that it will be drawn in a masked overlay mode rather than as a solid rectangle (there is also a strong implication that a sprite will be animated by cycling through a number of frames, but that isn't always the case). In recent years some people have started using "sprite" to refer to any character graphics, even if they are not in fact drawn as 2d bitmaps, eg. "this game uses 3d polygonal player sprites". This is a confusing misuse of the word (Doom uses sprites, Quake does not), but it does happen. The origin of the term "blit" is also rather interesting. This was originally BitBlt, an abbreviation of BITmap BLock Transfer, which was a function designed (possibly) by the people at Xerox who did so much of the pioneering work on graphics display systems, and subsequently copied by virtually everybody doing computer graphics (the Microsoft Windows GDI still provides a BitBlt function with identical functionality to the original). This routine was a workhorse for all sorts of drawing operations, basically copying bitmap graphics from one place to another, but including a number of different ROP modes (Raster OPerations) for doing things like XOR, inverting pixels, etc. A whole family of related words grew up around the BitBlt function, but "blt" is impossible to speak (try saying "bltter" or "bltting" :-) so people added the vowel to make it easier to pronounce. Thusly, the act of calling the BitBlt function came to be known as "doing a blit". The obvious next step was to rename the function itself to blit(), which generally took place at the same time as people decided to simplify the original, removing the different ROP modes on the grounds that they aren't needed for games coding and don't work well with anything higher than monochrome images in any case. This leaves us with a function called blit(), which is an abbreviation for "block transfer". A strong case could be made for calling this blot() instead, but somehow that just doesn't sound the same! Anyway, all the routines in this chapter are affected by the clipping rectangle of the destination bitmap. 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. Example: BITMAP *bmp; ... /* Blit src on the screen. */ blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h); /* Now copy a chunk to a corner, slightly outside. /* blit(screen, screen, 100, 100, -10, -10, 25, 30); 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. In this case, the behavior is affected by the COLORCONV_KEEP_TRANS and COLORCONV_DITHER* flags of the current color conversion mode: see set_color_conversion() for more information. 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. Example: BITMAP *bmp; ... /* Stretch bmp to fill the screen. */ stretch_blit(bmp, screen, 0, 0, bmp->w, bmp->h, 0, 0, SCREEN_W, SCREEN_H); 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. Example: BITMAP *hud_overlay; ... /* Paint hud overlay on the screen. */ masked_blit(hud_overlay, screen, 0, 0, 0, 0, hud_overlay->w, hud_overlay->h); 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. Example: BITMAP *hud_overlay; ... /* Stretch hud overlay over the screen. */ masked_stretch_blit(hud_overlay, screen, 0, 0, hud_overlay->w, hud_overlay->h, 0, 0, SCREEN_W, SCREEN_H); 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). Example: BITMAP *spaceship; ... draw_sprite(screen, spaceship, x, y); 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. Example: /* Create tunnel like effect. */ for (step = 1; step int width = SCREEN_W / f; int height = SCREEN_H / f; stretch_sprite(screen, image, SCREEN_W / 2 - width / 2, SCREEN_H / 2 - height / 2, width, height); } 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 additionally flip the image vertically, horizontally, or both, respectively. Flipping vertically means that the y-axis is reversed, while flipping horizontally means that the x-axis is reversed, between the source and the destination. 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. Example: if (key[KEY_RIGHT]) draw_sprite(screen, hero_right, pos_x, pos_y); else if (key[KEY_LEFT]) draw_h_sprite(screen, hero_right, pos_x, pos_y); else draw_sprite(screen, hero_idle, pos_x, pos_y); 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. Example: /* Some one time initialisation code. */ COLOR_MAP global_trans_table; create_trans_table(&global_trans_table, my_palette, 128, 128, 128, NULL); ... if (get_color_depth() == 8) color_map = &global_trans_table; else set_trans_blender(128, 128, 128, 128); draw_trans_sprite(buffer, ghost_sprite, x, y); 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. As draw_sprite() this function skips transparent pixels, except if the source sprite is an 8-bit image; if this is the case, you should pay attention to properly set up your color map table for index 0. 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). Example: /* Some one time initialisation code. */ COLOR_MAP global_light_table; create_light_table(&global_trans_table, my_palette, 10, 10, 60, NULL); ... if (get_color_depth() == 8) color_map = &global_light_table; else set_trans_blender(40, 40, 255, 255); /* Lit the cape with a blueish light. */ draw_lit_sprite(buffer, colored_cape, x, y); 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. The corner values passed to this function indicate the strength of the color applied on them, ranging from 0 (no strength) to 255 (full strength). Example: /* Some one time initialisation code. */ COLOR_MAP global_light_table; create_light_table(&global_trans_table, my_palette, 0, 0, 0, NULL); ... if (get_color_depth() == 8) color_map = &global_light_table; else set_trans_blender(0, 0, 0, 128); /* Enemies are in shadow unless lit by torch. */ draw_gouraud_sprite(buffer, menacing_spy, x, y, light_strength_on_corner_1, light_strength_on_corner_2, light_strength_on_corner_3, light_strength_on_corner_4); void draw_character_ex(BITMAP *bmp, BITMAP *sprite, int x, int y, color, bg); Draws a copy of the sprite bitmap onto the destination bitmap at the specified position, drawing transparent pixels in the background color (or skipping them if the background color is -1) 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. Example: BITMAP *logo; ... /* Draw the logo silhouette in red. */ draw_character_ex(screen, logo, SCREEN_W / 2, SCREEN_H / 2, makecol(255, 0, 0), -1); 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. Positive increments of the angle will make the sprite rotate clockwise on the screen, as demonstrated by the Allegro example. void rotate_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle); Like rotate_sprite, but flips the image vertically before rotating it. 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, int cx, int cy, 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 ============ ===================================== 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 (read chapter "Structures and types defined by Allegro" for an internal description of the RLE_SPRITE structure) or COMPILED_SPRITE (see next chapter) 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 than 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). Remember to free this RLE sprite later to avoid memory leaks. Example: RLE_SPRITE *rle; BITMAP *bmp; ... /* Create RLE sprite from an existent bitmap. */ rle = get_rle_sprite(bmp); if (!rle) abort_on_error("Couldn't create RLE sprite!"); /* We don't need the bitmap any more.*/ destroy_bitmap(bmp); /* Use the RLE sprite. */ ... /* Destroy it when we don't need it any more. */ destroy_rle_sprite(rle); Returns a pointer to the created RLE sprite, or NULL if the RLE sprite could not be created. Remember to free this RLE sprite later to avoid memory leaks. void destroy_rle_sprite(RLE_SPRITE *sprite); Destroys an RLE sprite structure previously returned by get_rle_sprite(). If you pass a NULL pointer this function won't do anything. Use this once you are done with an RLE sprite to avoid memory leaks in your program. 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. Example: RLE_SPRITE *rle_sprite; ... draw_rle_sprite(screen, rle_sprite, 100, 100); 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. Example: /* Some one time initialisation code. */ COLOR_MAP global_trans_table; create_trans_table(&global_trans_table, my_palette, 128, 128, 128, NULL); ... if (get_color_depth() == 8) color_map = &global_trans_table; else set_trans_blender(128, 128, 128, 128); draw_trans_rle_sprite(buffer, rle_ghost_sprite, x, y); 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). Example: /* Some one time initialisation code. */ COLOR_MAP global_light_table; create_light_table(&global_trans_table, my_palette, 10, 10, 60, NULL); ... if (get_color_depth() == 8) color_map = &global_light_table; else set_trans_blender(40, 40, 255, 255); /* Lit the cape with a blueish light. */ draw_lit_rle_sprite(buffer, rle_colored_cape, x, y); ========================================== ============ Compiled sprites ============ ========================================== 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 slow machines, up to and including a 486, drawing compiled sprites can be about to five times as fast as using draw_sprite() with a regular bitmap. On newer machines the difference is usually negligible. 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. Example: COMPILED_SPRITE *cspr; BITMAP *bmp; ... /* Create compiled sprite from an existent bitmap. */ cspr = get_compiled_sprite(bmp, 0); if (!cspr) abort_on_error("Couldn't create compiled sprite!"); /* We don't need the bitmap any more.*/ destroy_bitmap(bmp); /* Use the compiled sprite. */ ... /* Destroy it when we don't need it any more. */ destroy_compiled_sprite(cspr); Returns a pointer to the created compiled sprite, or NULL if the compiled sprite could not be created. Remember to free this compiled sprite later to avoid memory leaks. void destroy_compiled_sprite(COMPILED_SPRITE *sprite); Destroys a compiled sprite structure previously returned by get_compiled_sprite(). If you pass a NULL pointer this function won't do anything. Use this once you are done with a compiled sprite to avoid memory leaks in your program. 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... =============================== ============ Fonts ============ =============================== Allegro provides routines for loading fonts directly from GRX format .fnt files, 8x8 or 8x16 BIOS format .fnt files, from bitmap images, from datafiles or you can import a multiple-range Unicode font by writing a .txt script that specifies a number of different source files for each range of characters. By default, Allegro can only use bitmapped (non-scalable) fonts. If you want to use TrueType fonts, you will need to use an add-on library which allows you to load them on the fly (like AllegTTF or Glyph Keeper, listed among others at http://www.allegro.cc/) and render them directly, or generate a bitmapped version of a TrueType font with tools like TTF2PCX (http://www.talula.demon.co.uk/ttf2pcx/index.html). void register_font_file_type(const char *ext, FONT *(*load)(const char *filename, RGB *pal, void *param)); Informs the load_font() functions of a new file type, providing a routine to read fonts in this format. The function you supply must follow the following prototype: FONT *load_my_font(const char *filename, RGB *pal, void *param) { ... } The pal parameter can optionally be used to return a palette for the FONT. The parameter param can be anything you like: you can use this to pass information to your loading routine, such as for instance the font height, the character range to load or the index number of a font in a datafile. If you choose to write your own font loading code, your function should be prepared to deal with a value of NULL for either of these parameters. FONT *load_font(const char *filename, RGB *pal, void *param); Loads a font from a file. At present, this supports loading fonts from a GRX format .fnt file, a 8x8 or 8x16 BIOS format .fnt file, a datafile or any bitmap format that can be loaded by load_bitmap(). If the font contains palette information, then the palette is returned in the second parameter, which should be an array of 256 RGB structures (a PALETTE). The pal argument may be NULL. In this case, the palette data, if present, is simply not returned. The third parameter can be used to pass specific information to a custom loader routine. Normally, you can just leave this as NULL. Note that another way of loading fonts is embedding them into a datafile and using the datafile related functions. Example: FONT *myfont; PALETTE palette; ... myfont = load_font("my_font.pcx", palette, NULL); if (!myfont) abort_on_error("Couldn't load font!"); ... textout_centre_ex(screen, myfont, "This is my own pretty font!", SCREEN_W / 2, SCREEN_H / 2, white, black); ... destroy_font(bmp); Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. void destroy_font(FONT *f); Frees the memory being used by a font structure. Don't use this on the default global Allegro font or any text routines using it could crash. You should use this only on fonts you have loaded manually after you are done with them, to prevent memory leaks in your program. int is_color_font(FONT *f) This function checks if the given font is a color font, as opposed to a monochrome font. Returns TRUE if the font is a color font, FALSE if it is not. int is_mono_font(FONT *f) This function checks if the given font is a mono font, as opposed to a color font. Returns TRUE if the font is a monochrome font, FALSE if it is not. FONT *is_compatible_font(FONT *f1, FONT *f2) This function compares the two fonts, which you can use to find out if Allegro is capable of merging them. Returns TRUE if the two fonts are of the same general type (both are color fonts or both are monochrome fonts, for instance). int get_font_ranges(FONT *f) Use this function to find out the number of character ranges in a font. You should query each of these ranges with get_font_range_begin() and get_font_range_end() to find out what characters are available in the font. Example: FONT *f; int range; int n; ... range = get_font_ranges(f); printf("The font has %d character ranges:\n", range); for (n = 0; n < range; n++) printf("Range %d from 0x%03x - 0x%03x\n", get_font_range_begin(f, n), get_font_range_end(f, n)); Returns the number of continuous character ranges in a font, or -1 if that information is not available. int get_font_range_begin(FONT *f, int range) This function allows you to find out the start of a specific character range for a font. You can pass -1 for the `range' parameter if you want to know the start of the whole font range, or a number from 0 to (but not including) get_font_ranges(f) to get the start of a specific character range in the font. Example: printf("The font has a character range of %d - %d\n", get_font_range_begin(font, -1), get_font_range_end(font, -1)); Returns the first character in the font range, or -1 if that information is not available. int get_font_range_end(FONT *f, int range) This function allows you to find out the index to the last character of a character range for a font. You can pass -1 for the range parameter if you want to know the start of the whole font range, or a number from 0 to (but not including) get_font_ranges(f) to get the start of a specific character range in the font. You should check the start and end of all font ranges to see if a specific character is actually available in the font. Not all characters in the range returned by get_font_range_begin(f, -1) and get_font_range_end(f, -1) need to be available! Example: printf("The font has a character range of %d - %d\n", get_font_range_begin(font, -1), get_font_range_end(font, -1)); Returns the last character in the font range, or -1 if that information is not available. FONT *extract_font_range(FONT *f, int begin, int end) This function extracts a character range from a font and returns a new font that contains only the range of characters selected by this function. You can pass -1 for either the lower or upper bound if you want to select all characters from the start or to the end of the font. Example: FONT *myfont; FONT *capitals; FONT *fontcopy; ... /* Create a font of only capital letters */ capitals = extract_font_range(myfont, 'A', 'Z'); /* Create a copy of the font */ fontcopy = extract_font_range(myfont, -1, -1); ... destroy_font(capitals); destroy_font(fontcopy); Returns a pointer to the new font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. int transpose_font(FONT *f, int drange) This function transposes all characters in a font, effectively remapping the font. Example: FONT *myfont; FONT *capitals; ... /* Create a font of only capital letters */ capitals = extract_font_range(myfont, 'A', 'Z'); /* Now transpose the characters in the font so that they will be used */ /* for the lower case letters a-z */ transpose_font(capitals, 'a'-'A'); textout_ex(screen, capitals, "allcaps", 100, 100, makecol(255,255,255), 0); Returns 0 on success, -1 on failure. FONT *merge_fonts(FONT *f1, FONT *f2) This function merges the character ranges from two fonts and returns a new font containing all characters in the old fonts. In general, you cannot merge fonts of different types (eg, TrueType fonts and bitmapped fonts), but as a special case, this function can promote a monochrome bitmapped font to a color font and merge those. Example: FONT *myfont; FONT *myfancy_font; FONT *lower_range; FONT *upper_range; FONT *capitals; FONT *combined_font; FONT *tempfont; ... /* Create a font that contains the capatials from */ /* the fancy font but other characters from myfont */ lower_range = extract_font_range(myfont, -1, 'A'-1); upper_range = extract_font_range(myfont, 'Z'+1, -1); capitals = extract_font_range(myfancy_font, 'A', 'Z'); tempfont = merge_fonts(lower_range, capitals); combined_font = merge_fonts(tempfont, upper_range); /* Clean up temporary fonts */ destroy_font(lower_range); destroy_font(upper_range); destroy_font(capitals); destroy_font(combined_font); Returns a pointer to the new font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_dat_font(const char *filename, RGB *pal, void *param) Loads a FONT from an Allegro datafile. You can set param parameter to point to an array that holds two strings that identify the font and the palette in the datafile by name. The first string in this list is the name of the font. You can pass NULL here to just load the first font found in the datafile. The second string can be used to specify the name of the palette associated with the font. This is only returned if the pal parameter is not NULL. If you pass NULL for the name of the palette, the last palette found before the font was found is returned. You can also pass NULL for param, which is treated as if you had passed NULL for both strings separately. In this case, the function will simply load the first font it finds from the datafile and the palette that precedes it. For example, suppose you have a datafile named `fonts.dat' with the following contents: FONT FONT_1_DATA FONT FONT_2_DATA FONT FONT_3_DATA PAL FONT_1_PALETTE PAL FONT_2_PALETTE Then the following code will load FONT_1_DATA as a FONT and return FONT_1_PALETTE as the palette: FONT *f; PALETTE pal; char *names[] = { "FONT_1_DATA", "FONT_1_PALETTE" } f = load_dat_font("fonts.dat", pal, names); If instead you want to load the second font, FONT_2, from the datafile, you would use: FONT *f; PALETTE pal; char *names[] = { "FONT_2_DATA", "FONT_2_PALETTE" } f = load_dat_font("fonts.dat", pal, names); If you want to load the third font, but not bother with a palette, use: FONT *f; char *names[] = { "FONT_3_DATA", NULL } f = load_dat_font("fonts.dat", NULL, names); Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_bios_font(const char *filename, RGB *pal, void *param) Loads a 8x8 or 8x16 BIOS format font. You shouldn't normally call this routine directly. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_grx_font(const char *filename, RGB *pal, void *param) Loads a GRX format font. You shouldn't normally call this routine directly. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_grx_or_bios_font(const char *filename, RGB *pal, void *param) Loads either a BIOS or GRX format font. You shouldn't normally call this routine directly. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_bitmap_font(const char *filename, RGB *pal, void *param) Tries to grab a font from a bitmap. The bitmap can be in any format that load_bitmap understands. The size of each character is determined by the layout of the image, which should be a rectangular grid containing all the ASCII characters from space (32) up to the tilde (126). The way the characters are separated depends on the colordepth of the image file: paletted (8 bit) image file Use color 0 for the transparent portions of the characters and fill the spaces between each letter with color 255. High (15/16 bit) and true (24/32 bit) color image file Use bright pink (maximum red and blue, zero green) for the transparent portions of the characters and fill the spaces between each letter with bright yellow (maximum red and green, zero blue). Note that in each horizontal row the bounding boxes around the characters should align and have the same height. Probably the easiest way to get to grips with how this works is to load up the `demo.dat' file and export the TITLE_FONT into a PCX file. Have a look at the resulting picture in your paint program: that is the format a font should be in. Take care with high and true color fonts: Allegro will convert these to the current colordepth when you load the font. If you try to use a font on a bitmap with a different color depth Allegro will do color conversions on the fly, which will be rather slow. For optimal performance you should set the colordepth to the colordepth you want to use before loading any fonts. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *grab_font_from_bitmap(BITMAP *bmp) This function is the work-horse of load_bitmap_font, and can be used to grab a font from a bitmap in memory. You can use this if you want to generate or modify a font at runtime. The bitmap should follow the layout described for load_bitmap_font. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. FONT *load_txt_font(const char *filename, RGB *pal, void *param) This function can be used to load scripted fonts. The script file contains a number of lines in the format "filename start end", which specify the source file for that range of characters, the Unicode value of the first character in the range, and the end character in the range (optional, if left out, the entire input file will be grabbed). If the filename is replaced by a hyphen, more characters will be grabbed from the previous input file. For example, the script: ascii.fnt 0x20 0x7F - 0xA0 0xFF dingbats.fnt 0x1000 would import the first 96 characters from ascii.fnt as the range 0x20-0x7F, the next 96 characters from ascii.fnt as the range 0xA0-0xFF, and the entire contents of dingbats.fnt starting at Unicode position 0x1000. Returns a pointer to the font or NULL on error. Remember that you are responsible for destroying the font when you are finished with it to avoid memory leaks. ===================================== ============ Text output ============ ===================================== 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, `^', but you can change this global to use any other character instead. Example: /* Show unknown glyphs with an asterisk. */ allegro_404_char = '*'; int text_length(const FONT *f, const char *str); Returns the length (in pixels) of a string in the specified font. Example: int width = text_length(font, "I love spam"); ... bmp = create_bitmap(width, height); int text_height(const FONT *f) Returns the height (in pixels) of the specified font. Example: int height = text_height(font); ... bmp = create_bitmap(width, height); void textout_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); Writes the string `s' onto the bitmap at position x, y, using the specified font, foreground color and background color. If the background color is -1, then the text is written transparently. If the foreground 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. For high and true color fonts, the foreground color is ignored and always treated as -1. Example: /* Show the program's version in blue letters. */ textout_ex(screen, font, "v4.2.0-beta2", 10, 10, makecol(0, 0, 255), -1); void textout_centre_ex(BITMAP *bmp, const FONT *f, const char *s, int x, y, int color, int bg); Like textout_ex(), but interprets the x coordinate as the centre rather than the left edge of the string. Example: /* Important texts go in the middle. */ width = text_length("GAME OVER"); textout_centre_ex(screen, font, "GAME OVER", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 0, 0), makecol(0, 0, 0)); void textout_right_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); Like textout_ex(), but interprets the x coordinate as the right rather than the left edge of the string. Example: textout_right_ex(screen, font, "Look at this color!", SCREEN_W - 10, 10, my_yellow, -1); void textout_justify_ex(BITMAP *bmp, const FONT *f, const char *s, int x1, int x2, int y, int diff, int color, int bg); 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. Example: char *lines[] = {"Draws justified text", "within the specified", "x2-x1 area. But not", "T H I S !", NULL}; /* Show the justification marker. */ vline(screen, 200, 0, SCREEN_H-1, makecol(0, 0, 0)); /* Draw all the lines until we reach a NULL entry. */ for (num = 0, y = 0; lines[num]; num++, y += text_height(font)) textout_justify_ex(screen, font, lines[num], 0, 200, y, 80, makecol(0, 0, 0), makecol(255, 255, 255)); void textprintf_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...); Formatted text output, using a printf() style format string. Due to an internal limitation, this function can't be used for extremely long texts. If you happen to reach this limit, you can work around it by using uszprintf() and textout_ex(), which don't have any. Example: int player_score; ... textprintf_ex(screen, font, 10, 10, makecol(255, 100, 200), -1, "Score: %d", player_score); void textprintf_centre_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...); Like textprintf_ex(), but interprets the x coordinate as the centre rather than the left edge of the string. This function shares the text length limitation of textprintf_ex(). Example: textprintf_centre_ex(screen, font, SCREEN_W / 2, 120, makecol(0, 100, 243), -1, "Your best score so far was %d!", total_max_points); void textprintf_right_ex(BITMAP *bmp, const FONT *f, int x, y, color, bg, const char *fmt, ...); Like textprintf_ex(), but interprets the x coordinate as the right rather than the left edge of the string. This function shares the text length limitation of textprintf_ex(). Example: textprintf_right_ex(screen, font, SCREEN_W - 10, 10, makecol(200, 200, 20), -1, "%d bullets left", player_ammo); void textprintf_justify_ex(BITMAP *bmp, const FONT *f, int x1, x2, y, diff, color, bg, const char *fmt, ...); Like textout_justify_ex(), but using a printf() style format string. This function shares the text length limitation of textprintf_ex(). Example: char *lines[] = {"Line %02d: Draws justified text", "Line %02d: within the specified", "Line %02d: x2-x1 area. But not", "Line %02d: T H I S !", NULL}; /* Show the justification marker. */ vline(screen, 300, 0, SCREEN_H-1, makecol(0, 0, 0)); /* Draw all the lines until we reach a NULL entry. */ for (num = 0, y = 0; lines[num]; num++, y += text_height(font)) textprintf_justify_ex(screen, font, 0, 300, y, 180, makecol(0, 0, 0), makecol(255, 255, 255), lines[num], num); =========================================== ============ Polygon rendering ============ =========================================== All the 3d functions that accept a `type' parameter are asking for a polygon rendering mode, which can be any of the following POLYTYPE_* values. 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. #define 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. #define 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. #define 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). #define 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 this means, run Allegro's test program and see what happens to the polygon3d() test when you zoom in very close to the cube. #define 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). #define POLYTYPE_ATEX_MASK #define 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. #define POLYTYPE_ATEX_LIT #define 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! #define POLYTYPE_ATEX_MASK_LIT #define 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. #define POLYTYPE_ATEX_TRANS #define 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). #define POLYTYPE_ATEX_MASK_TRANS #define POLYTYPE_PTEX_MASK_TRANS Like POLYTYPE_ATEX_TRANS and POLYTYPE_PTEX_TRANS, but zero texture map pixels are skipped. 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. Read the beginning of chapter "Polygon rendering" for a list of rendering types you can use with this function. 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[]). Read the beginning of chapter "Polygon rendering" for a list of rendering types you can use with this function. 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[]). Read the beginning of chapter "Polygon rendering" for a list of rendering types you can use with this function. 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