1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/*
* 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.
*/
#include "allegro.h"
/* The fire is formed from several 'hotspots' which are moved randomly
* across the bottom of the screen.
*/
#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] += (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;
unsigned long address;
int x, y, c;
allegro_init();
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] = 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-192;
}
for (c=192; c<256; c++) {
palette[c].r = 63;
palette[c].g = 63;
palette[c].b = 63;
}
set_palette(palette);
textout(screen, font, "Using get/putpixel()", 0, 0, makecol(255,255,255));
/* 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(screen, font, "Using direct memory writes", 0, 0, makecol(255,255,255));
/* 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(screen, font, "Using block data transfers", 0, 0, makecol(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 (!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(unsigned long))
*((unsigned long *)&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(unsigned long))
bmp_write32(address+x, *((unsigned long *)&temp[x]));
}
bmp_unwrite_line(screen);
release_screen();
}
free(temp);
return 0;
}
END_OF_MAIN();
|