1 /*
2 * Example program for the Allegro library, by Grzegorz Ludorowski.
3 *
4 * This example demonstrates how to use datafiles, various sprite
5 * drawing routines and flicker-free animation.
6 *
7 * Why is the animate() routine coded in that way? As you
8 * probably know, VIDEO RAM is much slower than "normal"
9 * RAM, so it's advisable to reduce VRAM blits to a minimum.
10 * Drawing sprite on the screen (meaning in VRAM) and then
11 * clearing a background for it is not very fast. This example
12 * uses a different method which is much faster, but require a
13 * bit more memory.
14 *
15 * First the buffer is cleared (it's a normal BITMAP), then the
16 * sprite is drawn on it, and when the drawing is finished this
17 * buffer is copied directly to the screen. So the end result is
18 * that there is a single VRAM blit instead of blitting/clearing
19 * the background and drawing a sprite on it. It's a good method
20 * even when you have to restore the background. And of course,
21 * it completely removes any flickering effect.
22 *
23 * When one uses a big (ie. 800x600 background) and draws
24 * something on it, it's wise to use a copy of background
25 * somewhere in memory and restore background using this
26 * "virtual background". When blitting from VRAM in SVGA modes,
27 * it's probably, that drawing routines have to switch banks on
28 * video card. I think, I don't have to remind how slow is it.
29 *
30 * Note that on modern systems, the above isn't true anymore, and
31 * you usually get the best performance by caching all your
32 * animations in video ram and doing only VRAM->VRAM blits, so
33 * there is no more RAM->VRAM transfer at all anymore. And usually,
34 * such transfers can run in parallel on the graphics card's
35 * processor as well, costing virtually no main cpu time at all.
36 * See the exaccel example for an example of this.
37 */
38
39 #include <math.h>
40 #include <allegro.h>
41 #include "running.h"
42
43
44
45 #define FRAMES_PER_SECOND 30
46
47 /* set up a timer for animation */
48 volatile int ticks = 0;
ticker(void)49 void ticker(void)
50 {
51 ticks++;
52 }
53 END_OF_FUNCTION(ticker)
54
55 /* pointer to data file */
56 DATAFILE *running_data;
57
58 /* current sprite frame number */
59 int frame, frame_number = 0;
60
61 /* pointer to a sprite buffer, where sprite will be drawn */
62 BITMAP *sprite_buffer;
63
64 /* a boolean - if true, skip to next part */
65 int next;
66
67
68
animate(void)69 void animate(void)
70 {
71 /* Wait for animation timer. */
72 while (frame > ticks) {
73 /* Avoid busy wait. */
74 rest(1);
75 }
76
77 /* Ideally, instead of using a timer, we would set the monitor refresh rate
78 * to a multiple of the animation speed, and synchronize with the vertical
79 * blank interrupt (vsync) - to get a completely smooth animation. But this
80 * doesn't work on all setups (e.g. in X11 windowed modes), so should only
81 * be used after performing some tests first or letting the user enable it.
82 * Too much for this simple example
83 */
84
85 frame++;
86
87 /* blits sprite buffer to screen */
88 blit(sprite_buffer, screen, 0, 0, (SCREEN_W - sprite_buffer->w) / 2,
89 (SCREEN_H - sprite_buffer->h) / 2, sprite_buffer->w, sprite_buffer->h);
90
91 /* clears sprite buffer with color 0 */
92 clear_bitmap(sprite_buffer);
93
94 /* if key pressed set a next flag */
95 if (keypressed())
96 next = TRUE;
97 else
98 next = FALSE;
99
100 if (frame_number == 0)
101 play_sample(running_data[SOUND_01].dat, 128, 128, 1000, FALSE);
102
103 /* increase frame number, or if it's equal 9 (last frame) set it to 0 */
104 if (frame_number == 9)
105 frame_number = 0;
106 else
107 frame_number++;
108 }
109
110
111
main(int argc,char * argv[])112 int main(int argc, char *argv[])
113 {
114 char datafile_name[256];
115 int angle = 0;
116 int x, y;
117 int text_y;
118 int color;
119
120 if (allegro_init() != 0)
121 return 1;
122 install_keyboard();
123 install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);
124 install_timer();
125 LOCK_FUNCTION(ticker);
126 LOCK_VARIABLE(ticks);
127 install_int_ex(ticker, BPS_TO_TIMER(30));
128
129 if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
130 if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
131 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
132 allegro_message("Unable to set any graphic mode\n%s\n",
133 allegro_error);
134 return 1;
135 }
136 }
137
138 /* loads datafile and sets user palette saved in datafile */
139 replace_filename(datafile_name, argv[0], "running.dat",
140 sizeof(datafile_name));
141 running_data = load_datafile(datafile_name);
142 if (!running_data) {
143 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
144 allegro_message("Error loading %s!\n", datafile_name);
145 return 1;
146 }
147
148 /* select the palette which was loaded from the datafile */
149 set_palette(running_data[PALETTE_001].dat);
150
151 /* create and clear a bitmap for sprite buffering, big
152 * enough to hold the diagonal(sqrt(2)) when rotating */
153 sprite_buffer = create_bitmap((int)(82 * sqrt(2) + 2),
154 (int)(82 * sqrt(2) + 2));
155 clear_bitmap(sprite_buffer);
156
157 x = (sprite_buffer->w - 82) / 2;
158 y = (sprite_buffer->h - 82) / 2;
159 color = makecol(0, 80, 0);
160 text_y = SCREEN_H - 10 - text_height(font);
161
162 frame = ticks;
163
164 /* write current sprite drawing method */
165 textout_centre_ex(screen, font, "Press a key for next part...",
166 SCREEN_W / 2, 10, palette_color[1], -1);
167 textout_centre_ex(screen, font, "Using draw_sprite",
168 SCREEN_W / 2, text_y, palette_color[15], -1);
169
170 do {
171 hline(sprite_buffer, 0, y + 82, sprite_buffer->w - 1, color);
172 draw_sprite(sprite_buffer, running_data[frame_number].dat, x, y);
173 animate();
174 } while (!next);
175
176 clear_keybuf();
177 rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0);
178 textout_centre_ex(screen, font, "Using draw_sprite_h_flip",
179 SCREEN_W / 2, text_y, palette_color[15], -1);
180
181 do {
182 hline(sprite_buffer, 0, y + 82, sprite_buffer->w - 1, color);
183 draw_sprite_h_flip(sprite_buffer, running_data[frame_number].dat, x, y);
184 animate();
185 } while (!next);
186
187 clear_keybuf();
188 rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0);
189 textout_centre_ex(screen, font, "Using draw_sprite_v_flip",
190 SCREEN_W / 2, text_y, palette_color[15], -1);
191
192 do {
193 hline(sprite_buffer, 0, y - 1, sprite_buffer->w - 1, color);
194 draw_sprite_v_flip(sprite_buffer, running_data[frame_number].dat, x, y);
195 animate();
196 } while (!next);
197
198 clear_keybuf();
199 rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0);
200 textout_centre_ex(screen, font, "Using draw_sprite_vh_flip",
201 SCREEN_W / 2, text_y, palette_color[15], -1);
202
203 do {
204 hline(sprite_buffer, 0, y - 1, sprite_buffer->w - 1, color);
205 draw_sprite_vh_flip(sprite_buffer, running_data[frame_number].dat, x, y);
206 animate();
207 } while (!next);
208
209 clear_keybuf();
210 rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0);
211 textout_centre_ex(screen, font, "Now with rotating - pivot_sprite",
212 SCREEN_W / 2, text_y, palette_color[15], -1);
213
214 do {
215 /* The last argument to pivot_sprite() is a fixed point type,
216 * so I had to use itofix() routine (integer to fixed).
217 */
218 circle(sprite_buffer, x + 41, y + 41, 47, color);
219 pivot_sprite(sprite_buffer, running_data[frame_number].dat, sprite_buffer->w / 2,
220 sprite_buffer->h / 2, 41, 41, itofix(angle));
221 animate();
222 angle -= 4;
223 } while (!next);
224
225 clear_keybuf();
226 rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0);
227 textout_centre_ex(screen, font, "Now using pivot_sprite_v_flip",
228 SCREEN_W / 2, text_y, palette_color[15], -1);
229
230 do {
231 /* The last argument to pivot_sprite_v_flip() is a fixed point type,
232 * so I had to use itofix() routine (integer to fixed).
233 */
234 circle(sprite_buffer, x + 41, y + 41, 47, color);
235 pivot_sprite_v_flip(sprite_buffer, running_data[frame_number].dat,
236 sprite_buffer->w / 2, sprite_buffer->h / 2, 41, 41, itofix(angle));
237 animate();
238 angle += 4;
239 } while (!next);
240
241 unload_datafile(running_data);
242 destroy_bitmap(sprite_buffer);
243 return 0;
244 }
245
246 END_OF_MAIN()
247