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