This list is for any kind of discussion about Allegro, questions about Allegro, reports of problems with Allegro, suggestions for new features, announcements of programs written using Allegro, etc. General rule: if it has to do with Allegro, you can post it here. If not, go somewhere else (for example comp.os.msdos.djgpp, comp.lang.c, or the online forums at http://www.allegro.cc/).
This list is for the people currently working on Allegro, who use it to coordinate their efforts. You can use this address if you need to contact the developers directly, for example to submit some new code that you have written or to report a bug.
Unlike the other lists, we will be really rude to people who post inappropriate material here, so please don't do that! Do not send tech-support questions to this list. Don't post bug reports here unless you are 100% certain they aren't your fault (if you are in any doubt, use the main Allegro list instead, which is read by most of the same people who are subscribed here).
The Allegro development is a completely open process, and everyone is welcome to drop by, have a listen, and start contributing code patches. This list is for working rather than talking, though, so please don't do anything that might get in our way.
This list was once available for discussing the next major version of Allegro, when it was too noisy to do so on [AD]. This is no longer the case so the list has been shut down. However, its archives are still valuable.
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()). ]]>
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. ]]>
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)
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
p36 = 0 34 9 12specifies 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.
/* 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);]]>
int pos, x, y; pos = mouse_pos; x = pos >> 16; y = pos & 0x0000ffff;]]>
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. ]]>
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_COMMANDFinally, 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. ]]>
if (key[KEY_W]) { if (key_shifts & KB_SHIFT_FLAG) { /* User is pressing shift + W. */ } else { /* Hmmm... lower case W then. */ } }]]>
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
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. ]]>
/* 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(). ]]>
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 informationIf 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. ]]>
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). ]]>
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);]]>
clear_scene(buffer); if (some_polys_are_zbuf) clear_zbuffer(0.); while (polygons) { ... if (this_poly_is_zbuf) type |= POLYTYPE_ZBUF; scene_polygon3d(type, tex, vc, vtx); } render_scene();]]>
void memory_putpixel_15_or_16_bpp(BITMAP *bmp, int x, int y, int color) { ((short *)bmp->line[y])[x] = color; } void memory_putpixel_32(BITMAP *bmp, int x, int y, int color) { ((long *)bmp->line[y])[x] = color; }If you want to write to the screen as well as to memory bitmaps, you need to use some helper macros, because the video memory may not be part of your normal address space. This simple routine will work for any linear screen, eg. a VESA linear framebuffers:
void linear_screen_putpixel(BITMAP *bmp, int x, int y, int color) { bmp_select(bmp); bmp_write8((unsigned long)bmp->line[y]+x, color); }For truecolor modes you should replace the bmp_write8() with bmp_write16(), bmp_write24(), or bmp_write32(), and multiply the x offset by the number of bytes per pixel. There are of course similar functions to read a pixel value from a bitmap, namely bmp_read8(), bmp_read16(), bmp_read24() and bmp_read32(). This still won't work in banked SVGA modes, however, or on platforms like Windows that do special processing inside the bank switching functions. For more flexible access to bitmap memory, you need to call the following routines. They are implemented as inline assembler routines, so they are not as inefficient as they might seem. If the bitmap doesn't require bank switching (ie. it is a memory bitmap, mode 13h screen, etc), these functions just return bmp->line[line]. ]]>
void modex_putpixel(BITMAP *b, int x, int y, int color) { outportw(0x3C4, (0x100<<(x&3))|2); bmp_select(bmp); bmp_write8((unsigned long)bmp->line[y]+(x>>2), color); }Oh yeah: the DJGPP nearptr hack. Personally I don't like this very much because it disables memory protection and isn't portable to other platforms, but a lot of people swear by it because it can give you direct access to the screen memory via a normal C pointer. Warning: this method will only work with the DJGPP library, when using VGA 13h or a linear framebuffer modes! In your setup code:
#include <sys/nearptr.h> unsigned char *screenmemory; unsigned long screen_base_addr; __djgpp_nearptr_enable(); __dpmi_get_segment_base_address(screen->seg, &screen_base_addr); screenmemory = (unsigned char *)(screen_base_addr + screen->line[0] - __djgpp_base_address);Then:
void nearptr_putpixel(int x, int y, int color) { screenmemory[x + y*VIRTUAL_W] = color; }]]>
/* Create a 22KHz 8bit mono audio stream. */ stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128); if (!stream) abort_on_error("Error creating audio stream!\n");]]>
cap = get_sound_input_cap_bits(); if (cap == 0) { /* Ugh, no audio input supported? */ } else { if (cap & 8) { /* We have eight bit audio input. */ } if (cap & 16) { /* We have sixteen bit audio input. */ } }]]>
struct al_ffblk info; if (al_findfirst("*.pcx", &info, FA_ALL) != 0) { /* Tell user there are no PCX files. */ return; }]]>
PACKFILE *input_file; input_file = pack_fopen("scores.dat", "rp"); if (!input_file) abort_on_error("Couldn't read `scores.dat'!");]]>
PACKFILE *input = pack_fopen("out.raw", "rp"); ... input = pack_fopen_chunk(input, 1); /* Read data from the sub-chunk and close it. */ ... input = pack_fclose_chunk(input);This sequence will read the length counts created when the chunk was written, and automatically decompress the contents of the chunk if it was compressed. The length will also be used to prevent reading past the end of the chunk (Allegro will return EOF if you attempt this), and to automatically skip past any unread chunk data when you call pack_fclose_chunk(). Chunks can be nested inside each other by making repeated calls to pack_fopen_chunk(). When writing a file, the compression status is inherited from the parent file, so you only need to set the pack flag if the parent is not compressed but you want to pack the chunk data. If the parent file is already open in packed mode, setting the pack flag will result in data being compressed twice: once as it is written to the chunk, and again as the chunk passes it on to the parent file. ]]>
DATAFILE *load_datafile(char *filename);This will load the entire file, returning a pointer to it, or NULL on error. When the data is no longer required, the entire thing can be destroyed by calling:
void unload_datafile(DATAFILE *dat);When you load a datafile, you will obtain a pointer to an array of DATAFILE structures:
typedef struct DATAFILE { void *dat; - pointer to the actual data int type; - object type ID long size; - size of the data, in bytes DATAFILE_PROPERTY *prop; - list of object properties } DATAFILE;The only really important piece of information here is the `dat' field, which points to the contents of the object. What type of data this is will depend on the type of object: for bitmaps it will be an Allegro BITMAP structure, for RLE sprites an RLE_SPRITE, for fonts a FONT structure, etc. If you are programming in C you can pass this pointer directly to the relevant Allegro library functions, but if you are using C++ you will need to cast it to the appropriate type to prevent the compiler giving a warning. For example, if you have a datafile called `myfile.dat', which contains a bitmap called COOL_PICTURE, and you have used it to produce a header called `myfile.h', you could display the bitmap with the code:
#include "myfile.h" void show_the_bitmap() { DATAFILE *dat; BITMAP *bmp; dat = load_datafile("myfile.dat"); if (!dat) { /* report an error! */ return; } bmp = (BITMAP *)dat[COOL_PICTURE].dat; blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h); unload_datafile(dat); }If a datafile contains nested child datafiles, the header will prefix the names of objects in the sub-files with the name of their parent datafile. It will also define a count of the number of objects in the child file, which may be useful if for example the child datafile contains several bitmaps which form a 'run' animation, and you want your code to automatically adjust to the number of frames in the datafile. For example, the following datafile:
"FILE" - NESTED_FILE |- "BMP" - A_BITMAP |- "FONT" - A_FONT "DATA" - SOME_DATA "DATA" - SOME_MORE_DATAWill produce the header:
#define NESTED_FILE 0 /* FILE */ #define NESTED_FILE_A_BITMAP 0 /* BMP */ #define NESTED_FILE_A_FONT 1 /* FONT */ #define NESTED_FILE_COUNT 2 #define SOME_DATA 1 /* DATA */ #define SOME_MORE_DATA 2 /* DATA */The main datafile contains three objects (NESTED_FILE, SOME_DATA, and SOME_MORE_DATA) with consecutive indexes, while the child datafile contains the two objects A_BITMAP and A_FONT. To access these objects you need to reference both the parent and child datafiles, eg:
DATAFILE *dat = load_datafile("whatever.dat"); DATAFILE *nested = (DATAFILE *)dat[NESTED_FILE].dat; FONT *thefont = (FONT *)nested[NESTED_FILE_A_FONT].dat;If you need to access object property strings from within your program, you can use the function:
char *get_datafile_property(DATAFILE *dat, int type);This will return a pointer to the property string if it can be found, and an empty string (not null!) if it does not exist. One possible use of this function is to locate objects by name, rather than using the indexes from a header file. The datafile array is ended by an object of type DAT_END, so to search the datafile dat for the object "my_object" you could use the code:
const int name_type = DAT_ID('N','A','M','E'); for (i=0; dat[i].type != DAT_END; i++) { if (stricmp(get_datafile_property(dat+i, name_type), "my_object") == 0) { /* found the object at index i */ } } /* not found... */If you prefer to access objects by name rather than index number, you can use the function:
DATAFILE *find_datafile_object(DATAFILE *dat, char *objectname);This will search an already loaded datafile for an object with the specified name, returning a pointer to it, or NULL if the object cannot be found. It understands '/' and '#' separators for nested datafile paths. It is also possible to selectively load individual objects from a datafile, with the function:
DATAFILE *load_datafile_object(char *filename, char *objectname);This searches the datafile for an object with the specified name, so obviously it won't work if you strip the name properties out of the file. Because this function needs to seek through the data, it will be extremely slow if you have saved the file with global compression. If you are planning to load objects individually, you should save the file uncompressed or with individual compression per-object. Because the returned datafile points to a single object rather than an array of objects, you should access it with the syntax datafile->dat, rather than datafile[index].dat, and when you are done you should free the object with the function:
void unload_datafile_object(DATAFILE *dat);Example:
music_object = load_datafile_object("datafile.dat", "MUSIC"); play_midi(music_object->dat); ... unload_datafile_object(music_object);Alternatively, the packfile functions can open and read directly from the contents of a datafile object. You do this by calling pack_fopen() with a fake filename in the form "filename.dat#object_name". The contents of the object can then be read in an identical way to a normal disk file, so any of the file access functions in Allegro (eg. load_pcx() and set_config_file()) can be used to read from datafile objects. Note that you can't write to datafiles in this way: the fake file is read only. Also, you should save the file uncompressed or with per-object compression if you are planning on using this feature. Finally, be aware that the special Allegro object types aren't the same format as the files you import the data from, so if for example you want to use load_pcx to read an image from a datafile, you should import it as a binary data chunk rather than as a BITMAP object. If you have appended a datafile to the end of your executable with the exedat utility, use load_datafile("#") to read the entire thing into memory, load_datafile_object("#", "object_name") to load a specific object, and pack_fopen("#object_name", F_READ) to read one of the objects directly with your own code. Note that unless you use the previous functions to load the appended data, the OS will not load it into memory just because you are running the program, so you shouldn't have problems attaching datafiles to your binary larger than the available system memory. By default, all graphic objects loaded from a datafile will be converted into the current color depth. This conversion may be both lossy and very slow, particularly when reducing from truecolor to 256 color formats, so you may wish to disable it by calling set_color_conversion(COLORCONV_NONE) or set_color_conversion(COLORCONV_PARTIAL) before your call to load_datafile(). ]]>
void *load_mapdata(PACKFILE *f, long size) { /* Allegro will call this function whenever an object of your custom * type needs to be loaded from a datafile. It will be passed a * pointer to the file from which the data is to be read, and the size * of the object in bytes. It should return a pointer to the loaded * data, which will be stored in the dat field of the datafile object * structure, or NULL if an error occurs. The file will have been * opened as a sub-chunk of the main datafile, so it is safe to read * past the end of the object (if you attempt this, Allegro will * return EOF), and it is also safe to return before reading all the * data in the chunk (if you do this, Allegro will skip any unused * bytes before starting to read the next object). You should _not_ * close the file when you are done: this will be handled by the * calling function. To clarify how all this works, here's an example * implementation of a null-terminated string object: */ #define MAX_LEN 256 char buf[MAX_LEN]; char *p; int i, c; for (i=0; i<;MAX_LEN-1; i++) { if ((c = pack_getc(f)) == EOF) break; buf[i] = c; } buf[i] = 0; p = malloc(i+1); strcpy(p, buf); return p; } void destroy_mapdata(void *data) { /* Allegro will call this function whenever an object of your custom * type needs to be destroyed. It will be passed a pointer to the * object (as returned by the load function), and should free whatever * memory the object is using. For example, the simple string object * returned by the above loader could be destroyed with the code: */ if (data) free(data); }Finally, before you load your datafile you must tell Allegro about the custom format, by calling:
register_datafile_object(DAT_MAPDATA, load_mapdata, destroy_mapdata);It is also possible to integrate support for custom object types directly into the grabber and dat utilities, by copying some special files into the tools/plugins directory. This can be used to add whole new object types and menu commands, or to provide additional import/export routines for the existing formats. See `tools/plugins/plugins.txt' for an overview of how to write your own grabber plugins. ]]>
( a, b, c, d ) ( e, f, g, h ) ( i, j, k, l ) ( m, n, o, p )a pattern can be observed in which parts of it do what. The top left 3x3 grid implements rotation and scaling. The three values in the top right column (d, h, and l) implement translation, and as long as the matrix is only used for affine transformations, m, n and o will always be zero and p will always be 1. If you don't know what affine means, read Foley & Van Damme: basically it covers scaling, translation, and rotation, but not projection. Since Allegro uses a separate function for projection, the matrix functions only need to support affine transformations, which means that there is no need to store the bottom row of the matrix. Allegro implicitly assumes that it contains (0,0,0,1), and optimises the matrix manipulation functions accordingly. Read chapter "Structures and types defined by Allegro" for an internal view of the MATRIX/_f structures. ]]>
int foo(int msg, DIALOG *d, int c);It will be passed a flag (msg) indicating what action it should perform, a pointer to the object concerned (d), and if msg is MSG_CHAR or MSG_XCHAR, the key that was pressed (c). Note that d is a pointer to a specific object, and not to the entire dialog. The dialog procedure should return one of the values:
D_O_K - normal return status D_CLOSE - tells the dialog manager to close the dialog D_REDRAW - tells the dialog manager to redraw the entire dialog D_REDRAWME - tells the dialog manager to redraw the current object D_WANTFOCUS - requests that the input focus be given to this object D_USED_CHAR - MSG_CHAR and MSG_XCHAR return this if they used the keyDialog procedures may be called with any of the messages: MSG_START:
d_box_proc, d_shadow_box_proc, d_button_proc, d_check_proc, d_radio_proc, d_list_proc, d_text_list_proc and d_textbox_proc.When you want to convert old dialogs to look equally when compiling with the new Allegro version, just increase the size of the mentioned objects by one pixel in both width and height fields.
if (desktop_color_depth() == 16) { set_color_depth(16); if (set_gfx_mode(GFX_DIRECTX_WIN, 640, 480, 0, 0) != 0) { set_color_depth(15); if (set_gfx_mode(GFX_DIRECTX_WIN, 640, 480, 0, 0) != 0) { /* 640x480 direct drawing mode not supported */ goto Error; } } /* ok, we are in direct drawing mode */ }Note that, mainly for performance reasons, this driver requires the width of the screen to be a multiple of 4. This driver is capable of displaying a hardware cursor, but there are size restrictions. Typically, the cursor image cannot be more than 32x32 pixels.
if (desktop_color_depth() == 16) { set_color_depth(16); if (set_gfx_mode(GFX_DIRECTX_OVL, 640, 480, 0, 0) != 0) { set_color_depth(15); if (set_gfx_mode(GFX_DIRECTX_OVL, 640, 480, 0, 0) != 0) { /* 640x480 overlay driver not supported */ goto Error; } } /* ok, the 640x480 overlay driver is running */ }
./language.dat $ALLEGRO/language.dat ~/language.dat /etc/language.dat /usr/share/allegro/language.dat /usr/local/share/allegro/language.datNote that if you have installed Allegro from the source distribution with the typical `make install', global files like `language.dat' and `allegro.cfg' will not have been installed. As a system administrator you are required to install them manually wherever you prefer to have them. If you suspect that an Allegro program is somehow not finding the correct configuration file, you could try using the following command:
strace program 2>&1|egrep "(open|stat)"The strace program traces system calls and signals. By default it outputs the information to stderr, so that's why we redirect it to stdin with `2>&1'. Since we are interested only in files being (un)successfully opened, we restrict the output of the log to stat or open calls with the extended grep command. You could add another grep to filter only lines with text like `language' or `allegro'. ]]>
BEGIN_GFX_DRIVER_LIST driver1 driver2 etc... END_GFX_DRIVER_LISTwhere the driver names are any of the defines:
GFX_DRIVER_VBEAF GFX_DRIVER_VGA GFX_DRIVER_MODEX GFX_DRIVER_VESA3 GFX_DRIVER_VESA2L GFX_DRIVER_VESA2B GFX_DRIVER_XTENDED GFX_DRIVER_VESA1This construct must be included in only one of your C source files. The ordering of the names is important, because the autodetection routine works down from the top of the list until it finds the first driver that is able to support the requested mode. I suggest you stick to the default ordering given above, and simply delete whatever entries you aren't going to use.
BEGIN_COLOR_DEPTH_LIST depth1 depth2 etc... END_COLOR_DEPTH_LISTwhere the color depth names are any of the defines:
COLOR_DEPTH_8 COLOR_DEPTH_15 COLOR_DEPTH_16 COLOR_DEPTH_24 COLOR_DEPTH_32Removing any of the color depths will save quite a bit of space, with the exception of the 15 and 16-bit modes: these share a great deal of code, so if you are including one of them, there is no reason not to use both. Be warned that if you try to use a color depth which isn't in this list, your program will crash horribly!
BEGIN_DIGI_DRIVER_LIST driver1 driver2 etc... END_DIGI_DRIVER_LISTusing the digital sound driver defines:
DIGI_DRIVER_SOUNDSCAPE DIGI_DRIVER_AUDIODRIVE DIGI_DRIVER_WINSOUNDSYS DIGI_DRIVER_SBand for the MIDI music:
BEGIN_MIDI_DRIVER_LIST driver1 driver2 etc... END_MIDI_DRIVER_LISTusing the MIDI driver defines:
MIDI_DRIVER_AWE32 MIDI_DRIVER_DIGMID MIDI_DRIVER_ADLIB MIDI_DRIVER_MPU MIDI_DRIVER_SB_OUTIf you are going to use either of these sound driver constructs, you must include both.
BEGIN_JOYSTICK_DRIVER_LIST driver1 driver2 etc... END_JOYSTICK_DRIVER_LISTusing the joystick driver defines:
JOYSTICK_DRIVER_WINGWARRIOR JOYSTICK_DRIVER_SIDEWINDER JOYSTICK_DRIVER_GAMEPAD_PRO JOYSTICK_DRIVER_GRIP JOYSTICK_DRIVER_STANDARD JOYSTICK_DRIVER_SNESPAD JOYSTICK_DRIVER_PSXPAD JOYSTICK_DRIVER_N64PAD JOYSTICK_DRIVER_DB9 JOYSTICK_DRIVER_TURBOGRAFX JOYSTICK_DRIVER_IFSEGA_ISA JOYSTICK_DRIVER_IFSEGA_PCI JOYSTICK_DRIVER_IFSEGA_PCI_FASTThe standard driver includes support for the dual joysticks, increased numbers of buttons, Flightstick Pro, and Wingman Extreme, because these are all quite minor variations on the basic code.
#define ALLEGRO_COLOR8 #define ALLEGRO_COLOR16 #define ALLEGRO_COLOR24 #define ALLEGRO_COLOR32If you comment out any of these definitions and then rebuild the library, you will get a version without any support for the absent color depths, which will be even smaller than using the DECLARE_COLOR_DEPTH_LIST() macro. Removing the ALLEGRO_COLOR16 define will get rid of the support for both 15 and 16-bit hicolor modes, since these share a lot of the same code. Note: the aforementioned methods for removing unused hardware drivers only apply to statically linked versions of the library, eg. DOS. On Windows and Unix platforms, you can build Allegro as a DLL or shared library, which prevents these methods from working, but saves so much space that you probably won't care about that. Removing unused color depths from alconfig.h will work on any platform, though. If you are distributing a copy of the setup program along with your game, you may be able to get a dramatic size reduction by merging the setup code into your main program, so that only one copy of the Allegro routines will need to be linked. See setup.txt for details. In the DJGPP version, after compressing the executable, this will probably save you about 200k compared to having two separate programs for the setup and the game itself. ]]>
redir -eo make > logfile.txt]]>
main()
function.
Allegro uses this, along with some preprocessor magic, to turn a normal
main()
function into a Windows-style WinMain()
entry point.
]]>g++ -D__GTHREAD_HIDE_WIN32API program.cpp -lalleg]]>
main()
function.
Allegro uses this, along with some preprocessor magic, to get a copy
of your argv[]
parameters (it needs those for various internal things).
]]>ALLEGRO_USE_CONSOLE
. Also note that the magic
main can't be disabled on such a system: you simply can't define the
symbol ALLEGRO_NO_MAGIC_MAIN
in a program linked against Allegro.
]]>make
and
that will build everything for you.
]]>If you do have the patch program but it isn't working properly, make sure that you are installing the patch over the top of an unmodified copy of whatever Allegro version it is intended to update (this will usually be the most recent official release from before the WIP was made, but check the text file that comes with the WIP to be sure). ]]>
Also, have a look at http://www.allegro.cc/ for add-on packages (notably FBlend v0.5) that attempt to make this operation as fast as possible. ]]>
fade_out()
only work in 8-bit paletted modes.
See the previous question for details.
]]>rotate_sprite(bmp, spr, x, y, itofix(32))
will rotate the graphic by 45 degrees.
]]>dp
field as part of your program init
code, after you've loaded the bitmap into memory.
]]>draw_sprite()
function, depending on your CPU
and your bitmaps.
Compiled sprites are in general quite a bit faster than both the
others for masked images, and slightly faster for opaque graphics, but
this is far more variable. They are at their best with small sprites,
on older machines and in mode-X, and may actually be slower than
blit()
when using SVGA modes on a pentium (the large size of a
compiled sprite is very bad for the cache performance).
]]>save_bitmap()
documentation for a discussion of one common pitfall
when doing this, and some example code.
]]>rand()%limit
to obtain a pseudo-random number between 0
and limit-1
.
]]>allegro.txi
file from the
allegro/docs
dir, and run the commands makertf --no-warn allegro.txi
-o allegro.rtf -J allegro.hpj followed by hcp allegro.hpj. The
second command will give a lot of warnings, but they can safely be
ignored.
]]>readkey()
instead.
Or consider upgrading or downgrading your compiler.
]]>#include <iostream> #include <allegro.h> using namespace std;]]>
destroy_bitmap()
. The proper way to
destroy `screen' is calling set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)
.
]]>Call frame traceback EIPs: 0x00001eca _strcpy+14 0x00001590 _main+56, line 7 of t.c 0x00001aea ___crt1_startup+138In this case, you can see that the crash occurred in the strcpy() function, which was called at line 7 of the main() function in the t.c source file. Now you just have to go to that line, have a look at whatever you are doing there, and change it to be correct :-) Note: if the crash happens deep inside an Allegro function, this traceback may not be so useful. When this happens you can recompile Allegro with debugging information (see the readme file), and then link your program with the debugging library version. Note 2: even when this crash traceback points to one of the Allegro functions, that does not necessarily mean the Allegro routine is at fault. Anything will crash if you pass it invalid parameters, so unless you can duplicate the problem in one of the Allegro example programs, you should start out by assuming that it is a case of operator error and double-check exactly what you are passing to the Allegro function. ]]>
(gdb) backtrace #0 0x08065237 in utf8_getx (s=0xbffffc5c) at ./src/unicode.c:347 #1 0x0806953f in ustrzcpy (dest=0x0, size=2147483646, src=0x0) at ./src/unicode.c:1770 #2 0x08057575 in _mangled_main () at t.c:9 #3 0x0806c9bf in main (argc=1, argv=0xbffffd14) at ./src/unix/umain.c:39 #4 0x4015414f in __libc_start_main () from /lib/libc.so.6In this case, you can see that the crash occurred in the ustrzcpy() function, which was called at line 9 of the main() function in the t.c source file. Now you just have to go to that line, have a look at whatever you are doing there, and change it to be correct :-) Note that the crash happened deep inside an Allegro function, which is also revealed by the traceback. However, the binary was linked against a static debug version of Allegro, we wouldn't have had so much luck with a non debug or dynamically linked version. Since gdb is an interactive debugger, you could also select a frame and check out the values of the variables, to see better who is the culprit:
(gdb) frame 2 #2 0x08057575 in _mangled_main () at t.c:9 9 ustrcpy(p1, p2); (gdb) list 4 5 int main(void) 6 { 7 char *p1 = 0, *p2 = 0; 8 allegro_init(); 9 ustrcpy(p1, p2); 10 return 0; 11 } 12 END_OF_MAIN() (gdb) print p1 $1 = 0x0 (gdb) print p2 $2 = 0x0Yuck! Playing with NULL values doesn't really pay off. Ok, while this was a slightly out-of-the-can example, you surely get the point. Remember to check out GDB's manual to learn about more useful commands and/or how to debug your program while it's running and many other things. You might also want to check out Peter Wang's "Debugging with GDB" article, featured in the ninth number of the Pixelate online magazine (http://pixwiki.bafsoft.com/). ]]>
"I've got a problem with my program. I'm attaching a 500k zip file containing ten thousand lines of source code and all the graphics and sound data: can you please debug it and tell me what the trouble is?"After wasting the time and phone bills to download such a huge file, it is unlikely that anyone will even _want_ to help you, let alone invest the amount of time it would take to read and understand such a huge mess of information. You must try to isolate a smaller chunk of code that demonstrates the trouble: the smaller you can make it, the more chance that someone will be able to help you with it. Remember that you are asking other people to do you a favour, so it is your responsibility to make this process as easy for them as you possibly can. ]]>
if (foo) { /* stuff */ } else { /* stuff */ }The only time when something comes on the same line after a closing brace is at the end of a do/while loop, eg:
do { /* stuff */ } while (foo);Case statements look like this:
switch (foo) { case bar: /* stuff */ break; default: /* stuff */ break; }Examples of where to put spaces:
char *p; if (condition) { } for (x=0; x<10; x++) { } function(foo, bar); (BITMAP *)data[id].dat;All sources should begin with the standard header:
/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Brief description of what this file does. * * By Author. * * Cool stuff added by Someone Else. * * Stupid bug fixed by a Third Person. * * See readme.txt for copyright information. */Author credits should be added in chronological order, and email addresses should not be included: those can be found in the main credits file, and if they only exist in one place, it is easier to update them when people change address. People only need to be listed in the source file header if they've made a significant contribution to it (one-line fixes don't count), but no matter how small their addition, they must be added to the docs/thanks._tx file. This is sorted alphabetically by name. If they are already in it, update the text to describe the new addition, otherwise make a new entry for the new contributor. Also, anything more than very tiny modifications should be added to the docs/changes._tx file, which grows from the top in reverse chronological order. This file should briefly describe both the nature of the modification and who did it. ]]>
blit(source_bitmap, destination_bitmap, source_x, source_y, destination_x, destination_y, bitmap_width, bitmap_height); ... blit(spr[3]->bmp, screen, x, y, s_x, s_y, spr[3]->bmp->w, spr[3]->bmp->h);Whatever coding style applies to Allegro's code also applies to these examples (e.g. 8 characters tab, 3 spaces indentation). If you are having trouble documenting a particular function because you don't know how to approach the task (this tends to happen when you have used the function so much that you have learnt it by heart), here is a checklist you can follow:
diff -u file.c.old file.c > patchThis command will generate a text file which contains the differences between both files in unified output format. Open it with your prefered editor and verify that it contains the modifications you wanted to do: lines you have added will be marked with a plus sign '+', lines you have removed will be marked with a minus sign '-'. If the file is bigger than a few kilobytes, compress it before sending to the developers mailing list, and of course remember to add an explanation of what the patch is meant to do, why it's needed, and any other information you consider relevant. If the modifications you want to do are scattered through several files and/or directories, this form of patch generation is very tiresome for both ends (you, and the developers). So unpack a fresh copy of the Allegro source somewhere and move it to the parent directory where your current version is, after giving it another name of course, so as to obtain two complete sources trees side by side. Modify the files you wish in your working directory. Once you are finished, go back to the parent directory housing the two source trees and type:
diff -ur fresh_original_directory working_directory > patchThe '-r' switch makes diff compare directories recursively. Again, do the previous steps of verifying your patch, compressing and sending with correct instructions. If your patch adds or removes files, you will have to add the '-N' switch, because by default diff will ignore files which are only in one of the trees. Of course, you might want to run a 'make clean' in your working directory before running this command, or you will include lots of generated files which have nothing to do with your patch. Or you could edit the resulting patch, but that can be error prone. ]]>
cvs diff -u > patchUnlike the standalone diff, the cvs diff command will work recursively through the Allegro source tree, comparing each file against the Sourceforge repository. The patch will have slightly different headers, but that's ok, once you have it follow the previous process to send it to the developers mailing list. Of course, check cvs' manual for more information and options. ]]>
const type* ptr
without any problem whatsoever.
Note also that certain changes may remove warnings in your program as
static strings, etc, are now treated as `const' by Allegro functions.
There are a few places, described below, where there will be an effect
on existing code.
`const'-correctness is deemed important for two reasons. Firstly, it can
increase code readability and comprehension of Allegro functions (for
instance, you can see which parameters are altered and which are not).
Secondly, it ensures that the Allegro code is not changing data which it
should not be, and that client callback functions are not breaking
Allegro by changing data they should not be.
]]>int some_allegro_function(AL_CONST char** p); void my_func(char** x) { some_allegro_function((AL_CONST char**) x); }I realise that this is a change to the Allegro API, and that we are supposed to avoid those at all costs, but this is essentially fixing a bug in Allegro and changing behaviour. It also ensures that client-supplied callback functions are functioning correctly, and not altering data that they should not. Callback functions which do not treat relevant parameters as `const' are, in a small (but potentially signficant) way, broken. Please note that for the Unicode function ugetx(), I have provided an alternative version ugetxc(), which takes a `const char**' parameter as opposed to a `char**' parameter. This is because it is valid to pass either a `char**' or a `const char**', but unfortunately there is no way to tell the compiler exactly what we mean. ]]>
PROPERTY = 32 bit - <magic> - "prop" 32 bit - <type ID> - property type ID 32 bit - <size> - size of the property string, in bytes var - <data> - property string, _not_ null-terminatedIf the uncompressed size field in an object is positive, the contents of the object are not compressed (ie. the raw and compressed sizes should be the same). If the uncompressed size is negative, the object is LZSS compressed, and will expand into -<uncompressed size> bytes of data. The easiest way to handle this is to use the pack_fopen_chunk() function to read both the raw and compressed sizes and the contents of the object. The contents of an object vary depending on the type. Allegro defines the standard types:
DAT_FILE = 32 bit - <object count> - number of objects in the sub-file var - <object list> - objects in the same format as above DAT_FONT = 16 bit - <font size> - 8, 16, -1, or 0 if font size == 8 { - obsolete as of version 3.9.x! unsigned char[95][8] - 8x8 bit-packed font data } if font size == 16 { - obsolete as of version 3.9.x! unsigned char[95][16] - 8x16 bit-packed font data } if font size == -1 { - obsolete as of version 3.9.x! 95x { 16 bit - <width> - character width 16 bit - <height> - character height var - <data> - character data (8 bit pixels) } } if font size == 0 { - new format introduced in version 3.9.x 16 bit - <ranges> - number of character ranges for each range { 8 bit - <mono> - 1 or 8 bit format flag 32 bit - <start> - first character in range 32 bit - <end> - last character in range (inclusive) for each character { 16 bit - <width> - character width 16 bit - <height> - character height var - <data> - character data } } } DAT_SAMP = 16 bit - <bits> - sample bits (negative for stereo) 16 bit - <freq> - sample frequency 32 bit - <length> - sample length var - <data> - sample data DAT_MIDI = 16 bit - <divisions> - MIDI beat divisions 32x { 32 bit - <length> - track length, in bytes var - <data> - MIDI track data } DAT_FLI = var - <data> - FLI or FLC animation, standard format DAT_BITMAP = DAT_C_SPRITE = DAT_XC_SPRITE = 16 bit - <bits> - bitmap color depth 16 bit - <width> - bitmap width 16 bit - <height> - bitmap height var - <data> - bitmap data Valid color depths are 8, 15, 16, 24, 32, and -32. Both 15 and 16 bit images are stored in 5.6.5 RGB format, and 24 and 32 bit images as 8.8.8 RGB. The special -32 flag indicates that the data is in true 32 bit RGBA format. DAT_RLE_SPRITE = 16 bit - <bits> - sprite color depth 16 bit - <width> - sprite width 16 bit - <height> - sprite height 32 bit - <size> - data size, in bytes var - <data> - RLE compressed sprite data Valid color depths are 8, 15, 16, 24, 32. and -32. Both 15 and 16 bit images are stored in 5.6.5 RGB format with 16 bit skip counts and EOL markers, and 24 and 32 bit images as 8.8.8 RGB. with 32 bit skip counts and markers. The special -32 flag indicates that the data is in true 32 bit RGBA format. DAT_PALETTE = 256 x { 8 bit - <red> - red component, 0-63 8 bit - <green> - green component, 0-63 8 bit - <blue> - blue component, 0-63 8 bit - <pad> - alignment padding }I think that covers everything. ]]>
dat myfile.dat -a alien.pcx -t RLE'-bpp colordepth' Specifies which color format bitmap data should be grabbed in (valid depths are 8, 15, 16, 24, and 32 bits per pixel). '-c0' - no compression '-c1' - compress objects individually '-c2' - global compression on the entire datafile Sets the compression mode (see below). These can be used on their own to convert a datafile from one format to another, or in combination with any other options. '-d <objects>' Deletes the named objects from the datafile. '-dither' Dithers graphics when reducing color depths. '-e <objects>' Extracts the named objects from the datafile. To extract everything, use the wildcard * as the object name. To set the output filename or directory, use the '-o filename' option. For example, to extract an object called TITLE_SCREEN to the file title.pcx, use the command:
dat myfile.dat -e title_screen -o title.pcxTo extract the entire contents of the datafile to the directory c:\output, use:
dat myfile.dat -e * -o c:\output\'-f' Stores the references to original files as relative filenames instead of absolute filenames. This greatly increases the portability of complete source trees containing the source data. '-g x y w h' Grabs bitmap data from a specific grid location. '-h outputfile.h' Sets the output header file, for exporting object index definitions. This may be used on its own to produce a header file from an existing datafile, or in combination with any other commands. You can also use the '-p prefixstring' option to set a prefix string for the object definitions. '-k' Keep original names while grabbing objects. Without this switch, a file called image.pcx will be imported as an object called IMAGE_PCX, to ensure that all the object names are valid symbols for the output header defines. '-l' Lists the contents of the datafile. This can be combined with the '-v' option to list object properties along with the names, and you can specify particular objects to produce a partial listing. '-m dependencyfile' Writes a set of makefile dependencies into the specified file, which can be used to automatically update the file whenever any of the source data changes. '-n0' - no sort: list the objects in the order they were added '-n1' - sort the objects of the datafile alphabetically by name Sets the sort mode (see below). These can be used on their own to sort the objects of the datafile, or in combination with any other options. '-o output' Sets the output file or directory when extracting data. '-p prefixstring' Sets the prefix for the output header file. '-pal objectname' Specifies which palette to use. '-r' Recursively adds directories as nested datafiles. This makes it possible to maintain the data hierarchy within the datafile. '-s0' - no strip: save everything '-s1' - strip grabber specific information from the file '-s2' - strip all object properties and names from the file '-s-PROP' do not strip object property PROP from the file Sets the strip mode (see below). These can be used on their own to strip properties from the datafile, or in combination with any other options. '-t type' Sets the object type when adding files. '-transparency' Preserves transparency when converting between color depths. '-u' Updates the contents of the datafile. See below. '-v' Selects verbose mode. This can be used in combination with any other options to produce more detailed output. '-w' Always updates the entire contents of the datafile. '-x <objects>' Alias for '-e <objects>'. '-007 password' Sets the file encryption key. '<objects> PROP=value' Sets properties for the specified objects. This works like environment variables, in that setting a property to an empty string removes it. Because object names are stored as NAME properties, you can use this command to rename objects. For example, to rename MY_OBJECT to WHAT_A_SILLY_NAME, use the command:
dat myfile.dat my_object NAME=what_a_silly_nameYou can use the wildcard * to apply the property to everything in the file, so to remove the ORIG property from the entire datafile, you could execute:
dat myfile.dat * ORIG=You can create hierarchical nested datafiles by inserting one datafile into another with the '-a' command. Objects in the nested datafile can then be referred to by as "parentname/objectname". For example if the datafile myfile.dat contains a nested datafile called nestedfile, which contains a bitmap called thepicture, you could export the bitmap with the command:
dat myfile.dat -e nestedfile/thepicture -o output.pcx]]>