The Allegro Wiki is migrating to github at https://github.com/liballeg/allegro_wiki/wiki

ExampleExFlame

From Allegro Wiki
Jump to: navigation, search

<highlightSyntax lang="C"> /*

*    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 getpixel() and
*    putpixel(), then by accessing video memory directly a byte at a
*    time, and finally using block memory copy operations.
*/


  1. include <allegro.h>


/* The fire is formed from several 'hotspots' which are moved randomly

* across the bottom of the screen.
*/
  1. define FIRE_HOTSPOTS 48

int hotspot[FIRE_HOTSPOTS];

unsigned char *temp;


/* This function updates the bottom line of the 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<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 < SCREEN_W)) temp[c2] = MIN(temp[c2] + 20-ABS(hotspot[c]-c2), 192);

     /* move the hotspots */
     hotspot[c] += (AL_RAND() & 7) - 3; 
     if (hotspot[c] < 0)

hotspot[c] += SCREEN_W;

     else

if (hotspot[c] >= SCREEN_W) hotspot[c] -= SCREEN_W;

  }
  /* display the buffer */
  for (c=0; c<SCREEN_W; c++)
     putpixel(screen, c, SCREEN_H-1, temp[c]);

}


int main(void) {

  PALETTE palette;
  uintptr_t address;
  int x, y, c;
  if (allegro_init() != 0)
     return 1;
  install_keyboard(); 
  if (set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0) != 0) {
     if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {

allegro_message("Error setting graphics mode\n%s\n", allegro_error); return 1;

     }
  }
  temp = (unsigned char *)malloc(sizeof(unsigned char) * SCREEN_W);
  if (!temp) {
     set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
     allegro_message("Not enough memory? This is a joke right!?!\n");
     return 0;
  }
  for (c=0; c<FIRE_HOTSPOTS; c++)
     hotspot[c] = AL_RAND() % 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-128;
  }
  for (c=192; c<256; c++) {
     palette[c].r = 63;
     palette[c].g = 63;
     palette[c].b = 63;
  }
  set_palette(palette);
  textout_ex(screen, font, "Using get/putpixel()", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
  /* using getpixel() and putpixel() is slow :-) */
  while (!keypressed()) {
     acquire_screen();
     draw_bottom_line_of_fire();
     for (y=64; y<SCREEN_H-1; y++) {

/* read line */ for (x=0; x<SCREEN_W; x++) { c = getpixel(screen, x, y+1);

if (c > 0) c--;

putpixel(screen, x, y, c); }

     }
     release_screen();
  }
  clear_keybuf();
  textout_ex(screen, font, "Using direct memory writes", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
  /* It is much faster if we access the screen memory directly. This
   * time we read an entire line of the screen into our own buffer,
   * modify it there, and then write the whole 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 line.
   */
  while (!keypressed()) {
     acquire_screen();
     draw_bottom_line_of_fire();
     bmp_select(screen);
     for (y=64; y<SCREEN_H-1; y++) {

/* get an address for reading line y+1 */ address = bmp_read_line(screen, y+1);

/* read line with farptr functions */ for (x=0; x<SCREEN_W; x++) temp[x] = bmp_read8(address+x);

/* adjust it */ for (x=0; x<SCREEN_W; x++) if (temp[x] > 0) temp[x]--;

/* get an address for writing line y */ address = bmp_write_line(screen, y);

/* write line with farptr functions */ for (x=0; x<SCREEN_W; x++) bmp_write8(address+x, temp[x]);

     }
     bmp_unwrite_line(screen);
     release_screen();
  }
  clear_keybuf();
  textout_ex(screen, font, "Using block data transfers", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
  /* 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 (!keypressed()) {
     acquire_screen();
     draw_bottom_line_of_fire();
     bmp_select(screen);
     for (y=64; y<SCREEN_H-1; y++) {

/* get an address for reading line y+1 */ address = bmp_read_line(screen, y+1);

/* read line in 32 bit chunks */ for (x=0; x<SCREEN_W; x += sizeof(uint32_t)) *((uint32_t *)&temp[x]) = bmp_read32(address+x);

/* adjust it */ for (x=0; x<SCREEN_W; x++) if (temp[x] > 0) temp[x]--;

/* get an address for writing line y */ address = bmp_write_line(screen, y);

/* write line in 32 bit chunks */ for (x=0; x<SCREEN_W; x += sizeof(uint32_t)) bmp_write32(address+x, *((uint32_t *)&temp[x]));

     }
     bmp_unwrite_line(screen);
     release_screen();
  }
  free(temp);
  return 0;

}

END_OF_MAIN() </highlightSyntax>