1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * New display driver.
12 *
13 * By Elias Pschernig.
14 *
15 * Modified by Trent Gamblin.
16 *
17 * See readme.txt for copyright information.
18 */
19
20 /* Title: Display routines
21 */
22
23
24
25 #include "allegro5/allegro.h"
26 #include "allegro5/internal/aintern.h"
27 #include "allegro5/internal/aintern_bitmap.h"
28 #include "allegro5/internal/aintern_display.h"
29 #include "allegro5/internal/aintern_shader.h"
30 #include "allegro5/internal/aintern_system.h"
31
32
33 ALLEGRO_DEBUG_CHANNEL("display")
34
35
36 /* Function: al_create_display
37 */
al_create_display(int w,int h)38 ALLEGRO_DISPLAY *al_create_display(int w, int h)
39 {
40 ALLEGRO_SYSTEM *system;
41 ALLEGRO_DISPLAY_INTERFACE *driver;
42 ALLEGRO_DISPLAY *display;
43 ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings;
44 int64_t flags;
45
46 system = al_get_system_driver();
47 driver = system->vt->get_display_driver();
48 if (!driver) {
49 ALLEGRO_ERROR("Failed to create display (no display driver)\n");
50 return NULL;
51 }
52
53 display = driver->create_display(w, h);
54 if (!display) {
55 ALLEGRO_ERROR("Failed to create display (NULL)\n");
56 return NULL;
57 }
58
59 ASSERT(display->vt);
60
61 settings = &display->extra_settings;
62 flags = settings->required | settings->suggested;
63 if (!(flags & (1 << ALLEGRO_AUTO_CONVERT_BITMAPS))) {
64 settings->settings[ALLEGRO_AUTO_CONVERT_BITMAPS] = 1;
65 }
66
67 display->min_w = 0;
68 display->min_h = 0;
69 display->max_w = 0;
70 display->max_h = 0;
71 display->use_constraints = false;
72 display->extra_resize_height = 0;
73
74 display->vertex_cache = 0;
75 display->num_cache_vertices = 0;
76 display->cache_enabled = false;
77 display->vertex_cache_size = 0;
78 display->cache_texture = 0;
79 al_identity_transform(&display->projview_transform);
80
81 display->default_shader = NULL;
82
83 _al_vector_init(&display->display_invalidated_callbacks, sizeof(void *));
84 _al_vector_init(&display->display_validated_callbacks, sizeof(void *));
85
86 display->render_state.write_mask = ALLEGRO_MASK_RGBA | ALLEGRO_MASK_DEPTH;
87 display->render_state.depth_test = false;
88 display->render_state.depth_function = ALLEGRO_RENDER_LESS;
89 display->render_state.alpha_test = false;
90 display->render_state.alpha_function = ALLEGRO_RENDER_ALWAYS;
91 display->render_state.alpha_test_value = 0;
92
93 _al_vector_init(&display->bitmaps, sizeof(ALLEGRO_BITMAP*));
94
95 if (settings->settings[ALLEGRO_COMPATIBLE_DISPLAY]) {
96 al_set_target_bitmap(al_get_backbuffer(display));
97 }
98 else {
99 ALLEGRO_DEBUG("ALLEGRO_COMPATIBLE_DISPLAY not set\n");
100 _al_set_current_display_only(display);
101 }
102
103 if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
104 display->default_shader = _al_create_default_shader(display->flags);
105 if (!display->default_shader) {
106 al_destroy_display(display);
107 return NULL;
108 }
109 al_use_shader(display->default_shader);
110 }
111
112 /* Clear the screen */
113 if (settings->settings[ALLEGRO_COMPATIBLE_DISPLAY]) {
114 al_clear_to_color(al_map_rgb(0, 0, 0));
115
116 /* TODO:
117 * on iphone, don't kill the initial splashscreen - in fact, it's also
118 * annoying in linux to have an extra black frame as first frame and I
119 * suppose we never really want it
120 */
121 #if 0
122 al_flip_display();
123 #endif
124 }
125
126 if (settings->settings[ALLEGRO_AUTO_CONVERT_BITMAPS]) {
127 /* We convert video bitmaps to memory bitmaps when the display is
128 * destroyed, so seems only fair to re-convertt hem when the
129 * display is re-created again.
130 */
131 al_convert_memory_bitmaps();
132 }
133
134 return display;
135 }
136
137
138
139 /* Function: al_destroy_display
140 */
al_destroy_display(ALLEGRO_DISPLAY * display)141 void al_destroy_display(ALLEGRO_DISPLAY *display)
142 {
143 if (display) {
144 /* This causes warnings and potential errors on Android because
145 * it clears the context and Android needs this thread to have
146 * the context bound in its destroy function and to destroy the
147 * shader. Just skip this part on Android.
148 */
149 #ifndef ALLEGRO_ANDROID
150 ALLEGRO_BITMAP *bmp;
151
152 bmp = al_get_target_bitmap();
153 if (bmp && _al_get_bitmap_display(bmp) == display)
154 al_set_target_bitmap(NULL);
155
156 /* This can happen if we have a current display, but the target bitmap
157 * was a memory bitmap.
158 */
159 if (display == al_get_current_display())
160 _al_set_current_display_only(NULL);
161 #endif
162
163 al_destroy_shader(display->default_shader);
164 display->default_shader = NULL;
165
166 ASSERT(display->vt);
167 display->vt->destroy_display(display);
168 }
169 }
170
171
172
173 /* Function: al_get_backbuffer
174 */
al_get_backbuffer(ALLEGRO_DISPLAY * display)175 ALLEGRO_BITMAP *al_get_backbuffer(ALLEGRO_DISPLAY *display)
176 {
177 if (display) {
178 ASSERT(display->vt);
179 return display->vt->get_backbuffer(display);
180 }
181 return NULL;
182 }
183
184
185
186 /* Function: al_flip_display
187 */
al_flip_display(void)188 void al_flip_display(void)
189 {
190 ALLEGRO_DISPLAY *display = al_get_current_display();
191
192 if (display) {
193 ASSERT(display->vt);
194 display->vt->flip_display(display);
195 }
196 }
197
198
199
200 /* Function: al_update_display_region
201 */
al_update_display_region(int x,int y,int width,int height)202 void al_update_display_region(int x, int y, int width, int height)
203 {
204 ALLEGRO_DISPLAY *display = al_get_current_display();
205
206 if (display) {
207 ASSERT(display->vt);
208 display->vt->update_display_region(display, x, y, width, height);
209 }
210 }
211
212
213
214 /* Function: al_acknowledge_resize
215 */
al_acknowledge_resize(ALLEGRO_DISPLAY * display)216 bool al_acknowledge_resize(ALLEGRO_DISPLAY *display)
217 {
218 ASSERT(display);
219 ASSERT(display->vt);
220
221 if (!(display->flags & ALLEGRO_FULLSCREEN)) {
222 if (display->vt->acknowledge_resize) {
223 return display->vt->acknowledge_resize(display);
224 }
225 }
226 return false;
227 }
228
229
230
231 /* Function: al_resize_display
232 */
al_resize_display(ALLEGRO_DISPLAY * display,int width,int height)233 bool al_resize_display(ALLEGRO_DISPLAY *display, int width, int height)
234 {
235 ASSERT(display);
236 ASSERT(display->vt);
237
238 ALLEGRO_INFO("Requested display resize %dx%d+%d\n", width, height, display->extra_resize_height);
239
240 if (display->vt->resize_display) {
241 return display->vt->resize_display(display, width, height + display->extra_resize_height);
242 }
243 return false;
244 }
245
246
247
248 /* Function: al_is_compatible_bitmap
249 */
al_is_compatible_bitmap(ALLEGRO_BITMAP * bitmap)250 bool al_is_compatible_bitmap(ALLEGRO_BITMAP *bitmap)
251 {
252 ALLEGRO_DISPLAY *display = al_get_current_display();
253 ASSERT(bitmap);
254
255 if (display) {
256 ASSERT(display->vt);
257 return display->vt->is_compatible_bitmap(display, bitmap);
258 }
259
260 return false;
261 }
262
263
264
265 /* Function: al_get_display_width
266 */
al_get_display_width(ALLEGRO_DISPLAY * display)267 int al_get_display_width(ALLEGRO_DISPLAY *display)
268 {
269 ASSERT(display);
270
271 return display->w;
272 }
273
274
275
276 /* Function: al_get_display_height
277 */
al_get_display_height(ALLEGRO_DISPLAY * display)278 int al_get_display_height(ALLEGRO_DISPLAY *display)
279 {
280 ASSERT(display);
281
282 return display->h;
283 }
284
285
286 /* Function: al_get_display_format
287 */
al_get_display_format(ALLEGRO_DISPLAY * display)288 int al_get_display_format(ALLEGRO_DISPLAY *display)
289 {
290 ASSERT(display);
291
292 return display->backbuffer_format;
293 }
294
295
296 /* Function: al_get_display_refresh_rate
297 */
al_get_display_refresh_rate(ALLEGRO_DISPLAY * display)298 int al_get_display_refresh_rate(ALLEGRO_DISPLAY *display)
299 {
300 ASSERT(display);
301
302 return display->refresh_rate;
303 }
304
305
306
307 /* Function: al_get_display_flags
308 */
al_get_display_flags(ALLEGRO_DISPLAY * display)309 int al_get_display_flags(ALLEGRO_DISPLAY *display)
310 {
311 ASSERT(display);
312
313 return display->flags;
314 }
315
316
317 /* Function: al_get_display_orientation
318 */
al_get_display_orientation(ALLEGRO_DISPLAY * display)319 int al_get_display_orientation(ALLEGRO_DISPLAY* display)
320 {
321 if (display && display->vt->get_orientation)
322 return display->vt->get_orientation(display);
323 else
324 return ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN;
325 }
326
327
328 /* Function: al_wait_for_vsync
329 */
al_wait_for_vsync(void)330 bool al_wait_for_vsync(void)
331 {
332 ALLEGRO_DISPLAY *display = al_get_current_display();
333 ASSERT(display);
334
335 if (display->vt->wait_for_vsync)
336 return display->vt->wait_for_vsync(display);
337 else
338 return false;
339 }
340
341
342
343 /* Function: al_set_display_icon
344 */
al_set_display_icon(ALLEGRO_DISPLAY * display,ALLEGRO_BITMAP * icon)345 void al_set_display_icon(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *icon)
346 {
347 ALLEGRO_BITMAP *icons[1] = { icon };
348
349 al_set_display_icons(display, 1, icons);
350 }
351
352
353
354 /* Function: al_set_display_icons
355 */
al_set_display_icons(ALLEGRO_DISPLAY * display,int num_icons,ALLEGRO_BITMAP * icons[])356 void al_set_display_icons(ALLEGRO_DISPLAY *display,
357 int num_icons, ALLEGRO_BITMAP *icons[])
358 {
359 int i;
360
361 ASSERT(display);
362 ASSERT(num_icons >= 1);
363 ASSERT(icons);
364 for (i = 0; i < num_icons; i++) {
365 ASSERT(icons[i]);
366 }
367
368 if (display->vt->set_icons) {
369 display->vt->set_icons(display, num_icons, icons);
370 }
371 }
372
373 /* Function: al_set_window_position
374 */
al_set_window_position(ALLEGRO_DISPLAY * display,int x,int y)375 void al_set_window_position(ALLEGRO_DISPLAY *display, int x, int y)
376 {
377 ASSERT(display);
378
379 if (display && display->flags & ALLEGRO_FULLSCREEN) {
380 return;
381 }
382
383 if (display && display->vt && display->vt->set_window_position) {
384 display->vt->set_window_position(display, x, y);
385 }
386 }
387
388
389 /* Function: al_get_window_position
390 */
al_get_window_position(ALLEGRO_DISPLAY * display,int * x,int * y)391 void al_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y)
392 {
393 ASSERT(x);
394 ASSERT(y);
395
396 if (display && display->vt && display->vt->get_window_position) {
397 display->vt->get_window_position(display, x, y);
398 }
399 else {
400 *x = *y = -1;
401 }
402 }
403
404
405 /* Function: al_set_window_constraints
406 */
al_set_window_constraints(ALLEGRO_DISPLAY * display,int min_w,int min_h,int max_w,int max_h)407 bool al_set_window_constraints(ALLEGRO_DISPLAY *display,
408 int min_w, int min_h, int max_w, int max_h)
409 {
410 ASSERT(display);
411
412 /* Perform some basic checks. */
413 if (min_w < 0 || min_h < 0 || max_w < 0 || max_h < 0) {
414 return false;
415 }
416 if (min_w > 0 && max_w > 0 && max_w < min_w) {
417 return false;
418 }
419 if (min_h > 0 && max_h > 0 && max_h < min_h) {
420 return false;
421 }
422
423 /* Cannot constrain when fullscreen. */
424 if (display->flags & ALLEGRO_FULLSCREEN) {
425 return false;
426 }
427
428 /* Cannot constrain if not resizable. */
429 if (!(display->flags & ALLEGRO_RESIZABLE)) {
430 return false;
431 }
432
433 if (display && display->vt && display->vt->set_window_constraints) {
434 return display->vt->set_window_constraints(display, min_w, min_h,
435 max_w, max_h);
436 }
437 else {
438 return false;
439 }
440 }
441
442
443 /* Function: al_get_window_constraints
444 */
al_get_window_constraints(ALLEGRO_DISPLAY * display,int * min_w,int * min_h,int * max_w,int * max_h)445 bool al_get_window_constraints(ALLEGRO_DISPLAY *display,
446 int *min_w, int *min_h, int *max_w, int *max_h)
447 {
448 ASSERT(display);
449 ASSERT(min_w);
450 ASSERT(min_h);
451 ASSERT(max_w);
452 ASSERT(max_h);
453
454 if (display && display->vt && display->vt->get_window_constraints) {
455 return display->vt->get_window_constraints(display, min_w, min_h,
456 max_w, max_h);
457 }
458 else {
459 return false;
460 }
461 }
462
463
464 /* Function: al_set_display_flag
465 */
al_set_display_flag(ALLEGRO_DISPLAY * display,int flag,bool onoff)466 bool al_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff)
467 {
468 ASSERT(display);
469
470 if (display && display->vt && display->vt->set_display_flag) {
471 return display->vt->set_display_flag(display, flag, onoff);
472 }
473 return false;
474 }
475
476
477 /* Function: al_set_window_title
478 */
al_set_window_title(ALLEGRO_DISPLAY * display,const char * title)479 void al_set_window_title(ALLEGRO_DISPLAY *display, const char *title)
480 {
481 if (display && display->vt && display->vt->set_window_title)
482 display->vt->set_window_title(display, title);
483 }
484
485
486 /* Function: al_get_display_event_source
487 */
al_get_display_event_source(ALLEGRO_DISPLAY * display)488 ALLEGRO_EVENT_SOURCE *al_get_display_event_source(ALLEGRO_DISPLAY *display)
489 {
490 return &display->es;
491 }
492
493 /* Function: al_hold_bitmap_drawing
494 */
al_hold_bitmap_drawing(bool hold)495 void al_hold_bitmap_drawing(bool hold)
496 {
497 ALLEGRO_DISPLAY *current_display = al_get_current_display();
498
499 if (current_display) {
500 if (hold && !current_display->cache_enabled) {
501 /*
502 * Set the hardware transformation to identity, but keep the bitmap
503 * transform the same as it was. Relies on the fact that when bitmap
504 * holding is turned on, al_use_transform does not update the hardware
505 * transformation.
506 */
507 ALLEGRO_TRANSFORM old, ident;
508 al_copy_transform(&old, al_get_current_transform());
509 al_identity_transform(&ident);
510
511 al_use_transform(&ident);
512 current_display->cache_enabled = hold;
513 al_use_transform(&old);
514 }
515 else {
516 current_display->cache_enabled = hold;
517 }
518
519 if (!hold) {
520 current_display->vt->flush_vertex_cache(current_display);
521 /*
522 * Reset the hardware transform to match the stored transform.
523 */
524 al_use_transform(al_get_current_transform());
525 }
526 }
527 }
528
529 /* Function: al_is_bitmap_drawing_held
530 */
al_is_bitmap_drawing_held(void)531 bool al_is_bitmap_drawing_held(void)
532 {
533 ALLEGRO_DISPLAY *current_display = al_get_current_display();
534
535 if (current_display)
536 return current_display->cache_enabled;
537 else
538 return false;
539 }
540
_al_add_display_invalidated_callback(ALLEGRO_DISPLAY * display,void (* display_invalidated)(ALLEGRO_DISPLAY *))541 void _al_add_display_invalidated_callback(ALLEGRO_DISPLAY* display, void (*display_invalidated)(ALLEGRO_DISPLAY*))
542 {
543 if (_al_vector_find(&display->display_invalidated_callbacks, display_invalidated) >= 0) {
544 return;
545 }
546 else {
547 void (**callback)(ALLEGRO_DISPLAY *) = _al_vector_alloc_back(&display->display_invalidated_callbacks);
548 *callback = display_invalidated;
549 }
550 }
551
_al_add_display_validated_callback(ALLEGRO_DISPLAY * display,void (* display_validated)(ALLEGRO_DISPLAY *))552 void _al_add_display_validated_callback(ALLEGRO_DISPLAY* display, void (*display_validated)(ALLEGRO_DISPLAY*))
553 {
554 if (_al_vector_find(&display->display_validated_callbacks, display_validated) >= 0) {
555 return;
556 }
557 else {
558 void (**callback)(ALLEGRO_DISPLAY *) = _al_vector_alloc_back(&display->display_validated_callbacks);
559 *callback = display_validated;
560 }
561 }
562
_al_remove_display_invalidated_callback(ALLEGRO_DISPLAY * display,void (* callback)(ALLEGRO_DISPLAY *))563 void _al_remove_display_invalidated_callback(ALLEGRO_DISPLAY *display, void (*callback)(ALLEGRO_DISPLAY *))
564 {
565 _al_vector_find_and_delete(&display->display_invalidated_callbacks, &callback);
566 }
567
_al_remove_display_validated_callback(ALLEGRO_DISPLAY * display,void (* callback)(ALLEGRO_DISPLAY *))568 void _al_remove_display_validated_callback(ALLEGRO_DISPLAY *display, void (*callback)(ALLEGRO_DISPLAY *))
569 {
570 _al_vector_find_and_delete(&display->display_validated_callbacks, &callback);
571 }
572
573 /* Function: al_acknowledge_drawing_halt
574 */
al_acknowledge_drawing_halt(ALLEGRO_DISPLAY * display)575 void al_acknowledge_drawing_halt(ALLEGRO_DISPLAY *display)
576 {
577 if (display->vt->acknowledge_drawing_halt) {
578 display->vt->acknowledge_drawing_halt(display);
579 }
580 }
581
582 /* Function: al_acknowledge_drawing_resume
583 */
al_acknowledge_drawing_resume(ALLEGRO_DISPLAY * display)584 void al_acknowledge_drawing_resume(ALLEGRO_DISPLAY *display)
585 {
586 if (display->vt->acknowledge_drawing_resume) {
587 display->vt->acknowledge_drawing_resume(display);
588 }
589 }
590
591 /* Function: al_set_render_state
592 */
al_set_render_state(ALLEGRO_RENDER_STATE state,int value)593 void al_set_render_state(ALLEGRO_RENDER_STATE state, int value)
594 {
595 ALLEGRO_DISPLAY *display = al_get_current_display();
596
597 if (!display)
598 return;
599
600 switch (state) {
601 case ALLEGRO_ALPHA_TEST:
602 display->render_state.alpha_test = value;
603 break;
604 case ALLEGRO_WRITE_MASK:
605 display->render_state.write_mask = value;
606 break;
607 case ALLEGRO_DEPTH_TEST:
608 display->render_state.depth_test = value;
609 break;
610 case ALLEGRO_DEPTH_FUNCTION:
611 display->render_state.depth_function = value;
612 break;
613 case ALLEGRO_ALPHA_FUNCTION:
614 display->render_state.alpha_function = value;
615 break;
616 case ALLEGRO_ALPHA_TEST_VALUE:
617 display->render_state.alpha_test_value = value;
618 break;
619 default:
620 ALLEGRO_WARN("unknown state to change: %d\n", state);
621 break;
622 }
623
624 if (display->vt && display->vt->update_render_state) {
625 display->vt->update_render_state(display);
626 }
627 }
628
629 /* Function: al_backup_dirty_bitmaps
630 */
al_backup_dirty_bitmaps(ALLEGRO_DISPLAY * display)631 void al_backup_dirty_bitmaps(ALLEGRO_DISPLAY *display)
632 {
633 unsigned int i;
634
635 for (i = 0; i < display->bitmaps._size; i++) {
636 ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&display->bitmaps, i);
637 ALLEGRO_BITMAP *bmp = *bptr;
638 if (_al_get_bitmap_display(bmp) == display) {
639 if (bmp->vt && bmp->vt->backup_dirty_bitmap) {
640 bmp->vt->backup_dirty_bitmap(bmp);
641 }
642 }
643 }
644 }
645
646 /* Function: al_apply_window_constraints
647 */
al_apply_window_constraints(ALLEGRO_DISPLAY * display,bool onoff)648 void al_apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff)
649 {
650 display->use_constraints = onoff;
651
652 if (display->vt && display->vt->apply_window_constraints)
653 display->vt->apply_window_constraints(display, onoff);
654 }
655
656 /* vim: set sts=3 sw=3 et: */
657