Show exflame.c syntax highlighted
/*
* Example program for the Allegro library, by Shawn Hargreaves.
*
* This program demonstrates how to write directly to video memory.
* It implements a simple fire effect, first by calling al_get_pixel() and
* al_put_pixel(), then by accessing video memory directly a byte at a
* time, and finally using block memory copy operations.
*/
#include "allegro.h"
/* The fire is formed from several 'hotspots' which are moved randomly
* across the bottom of the al_screen.
*/
#define FIRE_HOTSPOTS 48
int hotspot[FIRE_HOTSPOTS];
unsigned char *temp;
/* This function updates the bottom al_draw_line of the al_screen with a pattern
* of varying intensities which are then moved upwards and faded out
* by the code in main().
*/
void draw_bottom_line_of_fire(void)
{
int c, c2;
/* zero the buffer */
for (c=0; c<AL_SCREEN_W; c++)
temp[c] = 0;
for (c=0; c<FIRE_HOTSPOTS; c++) {
/* display the hotspots */
for (c2=hotspot[c]-20; c2<hotspot[c]+20; c2++)
if ((c2 >= 0) && (c2 < AL_SCREEN_W))
temp[c2] = MIN(temp[c2] + 20-ABS(hotspot[c]-c2), 192);
/* move the hotspots */
hotspot[c] += (rand() & 7) - 3;
if (hotspot[c] < 0)
hotspot[c] += AL_SCREEN_W;
else
if (hotspot[c] >= AL_SCREEN_W)
hotspot[c] -= AL_SCREEN_W;
}
/* display the buffer */
for (c=0; c<AL_SCREEN_W; c++)
al_put_pixel(al_screen, c, AL_SCREEN_H-1, temp[c]);
}
int main(void)
{
AL_PALETTE palette;
unsigned long address;
int x, y, c;
allegro_init();
al_install_keyboard();
if (al_set_gfx_mode(AL_GFX_AUTODETECT, 320, 200, 0, 0) != 0) {
if (al_set_gfx_mode(AL_GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
al_show_message("Error setting graphics mode\n%s\n", al_error);
return 1;
}
}
temp = (unsigned char *)malloc(sizeof(unsigned char) * AL_SCREEN_W);
if (!temp) {
al_set_gfx_mode(AL_GFX_NONE, 0, 0, 0, 0);
al_show_message("Not enough memory? This is a joke right!?!\n");
return 0;
}
for (c=0; c<FIRE_HOTSPOTS; c++)
hotspot[c] = rand() % AL_SCREEN_W;
/* fill our palette with a gradually altering sequence of colors */
for (c=0; c<64; c++) {
palette[c].r = c;
palette[c].g = 0;
palette[c].b = 0;
}
for (c=64; c<128; c++) {
palette[c].r = 63;
palette[c].g = c-64;
palette[c].b = 0;
}
for (c=128; c<192; c++) {
palette[c].r = 63;
palette[c].g = 63;
palette[c].b = c-192;
}
for (c=192; c<256; c++) {
palette[c].r = 63;
palette[c].g = 63;
palette[c].b = 63;
}
al_set_palette(palette);
al_put_text(al_screen, al_font_8x8, "Using get/al_put_pixel()", 0, 0, al_make_color(255,255,255));
/* using al_get_pixel() and al_put_pixel() is slow :-) */
while (!al_key_pressed()) {
al_acquire_screen();
draw_bottom_line_of_fire();
for (y=64; y<AL_SCREEN_H-1; y++) {
/* read al_draw_line */
for (x=0; x<AL_SCREEN_W; x++) {
c = al_get_pixel(al_screen, x, y+1);
if (c > 0)
c--;
al_put_pixel(al_screen, x, y, c);
}
}
al_release_screen();
}
al_clear_keybuf();
al_put_text(al_screen, al_font_8x8, "Using direct memory writes", 0, 0, al_make_color(255,255,255));
/* It is much faster if we access the al_screen memory directly. This
* time we read an entire al_draw_line of the al_screen into our own buffer,
* modify it there, and then write the whole al_draw_line back in one go.
* That is to avoid having to keep switching back and forth between
* different scanlines: if we only copied one pixel at a time, we
* would have to call bmp_write_line() for every single pixel rather
* than just twice per al_draw_line.
*/
while (!al_key_pressed()) {
al_acquire_screen();
draw_bottom_line_of_fire();
bmp_select(al_screen);
for (y=64; y<AL_SCREEN_H-1; y++) {
/* get an address for reading al_draw_line y+1 */
address = bmp_read_line(al_screen, y+1);
/* read al_draw_line with farptr functions */
for (x=0; x<AL_SCREEN_W; x++)
temp[x] = bmp_read8(address+x);
/* adjust it */
for (x=0; x<AL_SCREEN_W; x++)
if (temp[x] > 0)
temp[x]--;
/* get an address for writing al_draw_line y */
address = bmp_write_line(al_screen, y);
/* write al_draw_line with farptr functions */
for (x=0; x<AL_SCREEN_W; x++)
bmp_write8(address+x, temp[x]);
}
bmp_unwrite_line(al_screen);
al_release_screen();
}
al_clear_keybuf();
al_put_text(al_screen, al_font_8x8, "Using block data transfers", 0, 0, al_make_color(255,255,255));
/* It is even faster if we transfer the data in 32 bit chunks, rather
* than only one pixel at a time. This method may not work on really
* unusual machine architectures, but should be ok on just about
* anything that you are practically likely to come across.
*/
while (!al_key_pressed()) {
al_acquire_screen();
draw_bottom_line_of_fire();
bmp_select(al_screen);
for (y=64; y<AL_SCREEN_H-1; y++) {
/* get an address for reading al_draw_line y+1 */
address = bmp_read_line(al_screen, y+1);
/* read al_draw_line in 32 bit chunks */
for (x=0; x<AL_SCREEN_W; x += sizeof(unsigned long))
*((unsigned long *)&temp[x]) = bmp_read32(address+x);
/* adjust it */
for (x=0; x<AL_SCREEN_W; x++)
if (temp[x] > 0)
temp[x]--;
/* get an address for writing al_draw_line y */
address = bmp_write_line(al_screen, y);
/* write al_draw_line in 32 bit chunks */
for (x=0; x<AL_SCREEN_W; x += sizeof(unsigned long))
bmp_write32(address+x, *((unsigned long *)&temp[x]));
}
bmp_unwrite_line(al_screen);
al_release_screen();
}
free(temp);
return 0;
}
AL_END_OF_MAIN();
See more files for this project here