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