1 /* An example demonstrating different blending modes.
2  */
3 
4 #define ALLEGRO_UNSTABLE
5 #include <allegro5/allegro.h>
6 #include <allegro5/allegro_font.h>
7 #include <allegro5/allegro_image.h>
8 #include <allegro5/allegro_primitives.h>
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <math.h>
12 
13 #include "common.c"
14 
15 /* A structure holding all variables of our example program. */
16 struct Example
17 {
18    ALLEGRO_BITMAP *example; /* Our example bitmap. */
19    ALLEGRO_BITMAP *offscreen; /* An offscreen buffer, for testing. */
20    ALLEGRO_BITMAP *memory; /* A memory buffer, for testing. */
21    ALLEGRO_FONT *myfont; /* Our font. */
22    ALLEGRO_EVENT_QUEUE *queue; /* Our events queue. */
23    int image; /* Which test image to use. */
24    int mode; /* How to draw it. */
25    int BUTTONS_X; /* Where to draw buttons. */
26 
27    int FPS;
28    double last_second;
29    int frames_accum;
30    double fps;
31 } ex;
32 
33 /* Print some text with a shadow. */
print(int x,int y,bool vertical,char const * format,...)34 static void print(int x, int y, bool vertical, char const *format, ...)
35 {
36    va_list list;
37    char message[1024];
38    ALLEGRO_COLOR color;
39    int h;
40    int j;
41 
42    va_start(list, format);
43    vsnprintf(message, sizeof message, format, list);
44    va_end(list);
45 
46    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
47    h = al_get_font_line_height(ex.myfont);
48 
49    for (j = 0; j < 2; j++) {
50       if (j == 0)
51          color = al_map_rgb(0, 0, 0);
52       else
53          color = al_map_rgb(255, 255, 255);
54 
55       if (vertical) {
56          int i;
57          ALLEGRO_USTR_INFO ui;
58          const ALLEGRO_USTR *us = al_ref_cstr(&ui, message);
59          for (i = 0; i < (int)al_ustr_length(us); i++) {
60             ALLEGRO_USTR_INFO letter;
61             al_draw_ustr(ex.myfont, color, x + 1 - j, y + 1 - j + h * i, 0,
62                al_ref_ustr(&letter, us, al_ustr_offset(us, i),
63                al_ustr_offset(us, i + 1)));
64          }
65       }
66       else {
67          al_draw_text(ex.myfont, color, x + 1 - j, y + 1 - j, 0, message);
68       }
69    }
70 }
71 
72 /* Create an example bitmap. */
create_example_bitmap(void)73 static ALLEGRO_BITMAP *create_example_bitmap(void)
74 {
75    ALLEGRO_BITMAP *bitmap;
76    int i, j;
77    ALLEGRO_LOCKED_REGION *locked;
78    unsigned char *data;
79 
80    bitmap = al_create_bitmap(100, 100);
81    locked = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY);
82    data = locked->data;
83 
84    for (j = 0; j < 100; j++) {
85       for (i = 0; i < 100; i++) {
86          int x = i - 50, y = j - 50;
87          int r = sqrt(x * x + y * y);
88          float rc = 1 - r / 50.0;
89          if (rc < 0)
90             rc = 0;
91          data[i * 4 + 0] = i * 255 / 100;
92          data[i * 4 + 1] = j * 255 / 100;
93          data[i * 4 + 2] = rc * 255;
94          data[i * 4 + 3] = rc * 255;
95       }
96       data += locked->pitch;
97    }
98    al_unlock_bitmap(bitmap);
99 
100    return bitmap;
101 }
102 
103 /* Draw our example scene. */
draw(void)104 static void draw(void)
105 {
106    ALLEGRO_COLOR test[5];
107    ALLEGRO_BITMAP *target = al_get_target_bitmap();
108 
109    char const *blend_names[] = {"ZERO", "ONE", "ALPHA", "INVERSE"};
110    char const *blend_vnames[] = {"ZERO", "ONE", "ALPHA", "INVER"};
111    int blend_modes[] = {ALLEGRO_ZERO, ALLEGRO_ONE, ALLEGRO_ALPHA,
112       ALLEGRO_INVERSE_ALPHA};
113    float x = 40, y = 40;
114    int i, j;
115 
116    al_clear_to_color(al_map_rgb_f(0.5, 0.5, 0.5));
117 
118    test[0] = al_map_rgba_f(1, 1, 1, 1);
119    test[1] = al_map_rgba_f(1, 1, 1, 0.5);
120    test[2] = al_map_rgba_f(1, 1, 1, 0.25);
121    test[3] = al_map_rgba_f(1, 0, 0, 0.75);
122    test[4] = al_map_rgba_f(0, 0, 0, 0);
123 
124    print(x, 0, false, "D  E  S  T  I  N  A  T  I  O  N  (%0.2f fps)", ex.fps);
125    print(0, y, true, "S O U R C E");
126    for (i = 0; i < 4; i++) {
127       print(x + i * 110, 20, false, blend_names[i]);
128       print(20, y + i * 110, true, blend_vnames[i]);
129    }
130 
131    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
132    if (ex.mode >= 1 && ex.mode <= 5) {
133       al_set_target_bitmap(ex.offscreen);
134       al_clear_to_color(test[ex.mode - 1]);
135    }
136    if (ex.mode >= 6 && ex.mode <= 10) {
137       al_set_target_bitmap(ex.memory);
138       al_clear_to_color(test[ex.mode - 6]);
139    }
140 
141    for (j = 0; j < 4; j++) {
142       for (i = 0; i < 4; i++) {
143          al_set_blender(ALLEGRO_ADD, blend_modes[j], blend_modes[i]);
144          if (ex.image == 0)
145             al_draw_bitmap(ex.example, x + i * 110, y + j * 110, 0);
146          else if (ex.image >= 1 && ex.image <= 6) {
147             al_draw_filled_rectangle(x + i * 110, y + j * 110,
148                x + i * 110 + 100, y + j * 110 + 100,
149                   test[ex.image - 1]);
150          }
151       }
152    }
153 
154    if (ex.mode >= 1 && ex.mode <= 5) {
155       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
156       al_set_target_bitmap(target);
157       al_draw_bitmap_region(ex.offscreen, x, y, 430, 430, x, y, 0);
158    }
159    if (ex.mode >= 6 && ex.mode <= 10) {
160       al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
161       al_set_target_bitmap(target);
162       al_draw_bitmap_region(ex.memory, x, y, 430, 430, x, y, 0);
163    }
164 
165    #define IS(x)  ((ex.image == x) ? "*" : " ")
166    print(ex.BUTTONS_X, 20 * 1, false, "What to draw");
167    print(ex.BUTTONS_X, 20 * 2, false, "%s Picture", IS(0));
168    print(ex.BUTTONS_X, 20 * 3, false, "%s Rec1 (1/1/1/1)", IS(1));
169    print(ex.BUTTONS_X, 20 * 4, false, "%s Rec2 (1/1/1/.5)", IS(2));
170    print(ex.BUTTONS_X, 20 * 5, false, "%s Rec3 (1/1/1/.25)", IS(3));
171    print(ex.BUTTONS_X, 20 * 6, false, "%s Rec4 (1/0/0/.75)", IS(4));
172    print(ex.BUTTONS_X, 20 * 7, false, "%s Rec5 (0/0/0/0)", IS(5));
173    #undef IS
174 
175    #define IS(x)  ((ex.mode == x) ? "*" : " ")
176    print(ex.BUTTONS_X, 20 * 9, false, "Where to draw");
177    print(ex.BUTTONS_X, 20 * 10, false, "%s screen", IS(0));
178 
179    print(ex.BUTTONS_X, 20 * 11, false, "%s offscreen1", IS(1));
180    print(ex.BUTTONS_X, 20 * 12, false, "%s offscreen2", IS(2));
181    print(ex.BUTTONS_X, 20 * 13, false, "%s offscreen3", IS(3));
182    print(ex.BUTTONS_X, 20 * 14, false, "%s offscreen4", IS(4));
183    print(ex.BUTTONS_X, 20 * 15, false, "%s offscreen5", IS(5));
184 
185    print(ex.BUTTONS_X, 20 * 16, false, "%s memory1", IS(6));
186    print(ex.BUTTONS_X, 20 * 17, false, "%s memory2", IS(7));
187    print(ex.BUTTONS_X, 20 * 18, false, "%s memory3", IS(8));
188    print(ex.BUTTONS_X, 20 * 19, false, "%s memory4", IS(9));
189    print(ex.BUTTONS_X, 20 * 20, false, "%s memory5", IS(10));
190    #undef IS
191 }
192 
193 /* Called a fixed amount of times per second. */
tick(void)194 static void tick(void)
195 {
196    /* Count frames during the last second or so. */
197    double t = al_get_time();
198    if (t >= ex.last_second + 1) {
199       ex.fps = ex.frames_accum / (t - ex.last_second);
200       ex.frames_accum = 0;
201       ex.last_second = t;
202    }
203 
204    draw();
205    al_flip_display();
206    ex.frames_accum++;
207 }
208 
209 /* Run our test. */
run(void)210 static void run(void)
211 {
212    ALLEGRO_EVENT event;
213    float x, y;
214    bool need_draw = true;
215 
216    while (1) {
217       /* Perform frame skipping so we don't fall behind the timer events. */
218       if (need_draw && al_is_event_queue_empty(ex.queue)) {
219          tick();
220          need_draw = false;
221       }
222 
223       al_wait_for_event(ex.queue, &event);
224 
225       switch (event.type) {
226          /* Was the X button on the window pressed? */
227          case ALLEGRO_EVENT_DISPLAY_CLOSE:
228             return;
229 
230          /* Was a key pressed? */
231          case ALLEGRO_EVENT_KEY_DOWN:
232             if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
233                return;
234             break;
235 
236          /* Is it time for the next timer tick? */
237          case ALLEGRO_EVENT_TIMER:
238             need_draw = true;
239             break;
240 
241          /* Mouse click? */
242          case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
243             x = event.mouse.x;
244             y = event.mouse.y;
245             if (x >= ex.BUTTONS_X) {
246                int button = y / 20;
247                if (button == 2) ex.image = 0;
248                if (button == 3) ex.image = 1;
249                if (button == 4) ex.image = 2;
250                if (button == 5) ex.image = 3;
251                if (button == 6) ex.image = 4;
252                if (button == 7) ex.image = 5;
253 
254                if (button == 10) ex.mode = 0;
255 
256                if (button == 11) ex.mode = 1;
257                if (button == 12) ex.mode = 2;
258                if (button == 13) ex.mode = 3;
259                if (button == 14) ex.mode = 4;
260                if (button == 15) ex.mode = 5;
261 
262                if (button == 16) ex.mode = 6;
263                if (button == 17) ex.mode = 7;
264                if (button == 18) ex.mode = 8;
265                if (button == 19) ex.mode = 9;
266                if (button == 20) ex.mode = 10;
267             }
268             break;
269       }
270    }
271 }
272 
273 /* Initialize the example. */
init(void)274 static void init(void)
275 {
276    ex.BUTTONS_X = 40 + 110 * 4;
277    ex.FPS = 60;
278 
279    ex.myfont = al_load_font("data/font.tga", 0, 0);
280    if (!ex.myfont) {
281       abort_example("data/font.tga not found\n");
282    }
283    ex.example = create_example_bitmap();
284 
285    ex.offscreen = al_create_bitmap(640, 480);
286    al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
287    ex.memory = al_create_bitmap(640, 480);
288 }
289 
main(int argc,char ** argv)290 int main(int argc, char **argv)
291 {
292    ALLEGRO_DISPLAY *display;
293    ALLEGRO_TIMER *timer;
294 
295    (void)argc;
296    (void)argv;
297 
298    if (!al_init()) {
299       abort_example("Could not init Allegro.\n");
300    }
301 
302    al_init_primitives_addon();
303    al_install_keyboard();
304    al_install_mouse();
305    al_install_touch_input();
306    al_init_image_addon();
307    al_init_font_addon();
308    init_platform_specific();
309 
310    display = al_create_display(640, 480);
311    if (!display) {
312       abort_example("Error creating display\n");
313    }
314 
315    init();
316 
317    timer = al_create_timer(1.0 / ex.FPS);
318 
319    ex.queue = al_create_event_queue();
320    al_register_event_source(ex.queue, al_get_keyboard_event_source());
321    al_register_event_source(ex.queue, al_get_mouse_event_source());
322    al_register_event_source(ex.queue, al_get_display_event_source(display));
323    al_register_event_source(ex.queue, al_get_timer_event_source(timer));
324    if (al_is_touch_input_installed()) {
325       al_register_event_source(ex.queue,
326          al_get_touch_input_mouse_emulation_event_source());
327    }
328 
329    al_start_timer(timer);
330    run();
331 
332    al_destroy_event_queue(ex.queue);
333 
334    return 0;
335 }
336