1 #include <allegro5/allegro.h>
2 #include <allegro5/allegro_image.h>
3 #include <allegro5/allegro_font.h>
4 #include <stdlib.h>
5 #include <math.h>
6 
7 #include "common.c"
8 
9 ALLEGRO_DEBUG_CHANNEL("main")
10 
11 #define FPS 60
12 #define MAX_SPRITES 1024
13 
14 typedef struct Sprite {
15    float x, y, dx, dy;
16 } Sprite;
17 
18 char const *text[] = {
19    "H - toggle held drawing",
20    "Space - toggle use of textures",
21    "B - toggle alpha blending",
22    "Left/Right - change bitmap size",
23    "Up/Down - change bitmap count",
24    "F1 - toggle help text"
25 };
26 
27 struct Example {
28    Sprite sprites[MAX_SPRITES];
29    bool use_memory_bitmaps;
30    int blending;
31    ALLEGRO_DISPLAY *display;
32    ALLEGRO_BITMAP *mysha, *bitmap;
33    bool hold_bitmap_drawing;
34    int bitmap_size;
35    int sprite_count;
36    bool show_help;
37    ALLEGRO_FONT *font;
38 
39    int t;
40 
41    ALLEGRO_COLOR white;
42    ALLEGRO_COLOR half_white;
43    ALLEGRO_COLOR dark;
44    ALLEGRO_COLOR red;
45 
46    double direct_speed_measure;
47 
48    int ftpos;
49    double frame_times[FPS];
50 } example;
51 
add_time(void)52 static void add_time(void)
53 {
54    example.frame_times[example.ftpos++] = al_get_time();
55    if (example.ftpos >= FPS)
56       example.ftpos = 0;
57 }
58 
get_fps(int * average,int * minmax)59 static void get_fps(int *average, int *minmax)
60 {
61    int i;
62    int prev = FPS - 1;
63    double min_dt = 1;
64    double max_dt = 1 / 1000000.0;
65    double av = 0;
66    double d;
67    for (i = 0; i < FPS; i++) {
68       if (i != example.ftpos) {
69          double dt = example.frame_times[i] - example.frame_times[prev];
70          if (dt < min_dt)
71             min_dt = dt;
72          if (dt > max_dt)
73             max_dt = dt;
74          av += dt;
75       }
76       prev = i;
77    }
78    av /= (FPS - 1);
79    *average = ceil(1 / av);
80    d = 1 / min_dt - 1 / max_dt;
81    *minmax = floor(d / 2);
82 }
83 
add_sprite(void)84 static void add_sprite(void)
85 {
86    if (example.sprite_count < MAX_SPRITES) {
87       int w = al_get_display_width(example.display);
88       int h = al_get_display_height(example.display);
89       int i = example.sprite_count++;
90       Sprite *s = example.sprites + i;
91       float a = rand() % 360;
92       s->x = rand() % (w - example.bitmap_size);
93       s->y = rand() % (h - example.bitmap_size);
94       s->dx = cos(a) * FPS * 2;
95       s->dy = sin(a) * FPS * 2;
96    }
97 }
98 
add_sprites(int n)99 static void add_sprites(int n)
100 {
101     int i;
102     for (i = 0; i < n; i++)
103        add_sprite();
104 }
105 
remove_sprites(int n)106 static void remove_sprites(int n)
107 {
108    example.sprite_count -= n;
109    if (example.sprite_count < 0)
110       example.sprite_count = 0;
111 }
112 
change_size(int size)113 static void change_size(int size)
114 {
115    int bw, bh;
116    if (size < 1)
117       size = 1;
118    if (size > 1024)
119       size = 1024;
120 
121    if (example.bitmap)
122       al_destroy_bitmap(example.bitmap);
123    al_set_new_bitmap_flags(
124       example.use_memory_bitmaps ? ALLEGRO_MEMORY_BITMAP : ALLEGRO_VIDEO_BITMAP);
125    example.bitmap = al_create_bitmap(size, size);
126    example.bitmap_size = size;
127    al_set_target_bitmap(example.bitmap);
128    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
129    al_clear_to_color(al_map_rgba_f(0, 0, 0, 0));
130    bw = al_get_bitmap_width(example.mysha);
131    bh = al_get_bitmap_height(example.mysha);
132    al_draw_scaled_bitmap(example.mysha, 0, 0, bw, bh, 0, 0,
133       size, size * bh / bw, 0);
134    al_set_target_backbuffer(example.display);
135 }
136 
sprite_update(Sprite * s)137 static void sprite_update(Sprite *s)
138 {
139    int w = al_get_display_width(example.display);
140    int h = al_get_display_height(example.display);
141 
142    s->x += s->dx / FPS;
143    s->y += s->dy / FPS;
144 
145    if (s->x < 0) {
146       s->x = -s->x;
147       s->dx = -s->dx;
148    }
149    if (s->x + example.bitmap_size > w) {
150       s->x = -s->x + 2 * (w - example.bitmap_size);
151       s->dx = -s->dx;
152    }
153    if (s->y < 0) {
154       s->y = -s->y;
155       s->dy = -s->dy;
156    }
157    if (s->y + example.bitmap_size > h) {
158       s->y = -s->y + 2 * (h - example.bitmap_size);
159       s->dy = -s->dy;
160    }
161 
162    if (example.bitmap_size > w) s->x = w / 2 - example.bitmap_size / 2;
163    if (example.bitmap_size > h) s->y = h / 2 - example.bitmap_size / 2;
164 }
165 
update(void)166 static void update(void)
167 {
168    int i;
169    for (i = 0; i < example.sprite_count; i++)
170       sprite_update(example.sprites + i);
171 
172    example.t++;
173    if (example.t == 60) {
174       ALLEGRO_DEBUG("tick");
175       example.t = 0;
176    }
177 }
178 
redraw(void)179 static void redraw(void)
180 {
181    int w = al_get_display_width(example.display);
182    int h = al_get_display_height(example.display);
183    int i;
184    int f1, f2;
185    int fh = al_get_font_line_height(example.font);
186    char const *info[] = {"textures", "memory buffers"};
187    char const *binfo[] = {"alpha", "additive", "tinted", "solid", "alpha test"};
188    ALLEGRO_COLOR tint = example.white;
189 
190    if (example.blending == 0) {
191       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
192       tint = example.half_white;
193    }
194    else if (example.blending == 1) {
195       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
196       tint = example.dark;
197    }
198    else if (example.blending == 2) {
199       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
200       tint = example.red;
201    }
202    else if (example.blending == 3) {
203       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
204    }
205 
206    if (example.blending == 4) {
207       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
208       al_set_render_state(ALLEGRO_ALPHA_TEST, true);
209       al_set_render_state(ALLEGRO_ALPHA_FUNCTION, ALLEGRO_RENDER_GREATER);
210       al_set_render_state(ALLEGRO_ALPHA_TEST_VALUE, 128);
211    }
212    else {
213       al_set_render_state(ALLEGRO_ALPHA_TEST, false);
214    }
215 
216    if (example.hold_bitmap_drawing) {
217       al_hold_bitmap_drawing(true);
218    }
219    for (i = 0; i < example.sprite_count; i++) {
220       Sprite *s = example.sprites + i;
221       al_draw_tinted_bitmap(example.bitmap, tint, s->x, s->y, 0);
222    }
223    if (example.hold_bitmap_drawing) {
224       al_hold_bitmap_drawing(false);
225    }
226 
227    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
228    if (example.show_help) {
229       int dh = fh * 3.5;
230       for (i = 5; i >= 0; i--) {
231          al_draw_text(example.font, example.white, 0, h - dh, 0, text[i]);
232          dh += fh * 6;
233       }
234    }
235 
236    al_draw_textf(example.font, example.white, 0, 0, 0, "count: %d",
237       example.sprite_count);
238    al_draw_textf(example.font, example.white, 0, fh, 0, "size: %d",
239       example.bitmap_size);
240    al_draw_textf(example.font, example.white, 0, fh * 2, 0, "%s",
241       info[example.use_memory_bitmaps]);
242    al_draw_textf(example.font, example.white, 0, fh * 3, 0, "%s",
243       binfo[example.blending]);
244 
245    get_fps(&f1, &f2);
246    al_draw_textf(example.font, example.white, w, 0, ALLEGRO_ALIGN_RIGHT, "FPS: %4d +- %-4d",
247       f1, f2);
248    al_draw_textf(example.font, example.white, w, fh, ALLEGRO_ALIGN_RIGHT, "%4d / sec",
249       (int)(1.0 / example.direct_speed_measure));
250 
251 }
252 
main(int argc,char ** argv)253 int main(int argc, char **argv)
254 {
255    ALLEGRO_TIMER *timer;
256    ALLEGRO_EVENT_QUEUE *queue;
257    ALLEGRO_MONITOR_INFO info;
258    const char* bitmap_filename;
259    int w = 640, h = 480;
260    bool done = false;
261    bool need_redraw = true;
262    bool background = false;
263    example.show_help = true;
264    example.hold_bitmap_drawing = false;
265 
266    if (argc > 1) {
267       bitmap_filename = argv[1];
268    }
269    else {
270       bitmap_filename = "data/mysha256x256.png";
271    }
272 
273    if (!al_init()) {
274       abort_example("Failed to init Allegro.\n");
275    }
276 
277    if (!al_init_image_addon()) {
278       abort_example("Failed to init IIO addon.\n");
279    }
280 
281    al_init_font_addon();
282    init_platform_specific();
283 
284    al_get_num_video_adapters();
285 
286    al_get_monitor_info(0, &info);
287 
288    al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS,
289                              ALLEGRO_DISPLAY_ORIENTATION_ALL, ALLEGRO_SUGGEST);
290    example.display = al_create_display(w, h);
291    if (!example.display) {
292       abort_example("Error creating display.\n");
293    }
294 
295    w = al_get_display_width(example.display);
296    h = al_get_display_height(example.display);
297 
298    if (!al_install_keyboard()) {
299       abort_example("Error installing keyboard.\n");
300    }
301 
302    if (!al_install_mouse()) {
303       abort_example("Error installing mouse.\n");
304    }
305 
306    al_install_touch_input();
307 
308    example.font = al_create_builtin_font();
309    if (!example.font) {
310       abort_example("Error creating builtin font\n");
311    }
312 
313    example.mysha = al_load_bitmap(bitmap_filename);
314    if (!example.mysha) {
315       abort_example("Error loading %s\n", bitmap_filename);
316    }
317 
318    example.white = al_map_rgb_f(1, 1, 1);
319    example.half_white = al_map_rgba_f(1, 1, 1, 0.5);
320    example.dark = al_map_rgb(15, 15, 15);
321    example.red = al_map_rgb_f(1, 0.2, 0.1);
322    change_size(256);
323    add_sprite();
324    add_sprite();
325 
326    timer = al_create_timer(1.0 / FPS);
327 
328    queue = al_create_event_queue();
329    al_register_event_source(queue, al_get_keyboard_event_source());
330    al_register_event_source(queue, al_get_mouse_event_source());
331    al_register_event_source(queue, al_get_timer_event_source(timer));
332 
333    if (al_install_touch_input())
334       al_register_event_source(queue, al_get_touch_input_event_source());
335    al_register_event_source(queue, al_get_display_event_source(example.display));
336 
337    al_start_timer(timer);
338 
339    while (!done) {
340       float x, y;
341       ALLEGRO_EVENT event;
342       w = al_get_display_width(example.display);
343       h = al_get_display_height(example.display);
344 
345       if (!background && need_redraw && al_is_event_queue_empty(queue)) {
346          double t = -al_get_time();
347          add_time();
348          al_clear_to_color(al_map_rgb_f(0, 0, 0));
349          redraw();
350          t += al_get_time();
351          example.direct_speed_measure  = t;
352          al_flip_display();
353          need_redraw = false;
354       }
355 
356       al_wait_for_event(queue, &event);
357       switch (event.type) {
358          case ALLEGRO_EVENT_KEY_CHAR: /* includes repeats */
359             if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
360                done = true;
361             else if (event.keyboard.keycode == ALLEGRO_KEY_UP) {
362                add_sprites(1);
363             }
364             else if (event.keyboard.keycode == ALLEGRO_KEY_DOWN) {
365                remove_sprites(1);
366             }
367             else if (event.keyboard.keycode == ALLEGRO_KEY_LEFT) {
368                change_size(example.bitmap_size - 1);
369             }
370             else if (event.keyboard.keycode == ALLEGRO_KEY_RIGHT) {
371                change_size(example.bitmap_size + 1);
372             }
373             else if (event.keyboard.keycode == ALLEGRO_KEY_F1) {
374                example.show_help ^= 1;
375             }
376             else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) {
377                example.use_memory_bitmaps ^= 1;
378                change_size(example.bitmap_size);
379             }
380             else if (event.keyboard.keycode == ALLEGRO_KEY_B) {
381                example.blending++;
382                if (example.blending == 5)
383                   example.blending = 0;
384             }
385             else if (event.keyboard.keycode == ALLEGRO_KEY_H) {
386                example.hold_bitmap_drawing ^= 1;
387             }
388             break;
389 
390          case ALLEGRO_EVENT_DISPLAY_CLOSE:
391             done = true;
392             break;
393 
394          case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
395 
396             background = true;
397             al_acknowledge_drawing_halt(event.display.source);
398 
399             break;
400 
401          case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
402             background = false;
403             al_acknowledge_drawing_resume(event.display.source);
404             break;
405 
406          case ALLEGRO_EVENT_DISPLAY_RESIZE:
407             al_acknowledge_resize(event.display.source);
408             break;
409 
410          case ALLEGRO_EVENT_TIMER:
411             update();
412             need_redraw = true;
413             break;
414 
415          case ALLEGRO_EVENT_TOUCH_BEGIN:
416             x = event.touch.x;
417             y = event.touch.y;
418             goto click;
419 
420          case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
421             x = event.mouse.x;
422             y = event.mouse.y;
423             goto click;
424 
425          click:
426          {
427             int fh = al_get_font_line_height(example.font);
428 
429             if (x < fh * 12 && y >= h - fh * 30) {
430                int button = (y - (h - fh * 30)) / (fh * 6);
431                if (button == 0) {
432                   example.use_memory_bitmaps ^= 1;
433                   change_size(example.bitmap_size);
434                }
435                if (button == 1) {
436                   example.blending++;
437                   if (example.blending == 5)
438                      example.blending = 0;
439                }
440                if (button == 3) {
441                   if (x < fh * 6)
442                      remove_sprites(example.sprite_count / 2);
443                   else
444                      add_sprites(example.sprite_count);
445                }
446                if (button == 2) {
447                   int s = example.bitmap_size * 2;
448                   if (x < fh * 6)
449                      s = example.bitmap_size / 2;
450                   change_size(s);
451                }
452                if (button == 4) {
453                   example.show_help ^= 1;
454                }
455 
456             }
457             break;
458          }
459       }
460    }
461 
462    al_destroy_bitmap(example.bitmap);
463 
464    return 0;
465 }
466 
467 /* vim: set sts=3 sw=3 et: */
468