1 /*
2 * Example program for the Allegro library, by Shawn Hargreaves.
3 *
4 * This program demonstrates how to write directly to video memory.
5 * It implements a simple fire effect, first by calling getpixel() and
6 * putpixel(), then by accessing video memory directly a byte at a
7 * time, and finally using block memory copy operations.
8 */
9
10
11 #include <allegro.h>
12
13
14
15 /* The fire is formed from several 'hotspots' which are moved randomly
16 * across the bottom of the screen.
17 */
18 #define FIRE_HOTSPOTS 48
19
20 int hotspot[FIRE_HOTSPOTS];
21
22 unsigned char *temp;
23
24
25
26 /* This function updates the bottom line of the screen with a pattern
27 * of varying intensities which are then moved upwards and faded out
28 * by the code in main().
29 */
draw_bottom_line_of_fire(void)30 void draw_bottom_line_of_fire(void)
31 {
32 int c, c2;
33
34 /* zero the buffer */
35 for (c=0; c<SCREEN_W; c++)
36 temp[c] = 0;
37
38 for (c=0; c<FIRE_HOTSPOTS; c++) {
39 /* display the hotspots */
40 for (c2=hotspot[c]-20; c2<hotspot[c]+20; c2++)
41 if ((c2 >= 0) && (c2 < SCREEN_W))
42 temp[c2] = MIN(temp[c2] + 20-ABS(hotspot[c]-c2), 192);
43
44 /* move the hotspots */
45 hotspot[c] += (AL_RAND() & 7) - 3;
46 if (hotspot[c] < 0)
47 hotspot[c] += SCREEN_W;
48 else
49 if (hotspot[c] >= SCREEN_W)
50 hotspot[c] -= SCREEN_W;
51 }
52
53 /* display the buffer */
54 for (c=0; c<SCREEN_W; c++)
55 putpixel(screen, c, SCREEN_H-1, temp[c]);
56 }
57
58
59
main(void)60 int main(void)
61 {
62 PALETTE palette;
63 uintptr_t address;
64 int x, y, c;
65
66 if (allegro_init() != 0)
67 return 1;
68 install_keyboard();
69 if (set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0) != 0) {
70 if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
71 allegro_message("Error setting graphics mode\n%s\n", allegro_error);
72 return 1;
73 }
74 }
75
76 temp = (unsigned char *)malloc(sizeof(unsigned char) * SCREEN_W);
77
78 if (!temp) {
79 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
80 allegro_message("Not enough memory? This is a joke right!?!\n");
81 return 0;
82 }
83
84 for (c=0; c<FIRE_HOTSPOTS; c++)
85 hotspot[c] = AL_RAND() % SCREEN_W;
86
87 /* fill our palette with a gradually altering sequence of colors */
88 for (c=0; c<64; c++) {
89 palette[c].r = c;
90 palette[c].g = 0;
91 palette[c].b = 0;
92 }
93 for (c=64; c<128; c++) {
94 palette[c].r = 63;
95 palette[c].g = c-64;
96 palette[c].b = 0;
97 }
98 for (c=128; c<192; c++) {
99 palette[c].r = 63;
100 palette[c].g = 63;
101 palette[c].b = c-128;
102 }
103 for (c=192; c<256; c++) {
104 palette[c].r = 63;
105 palette[c].g = 63;
106 palette[c].b = 63;
107 }
108
109 set_palette(palette);
110
111 textout_ex(screen, font, "Using get/putpixel()", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
112
113 /* using getpixel() and putpixel() is slow :-) */
114 while (!keypressed()) {
115 acquire_screen();
116
117 draw_bottom_line_of_fire();
118
119 for (y=64; y<SCREEN_H-1; y++) {
120 /* read line */
121 for (x=0; x<SCREEN_W; x++) {
122 c = getpixel(screen, x, y+1);
123
124 if (c > 0)
125 c--;
126
127 putpixel(screen, x, y, c);
128 }
129 }
130 release_screen();
131
132 /* Hack to make sure keyboard input is noticed. */
133 rest(0);
134 }
135
136 clear_keybuf();
137 textout_ex(screen, font, "Using direct memory writes", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
138
139 /* It is much faster if we access the screen memory directly. This
140 * time we read an entire line of the screen into our own buffer,
141 * modify it there, and then write the whole line back in one go.
142 * That is to avoid having to keep switching back and forth between
143 * different scanlines: if we only copied one pixel at a time, we
144 * would have to call bmp_write_line() for every single pixel rather
145 * than just twice per line.
146 */
147 while (!keypressed()) {
148 acquire_screen();
149 draw_bottom_line_of_fire();
150
151 bmp_select(screen);
152
153 for (y=64; y<SCREEN_H-1; y++) {
154 /* get an address for reading line y+1 */
155 address = bmp_read_line(screen, y+1);
156
157 /* read line with farptr functions */
158 for (x=0; x<SCREEN_W; x++)
159 temp[x] = bmp_read8(address+x);
160
161 /* adjust it */
162 for (x=0; x<SCREEN_W; x++)
163 if (temp[x] > 0)
164 temp[x]--;
165
166 /* get an address for writing line y */
167 address = bmp_write_line(screen, y);
168
169 /* write line with farptr functions */
170 for (x=0; x<SCREEN_W; x++)
171 bmp_write8(address+x, temp[x]);
172 }
173
174 bmp_unwrite_line(screen);
175 release_screen();
176
177 /* Hack to make sure keyboard input is noticed. */
178 rest(0);
179 }
180
181 clear_keybuf();
182 textout_ex(screen, font, "Using block data transfers", 0, 0, makecol(255,255,255), makecol(0, 0, 0));
183
184 /* It is even faster if we transfer the data in 32 bit chunks, rather
185 * than only one pixel at a time. This method may not work on really
186 * unusual machine architectures, but should be ok on just about
187 * anything that you are practically likely to come across.
188 */
189 while (!keypressed()) {
190 acquire_screen();
191 draw_bottom_line_of_fire();
192
193 bmp_select(screen);
194
195 for (y=64; y<SCREEN_H-1; y++) {
196 /* get an address for reading line y+1 */
197 address = bmp_read_line(screen, y+1);
198
199 /* read line in 32 bit chunks */
200 for (x=0; x<SCREEN_W; x += sizeof(uint32_t))
201 *((uint32_t *)&temp[x]) = bmp_read32(address+x);
202
203 /* adjust it */
204 for (x=0; x<SCREEN_W; x++)
205 if (temp[x] > 0)
206 temp[x]--;
207
208 /* get an address for writing line y */
209 address = bmp_write_line(screen, y);
210
211 /* write line in 32 bit chunks */
212 for (x=0; x<SCREEN_W; x += sizeof(uint32_t))
213 bmp_write32(address+x, *((uint32_t *)&temp[x]));
214 }
215
216 bmp_unwrite_line(screen);
217 release_screen();
218
219 /* Hack to make sure keyboard input is noticed. */
220 rest(0);
221 }
222
223 free(temp);
224
225 return 0;
226 }
227
228 END_OF_MAIN()
229