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