1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Graphics mode set and bitmap creation routines.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include <string.h>
20 
21 #include "allegro.h"
22 #include "allegro/internal/aintern.h"
23 
24 extern void blit_end(void);   /* for LOCK_FUNCTION; defined in blit.c */
25 
26 
27 
28 #define PREFIX_I                "al-gfx INFO: "
29 #define PREFIX_W                "al-gfx WARNING: "
30 #define PREFIX_E                "al-gfx ERROR: "
31 
32 
33 
34 static int gfx_virgin = TRUE;          /* is the graphics system active? */
35 
36 int _sub_bitmap_id_count = 1;          /* hash value for sub-bitmaps */
37 
38 int _gfx_mode_set_count = 0;           /* has the graphics mode changed? */
39 
40 int _screen_split_position = 0;        /* has the screen been split? */
41 
42 int _safe_gfx_mode_change = 0;         /* are we getting through GFX_SAFE? */
43 
44 RGB_MAP *rgb_map = NULL;               /* RGB -> palette entry conversion */
45 
46 COLOR_MAP *color_map = NULL;           /* translucency/lighting table */
47 
48 int _color_depth = 8;                  /* how many bits per pixel? */
49 
50 int _refresh_rate_request = 0;         /* requested refresh rate */
51 static int current_refresh_rate = 0;   /* refresh rate set by the driver */
52 
53 int _wait_for_vsync = TRUE;            /* vsync when page-flipping? */
54 
55 int _color_conv = COLORCONV_TOTAL;     /* which formats to auto convert? */
56 
57 static int color_conv_set = FALSE;     /* has the user set conversion mode? */
58 
59 int _palette_color8[256];               /* palette -> pixel mapping */
60 int _palette_color15[256];
61 int _palette_color16[256];
62 int _palette_color24[256];
63 int _palette_color32[256];
64 
65 int *palette_color = _palette_color8;
66 
67 BLENDER_FUNC _blender_func15 = NULL;   /* truecolor pixel blender routines */
68 BLENDER_FUNC _blender_func16 = NULL;
69 BLENDER_FUNC _blender_func24 = NULL;
70 BLENDER_FUNC _blender_func32 = NULL;
71 
72 BLENDER_FUNC _blender_func15x = NULL;
73 BLENDER_FUNC _blender_func16x = NULL;
74 BLENDER_FUNC _blender_func24x = NULL;
75 
76 int _blender_col_15 = 0;               /* for truecolor lit sprites */
77 int _blender_col_16 = 0;
78 int _blender_col_24 = 0;
79 int _blender_col_32 = 0;
80 
81 int _blender_alpha = 0;                /* for truecolor translucent drawing */
82 
83 int _rgb_r_shift_15 = DEFAULT_RGB_R_SHIFT_15;     /* truecolor pixel format */
84 int _rgb_g_shift_15 = DEFAULT_RGB_G_SHIFT_15;
85 int _rgb_b_shift_15 = DEFAULT_RGB_B_SHIFT_15;
86 int _rgb_r_shift_16 = DEFAULT_RGB_R_SHIFT_16;
87 int _rgb_g_shift_16 = DEFAULT_RGB_G_SHIFT_16;
88 int _rgb_b_shift_16 = DEFAULT_RGB_B_SHIFT_16;
89 int _rgb_r_shift_24 = DEFAULT_RGB_R_SHIFT_24;
90 int _rgb_g_shift_24 = DEFAULT_RGB_G_SHIFT_24;
91 int _rgb_b_shift_24 = DEFAULT_RGB_B_SHIFT_24;
92 int _rgb_r_shift_32 = DEFAULT_RGB_R_SHIFT_32;
93 int _rgb_g_shift_32 = DEFAULT_RGB_G_SHIFT_32;
94 int _rgb_b_shift_32 = DEFAULT_RGB_B_SHIFT_32;
95 int _rgb_a_shift_32 = DEFAULT_RGB_A_SHIFT_32;
96 
97 
98 /* lookup table for scaling 5 bit colors up to 8 bits */
99 int _rgb_scale_5[32] =
100 {
101    0,   8,   16,  24,  33,  41,  49,  57,
102    66,  74,  82,  90,  99,  107, 115, 123,
103    132, 140, 148, 156, 165, 173, 181, 189,
104    198, 206, 214, 222, 231, 239, 247, 255
105 };
106 
107 
108 /* lookup table for scaling 6 bit colors up to 8 bits */
109 int _rgb_scale_6[64] =
110 {
111    0,   4,   8,   12,  16,  20,  24,  28,
112    32,  36,  40,  44,  48,  52,  56,  60,
113    65,  69,  73,  77,  81,  85,  89,  93,
114    97,  101, 105, 109, 113, 117, 121, 125,
115    130, 134, 138, 142, 146, 150, 154, 158,
116    162, 166, 170, 174, 178, 182, 186, 190,
117    195, 199, 203, 207, 211, 215, 219, 223,
118    227, 231, 235, 239, 243, 247, 251, 255
119 };
120 
121 
122 GFX_VTABLE _screen_vtable;             /* accelerated drivers change this */
123 
124 
125 typedef struct VRAM_BITMAP             /* list of video memory bitmaps */
126 {
127    int x, y, w, h;
128    BITMAP *bmp;
129    struct VRAM_BITMAP *next_x, *next_y;
130 } VRAM_BITMAP;
131 
132 
133 static VRAM_BITMAP *vram_bitmap_list = NULL;
134 
135 
136 #define BMP_MAX_SIZE  46340   /* sqrt(INT_MAX) */
137 
138 /* the product of these must fit in an int */
139 static int failed_bitmap_w = BMP_MAX_SIZE;
140 static int failed_bitmap_h = BMP_MAX_SIZE;
141 
142 
143 
144 static int _set_gfx_mode(int card, int w, int h, int v_w, int v_h, int allow_config);
145 static int _set_gfx_mode_safe(int card, int w, int h, int v_w, int v_h);
146 
147 
148 
149 /* lock_bitmap:
150  *  Locks all the memory used by a bitmap structure.
151  */
lock_bitmap(BITMAP * bmp)152 void lock_bitmap(BITMAP *bmp)
153 {
154    LOCK_DATA(bmp, sizeof(BITMAP) + sizeof(char *) * bmp->h);
155 
156    if (bmp->dat) {
157       LOCK_DATA(bmp->dat, bmp->w * bmp->h * BYTES_PER_PIXEL(bitmap_color_depth(bmp)));
158    }
159 }
160 
161 
162 
163 /* request_refresh_rate:
164  *  Requests that the next call to set_gfx_mode() use the specified refresh
165  *  rate.
166  */
request_refresh_rate(int rate)167 void request_refresh_rate(int rate)
168 {
169    _refresh_rate_request = rate;
170 }
171 
172 
173 
174 /* get_refresh_rate:
175  *  Returns the refresh rate set by the most recent call to set_gfx_mode().
176  */
get_refresh_rate(void)177 int get_refresh_rate(void)
178 {
179    return current_refresh_rate;
180 }
181 
182 
183 
184 /* _set_current_refresh_rate:
185  *  Sets the current refresh rate.
186  *  (This function must be called by the gfx drivers)
187  */
_set_current_refresh_rate(int rate)188 void _set_current_refresh_rate(int rate)
189 {
190    /* sanity check to discard bogus values */
191    if ((rate<40) || (rate>200))
192       rate = 0;
193 
194    current_refresh_rate = rate;
195 
196    /* adjust retrace speed */
197    _vsync_speed = rate ? BPS_TO_TIMER(rate) : BPS_TO_TIMER(70);
198 }
199 
200 
201 
202 /* sort_gfx_mode_list:
203  *  Callback for quick-sorting a mode-list.
204  */
sort_gfx_mode_list(GFX_MODE * entry1,GFX_MODE * entry2)205 static int sort_gfx_mode_list(GFX_MODE *entry1, GFX_MODE *entry2)
206 {
207    if (entry1->width > entry2->width) {
208       return +1;
209    }
210    else if (entry1->width < entry2->width) {
211       return -1;
212    }
213    else {
214       if (entry1->height > entry2->height) {
215          return +1;
216       }
217       else if (entry1->height < entry2->height) {
218          return -1;
219       }
220       else {
221          if (entry1->bpp > entry2->bpp) {
222             return +1;
223          }
224          else if (entry1->bpp < entry2->bpp) {
225             return -1;
226          }
227          else {
228             return 0;
229          }
230       }
231    }
232 }
233 
234 
235 
236 /* get_gfx_mode_list:
237  *  Attempts to create a list of all the supported video modes for a certain
238  *  GFX driver.
239  */
get_gfx_mode_list(int card)240 GFX_MODE_LIST *get_gfx_mode_list(int card)
241 {
242    _DRIVER_INFO *list_entry;
243    GFX_DRIVER *drv = NULL;
244    GFX_MODE_LIST *gfx_mode_list = NULL;
245 
246    ASSERT(system_driver);
247 
248    /* ask the system driver for a list of graphics hardware drivers */
249    if (system_driver->gfx_drivers)
250       list_entry = system_driver->gfx_drivers();
251    else
252       list_entry = _gfx_driver_list;
253 
254    /* find the graphics driver, and if it can fetch mode lists, do so */
255    while (list_entry->driver) {
256       if (list_entry->id == card) {
257          drv = list_entry->driver;
258          if (!drv->fetch_mode_list)
259             return NULL;
260 
261          gfx_mode_list = drv->fetch_mode_list();
262          if (!gfx_mode_list)
263             return NULL;
264 
265          break;
266       }
267 
268       list_entry++;
269    }
270 
271    if (!drv)
272       return NULL;
273 
274    /* sort the list and finish */
275    qsort(gfx_mode_list->mode, gfx_mode_list->num_modes, sizeof(GFX_MODE),
276          (int (*) (AL_CONST void *, AL_CONST void *))sort_gfx_mode_list);
277 
278    return gfx_mode_list;
279 }
280 
281 
282 
283 /* destroy_gfx_mode_list:
284  *  Removes the mode list created by get_gfx_mode_list() from memory.
285  */
destroy_gfx_mode_list(GFX_MODE_LIST * gfx_mode_list)286 void destroy_gfx_mode_list(GFX_MODE_LIST *gfx_mode_list)
287 {
288    if (gfx_mode_list) {
289       if (gfx_mode_list->mode)
290          _AL_FREE(gfx_mode_list->mode);
291 
292       _AL_FREE(gfx_mode_list);
293    }
294 }
295 
296 
297 
298 /* set_color_depth:
299  *  Sets the pixel size (in bits) which will be used by subsequent calls to
300  *  set_gfx_mode() and create_bitmap(). Valid depths are 8, 15, 16, 24 and 32.
301  */
set_color_depth(int depth)302 void set_color_depth(int depth)
303 {
304    _color_depth = depth;
305 
306    switch (depth) {
307       case 8:  palette_color = _palette_color8;  break;
308       case 15: palette_color = _palette_color15; break;
309       case 16: palette_color = _palette_color16; break;
310       case 24: palette_color = _palette_color24; break;
311       case 32: palette_color = _palette_color32; break;
312       default: ASSERT(FALSE);
313    }
314 }
315 
316 
317 
318 /* get_color_depth:
319  *  Returns the current color depth.
320  */
get_color_depth(void)321 int get_color_depth(void)
322 {
323    return _color_depth;
324 }
325 
326 
327 
328 /* set_color_conversion:
329  *  Sets a bit mask specifying which types of color format conversions are
330  *  valid when loading data from disk.
331  */
set_color_conversion(int mode)332 void set_color_conversion(int mode)
333 {
334    _color_conv = mode;
335 
336    color_conv_set = TRUE;
337 }
338 
339 
340 
341 /* get_color_conversion:
342  *  Returns the bitmask specifying which types of color format
343  *  conversion are valid when loading data from disk.
344  */
get_color_conversion(void)345 int get_color_conversion(void)
346 {
347    return _color_conv;
348 }
349 
350 
351 
352 /* _color_load_depth:
353  *  Works out which color depth an image should be loaded as, given the
354  *  current conversion mode.
355  */
_color_load_depth(int depth,int hasalpha)356 int _color_load_depth(int depth, int hasalpha)
357 {
358    typedef struct CONVERSION_FLAGS
359    {
360       int flag;
361       int in_depth;
362       int out_depth;
363       int hasalpha;
364    } CONVERSION_FLAGS;
365 
366    static CONVERSION_FLAGS conversion_flags[] =
367    {
368       { COLORCONV_8_TO_15,   8,  15, FALSE },
369       { COLORCONV_8_TO_16,   8,  16, FALSE },
370       { COLORCONV_8_TO_24,   8,  24, FALSE },
371       { COLORCONV_8_TO_32,   8,  32, FALSE },
372       { COLORCONV_15_TO_8,   15, 8,  FALSE },
373       { COLORCONV_15_TO_16,  15, 16, FALSE },
374       { COLORCONV_15_TO_24,  15, 24, FALSE },
375       { COLORCONV_15_TO_32,  15, 32, FALSE },
376       { COLORCONV_16_TO_8,   16, 8,  FALSE },
377       { COLORCONV_16_TO_15,  16, 15, FALSE },
378       { COLORCONV_16_TO_24,  16, 24, FALSE },
379       { COLORCONV_16_TO_32,  16, 32, FALSE },
380       { COLORCONV_24_TO_8,   24, 8,  FALSE },
381       { COLORCONV_24_TO_15,  24, 15, FALSE },
382       { COLORCONV_24_TO_16,  24, 16, FALSE },
383       { COLORCONV_24_TO_32,  24, 32, FALSE },
384       { COLORCONV_32_TO_8,   32, 8,  FALSE },
385       { COLORCONV_32_TO_15,  32, 15, FALSE },
386       { COLORCONV_32_TO_16,  32, 16, FALSE },
387       { COLORCONV_32_TO_24,  32, 24, FALSE },
388       { COLORCONV_32A_TO_8,  32, 8 , TRUE  },
389       { COLORCONV_32A_TO_15, 32, 15, TRUE  },
390       { COLORCONV_32A_TO_16, 32, 16, TRUE  },
391       { COLORCONV_32A_TO_24, 32, 24, TRUE  }
392    };
393 
394    int i;
395 
396    ASSERT((_gfx_mode_set_count > 0) || (color_conv_set));
397 
398    if (depth == _color_depth)
399       return depth;
400 
401    for (i=0; i < (int)(sizeof(conversion_flags)/sizeof(CONVERSION_FLAGS)); i++) {
402       if ((conversion_flags[i].in_depth == depth) &&
403 	  (conversion_flags[i].out_depth == _color_depth) &&
404 	  ((conversion_flags[i].hasalpha != 0) == (hasalpha != 0))) {
405 	 if (_color_conv & conversion_flags[i].flag)
406 	    return _color_depth;
407 	 else
408 	    return depth;
409       }
410    }
411 
412    ASSERT(FALSE);
413    return 0;
414 }
415 
416 
417 
418 /* _get_vtable:
419  *  Returns a pointer to the linear vtable for the specified color depth.
420  */
_get_vtable(int color_depth)421 GFX_VTABLE *_get_vtable(int color_depth)
422 {
423    GFX_VTABLE *vt;
424    int i;
425 
426    ASSERT(system_driver);
427 
428    if (system_driver->get_vtable) {
429       vt = system_driver->get_vtable(color_depth);
430 
431       if (vt) {
432 	 LOCK_DATA(vt, sizeof(GFX_VTABLE));
433 	 LOCK_CODE(vt->draw_sprite, (long)vt->draw_sprite_end - (long)vt->draw_sprite);
434 	 LOCK_CODE(vt->blit_from_memory, (long)vt->blit_end - (long)vt->blit_from_memory);
435 	 return vt;
436       }
437    }
438 
439    for (i=0; _vtable_list[i].vtable; i++) {
440       if (_vtable_list[i].color_depth == color_depth) {
441 	 LOCK_DATA(_vtable_list[i].vtable, sizeof(GFX_VTABLE));
442 	 LOCK_CODE(_vtable_list[i].vtable->draw_sprite, (long)_vtable_list[i].vtable->draw_sprite_end - (long)_vtable_list[i].vtable->draw_sprite);
443 	 LOCK_CODE(_vtable_list[i].vtable->blit_from_memory, (long)_vtable_list[i].vtable->blit_end - (long)_vtable_list[i].vtable->blit_from_memory);
444 	 return _vtable_list[i].vtable;
445       }
446    }
447 
448    return NULL;
449 }
450 
451 
452 
453 /* shutdown_gfx:
454  *  Used by allegro_exit() to return the system to text mode.
455  */
shutdown_gfx(void)456 static void shutdown_gfx(void)
457 {
458    if (gfx_driver)
459       set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
460 
461    if (system_driver->restore_console_state)
462       system_driver->restore_console_state();
463 
464    _remove_exit_func(shutdown_gfx);
465 
466    gfx_virgin = TRUE;
467 }
468 
469 
470 #define GFX_DRIVER_FULLSCREEN_FLAG    0x01
471 #define GFX_DRIVER_WINDOWED_FLAG      0x02
472 
473 
474 /* gfx_driver_is_valid:
475  *  Checks that the graphics driver 'drv' fulfills the condition
476  *  expressed by the bitmask 'flags'.
477  */
gfx_driver_is_valid(GFX_DRIVER * drv,int flags)478 static int gfx_driver_is_valid(GFX_DRIVER *drv, int flags)
479 {
480    if ((flags & GFX_DRIVER_FULLSCREEN_FLAG) && drv->windowed)
481       return FALSE;
482 
483    if ((flags & GFX_DRIVER_WINDOWED_FLAG) && !drv->windowed)
484       return FALSE;
485 
486    return TRUE;
487 }
488 
489 
490 
491 /* get_gfx_driver_from_id:
492  *  Retrieves a pointer to the graphics driver identified by 'card' from
493  *  the list 'driver_list' or NULL if it doesn't exist.
494  */
get_gfx_driver_from_id(int card,_DRIVER_INFO * driver_list)495 static GFX_DRIVER *get_gfx_driver_from_id(int card, _DRIVER_INFO *driver_list)
496 {
497    int c;
498 
499    for (c=0; driver_list[c].driver; c++) {
500       if (driver_list[c].id == card)
501 	 return driver_list[c].driver;
502    }
503 
504    return NULL;
505 }
506 
507 
508 
509 /* init_gfx_driver:
510  *  Helper function for initializing a graphics driver.
511  */
init_gfx_driver(GFX_DRIVER * drv,int w,int h,int v_w,int v_h)512 static BITMAP *init_gfx_driver(GFX_DRIVER *drv, int w, int h, int v_w, int v_h)
513 {
514    drv->name = drv->desc = get_config_text(drv->ascii_name);
515 
516    /* set gfx_driver so that it is visible when initializing the driver */
517    gfx_driver = drv;
518 
519    return drv->init(w, h, v_w, v_h, _color_depth);
520 }
521 
522 
523 
524 /* get_config_gfx_driver:
525  *  Helper function for set_gfx_mode: it reads the gfx_card* config variables and
526  *  tries to set the graphics mode if a matching driver is found. Returns TRUE if
527  *  at least one matching driver was found, FALSE otherwise.
528  */
get_config_gfx_driver(char * gfx_card,int w,int h,int v_w,int v_h,int flags,_DRIVER_INFO * driver_list)529 static int get_config_gfx_driver(char *gfx_card, int w, int h, int v_w, int v_h, int flags, _DRIVER_INFO *driver_list)
530 {
531    char buf[512], tmp[64];
532    GFX_DRIVER *drv;
533    int found = FALSE;
534    int card, n;
535 
536    /* try the drivers that are listed in the config file */
537    for (n=-2; n<255; n++) {
538       switch (n) {
539 
540 	 case -2:
541 	    /* example: gfx_card_640x480x16 = */
542 	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dx%dx%d", tmp), gfx_card, w, h, _color_depth);
543 	    break;
544 
545 	 case -1:
546 	    /* example: gfx_card_24bpp = */
547 	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dbpp", tmp), gfx_card, _color_depth);
548 	    break;
549 
550 	 case 0:
551 	    /* example: gfx_card = */
552 	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s", tmp), gfx_card);
553 	    break;
554 
555 	 default:
556 	    /* example: gfx_card1 = */
557 	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s%d", tmp), gfx_card, n);
558 	    break;
559       }
560 
561       card = get_config_id(uconvert_ascii("graphics", tmp), buf, 0);
562 
563       if (card) {
564 	 drv = get_gfx_driver_from_id(card, driver_list);
565 
566 	 if (drv && gfx_driver_is_valid(drv, flags)) {
567 	    found = TRUE;
568 	    screen = init_gfx_driver(drv, w, h, v_w, v_h);
569 
570 	    if (screen)
571 	       break;
572 	 }
573       }
574       else {
575 	 /* Stop searching the gfx_card#n (n>0) family at the first missing member,
576 	  * except gfx_card1 which could have been identified with gfx_card.
577 	  */
578 	 if (n > 1)
579 	    break;
580       }
581    }
582 
583    return found;
584 }
585 
586 
587 
588 /* set_gfx_mode:
589  *  Sets the graphics mode. The card should be one of the GFX_* constants
590  *  from allegro.h, or GFX_AUTODETECT to accept any graphics driver. Pass
591  *  GFX_TEXT to return to text mode (although allegro_exit() will usually
592  *  do this for you). The w and h parameters specify the screen resolution
593  *  you want, and v_w and v_h specify the minumum virtual screen size.
594  *  The graphics drivers may actually create a much larger virtual screen,
595  *  so you should check the values of VIRTUAL_W and VIRTUAL_H after you
596  *  set the mode. If unable to select an appropriate mode, this function
597  *  returns -1.
598  */
set_gfx_mode(int card,int w,int h,int v_w,int v_h)599 int set_gfx_mode(int card, int w, int h, int v_w, int v_h)
600 {
601    TRACE(PREFIX_I "Called set_gfx_mode(%d, %d, %d, %d, %d).\n",
602 	 card, w, h, v_w, v_h);
603 
604    /* TODO: shouldn't this be incremented only IF successful? */
605    _gfx_mode_set_count++;
606 
607    /* special bodge for the GFX_SAFE driver */
608    if (card == GFX_SAFE)
609       return _set_gfx_mode_safe(card, w, h, v_w, v_h);
610    else
611       return _set_gfx_mode(card, w, h, v_w, v_h, TRUE);
612 }
613 
614 
615 
616 /* _set_gfx_mode:
617  *  Called by set_gfx_mode(). Separated to make a clear difference between
618  *  the virtual GFX_SAFE driver and the rest. The allow_config parameter,
619  *  if true, allows the configuration to override the graphics card/driver
620  *  when using GFX_AUTODETECT.
621  */
_set_gfx_mode(int card,int w,int h,int v_w,int v_h,int allow_config)622 static int _set_gfx_mode(int card, int w, int h, int v_w, int v_h, int allow_config)
623 {
624    _DRIVER_INFO *driver_list;
625    GFX_DRIVER *drv;
626    char tmp1[64], tmp2[64];
627    AL_CONST char *dv;
628    int flags = 0;
629    int c;
630    ASSERT(system_driver);
631    ASSERT(card != GFX_SAFE);
632 
633    /* remember the current console state */
634    if (gfx_virgin) {
635       TRACE(PREFIX_I "First call, remembering console state.\n");
636       LOCK_FUNCTION(_stub_bank_switch);
637       LOCK_FUNCTION(blit);
638 
639       if (system_driver->save_console_state)
640 	 system_driver->save_console_state();
641 
642       _add_exit_func(shutdown_gfx, "shutdown_gfx");
643 
644       gfx_virgin = FALSE;
645    }
646 
647    timer_simulate_retrace(FALSE);
648    _screen_split_position = 0;
649 
650    /* close down any existing graphics driver */
651    if (gfx_driver) {
652       TRACE(PREFIX_I "Closing graphics driver (%p) ", gfx_driver);
653       TRACE("%s.\n", gfx_driver->ascii_name);
654       if (_al_linker_mouse)
655          _al_linker_mouse->show_mouse(NULL);
656 
657       while (vram_bitmap_list)
658 	 destroy_bitmap(vram_bitmap_list->bmp);
659 
660       bmp_read_line(screen, 0);
661       bmp_write_line(screen, 0);
662       bmp_unwrite_line(screen);
663 
664       if (gfx_driver->scroll)
665 	 gfx_driver->scroll(0, 0);
666 
667       if (gfx_driver->exit)
668 	 gfx_driver->exit(screen);
669 
670       destroy_bitmap(screen);
671 
672       gfx_driver = NULL;
673       screen = NULL;
674       gfx_capabilities = 0;
675    }
676 
677    /* We probably don't want to do this because it makes
678     * Allegro "forget" the color layout of previously set
679     * graphics modes. But it should be retained if bitmaps
680     * created in those modes are to be used in the new mode.
681     */
682 #if 0
683    /* restore default truecolor pixel format */
684    _rgb_r_shift_15 = 0;
685    _rgb_g_shift_15 = 5;
686    _rgb_b_shift_15 = 10;
687    _rgb_r_shift_16 = 0;
688    _rgb_g_shift_16 = 5;
689    _rgb_b_shift_16 = 11;
690    _rgb_r_shift_24 = 0;
691    _rgb_g_shift_24 = 8;
692    _rgb_b_shift_24 = 16;
693    _rgb_r_shift_32 = 0;
694    _rgb_g_shift_32 = 8;
695    _rgb_b_shift_32 = 16;
696    _rgb_a_shift_32 = 24;
697 #endif
698 
699    gfx_capabilities = 0;
700 
701    _set_current_refresh_rate(0);
702 
703    /* return to text mode? */
704    if (card == GFX_TEXT) {
705       TRACE(PREFIX_I "Closing, restoring original console state.\n");
706       if (system_driver->restore_console_state)
707 	 system_driver->restore_console_state();
708 
709       if (_gfx_bank) {
710 	 _AL_FREE(_gfx_bank);
711 	 _gfx_bank = NULL;
712       }
713 
714       TRACE(PREFIX_I "Graphic mode closed.\n");
715       return 0;
716    }
717 
718    /* now to the interesting part: let's try to find a graphics driver */
719    usetc(allegro_error, 0);
720 
721    /* ask the system driver for a list of graphics hardware drivers */
722    if (system_driver->gfx_drivers)
723       driver_list = system_driver->gfx_drivers();
724    else
725       driver_list = _gfx_driver_list;
726 
727    /* filter specific fullscreen/windowed driver requests */
728    if (card == GFX_AUTODETECT_FULLSCREEN) {
729       flags |= GFX_DRIVER_FULLSCREEN_FLAG;
730       card = GFX_AUTODETECT;
731    }
732    else if (card == GFX_AUTODETECT_WINDOWED) {
733       flags |= GFX_DRIVER_WINDOWED_FLAG;
734       card = GFX_AUTODETECT;
735    }
736 
737    if (card == GFX_AUTODETECT) {
738       /* autodetect the driver */
739       int found = FALSE;
740 
741       tmp1[0] = '\0';
742 
743       /* first try the config variables */
744       if (allow_config) {
745 	 /* try the gfx_card variable if GFX_AUTODETECT or GFX_AUTODETECT_FULLSCREEN was selected */
746 	 if (!(flags & GFX_DRIVER_WINDOWED_FLAG))
747 	    found = get_config_gfx_driver(uconvert_ascii("gfx_card", tmp1), w, h, v_w, v_h, flags, driver_list);
748 
749 	 /* try the gfx_cardw variable if GFX_AUTODETECT or GFX_AUTODETECT_WINDOWED was selected */
750 	 if (!(flags & GFX_DRIVER_FULLSCREEN_FLAG) && !found)
751 	    found = get_config_gfx_driver(uconvert_ascii("gfx_cardw", tmp1), w, h, v_w, v_h, flags, driver_list);
752       }
753 
754       /* go through the list of autodetected drivers if none was previously found */
755       if (!found) {
756 	 TRACE(PREFIX_I "Autodetecting graphic driver.\n");
757 	 for (c=0; driver_list[c].driver; c++) {
758 	    if (driver_list[c].autodetect) {
759 	       drv = driver_list[c].driver;
760 
761 	       if (gfx_driver_is_valid(drv, flags)) {
762 		  screen = init_gfx_driver(drv, w, h, v_w, v_h);
763 
764 		  if (screen)
765 		     break;
766 	       }
767 	    }
768 	 }
769       }
770       else {
771 	 TRACE(PREFIX_I "GFX_AUTODETECT overridden through configuration:"
772 	       " %s.\n", tmp1);
773       }
774    }
775    else {
776       /* search the list for the requested driver */
777       drv = get_gfx_driver_from_id(card, driver_list);
778 
779       if (drv)
780 	 screen = init_gfx_driver(drv, w, h, v_w, v_h);
781    }
782 
783    /* gracefully handle failure */
784    if (!screen) {
785       gfx_driver = NULL;  /* set by init_gfx_driver() */
786 
787       if (!ugetc(allegro_error))
788 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to find a suitable graphics driver"));
789 
790       TRACE(PREFIX_E "Failed setting graphic driver %d.\n", card);
791       return -1;
792    }
793 
794    /* set the basic capabilities of the driver */
795    if ((VIRTUAL_W > SCREEN_W) || (VIRTUAL_H > SCREEN_H)) {
796       if (gfx_driver->scroll)
797 	 gfx_capabilities |= GFX_CAN_SCROLL;
798 
799       if ((gfx_driver->request_scroll) || (gfx_driver->request_video_bitmap))
800 	 gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
801    }
802 
803    /* check whether we are instructed to disable vsync */
804    dv = get_config_string(uconvert_ascii("graphics", tmp1),
805                           uconvert_ascii("disable_vsync", tmp2),
806                           NULL);
807 
808    if ((dv) && ((c = ugetc(dv)) != 0) && ((c == 'y') || (c == 'Y') || (c == '1')))
809       _wait_for_vsync = FALSE;
810    else
811       _wait_for_vsync = TRUE;
812 
813    TRACE(PREFIX_I "The driver %s wait for vsync.\n",
814 	 (_wait_for_vsync) ? "will" : "won't");
815 
816    /* Give the gfx driver an opportunity to set the drawing mode */
817    if ((gfx_driver->drawing_mode) && (!_dispsw_status))
818       gfx_driver->drawing_mode();
819 
820    clear_bitmap(screen);
821 
822    /* set up the default colors */
823    for (c=0; c<256; c++)
824       _palette_color8[c] = c;
825 
826    set_palette(default_palette);
827 
828    if (_color_depth == 8) {
829       gui_fg_color = 255;
830       gui_mg_color = 8;
831       gui_bg_color = 0;
832    }
833    else {
834       gui_fg_color = makecol(0, 0, 0);
835       gui_mg_color = makecol(128, 128, 128);
836       gui_bg_color = makecol(255, 255, 255);
837    }
838 
839    if (_al_linker_mouse)
840       _al_linker_mouse->set_mouse_etc();
841 
842    LOCK_DATA(gfx_driver, sizeof(GFX_DRIVER));
843 
844    _register_switch_bitmap(screen, NULL);
845 
846    TRACE(PREFIX_I "set_gfx_card success for %dx%dx%d.\n",
847 	 screen->w, screen->h, bitmap_color_depth(screen));
848    return 0;
849 }
850 
851 
852 
853 /* _set_gfx_mode_safe:
854  *  Special wrapper used when the card parameter of set_gfx_mode()
855  *  is GFX_SAFE. In this case the function tries to query the
856  *  system driver for a "safe" resolution+driver it knows it will
857  *  work, and set it. If the system driver cannot get a "safe"
858  *  resolution+driver, it will try the given parameters.
859  */
_set_gfx_mode_safe(int card,int w,int h,int v_w,int v_h)860 static int _set_gfx_mode_safe(int card, int w, int h, int v_w, int v_h)
861 {
862    char buf[ALLEGRO_ERROR_SIZE], tmp1[64];
863    struct GFX_MODE mode;
864    int ret, driver;
865 
866    ASSERT(card == GFX_SAFE);
867    ASSERT(system_driver);
868    TRACE(PREFIX_I "Trying to set a safe graphics mode.\n");
869 
870    if (system_driver->get_gfx_safe_mode) {
871       ustrzcpy(buf, sizeof(buf), allegro_error);
872 
873       /* retrieve the safe graphics mode */
874       system_driver->get_gfx_safe_mode(&driver, &mode);
875       TRACE(PREFIX_I "The system driver suggests %dx%dx%d\n",
876 	    mode.width, mode.height, mode.bpp);
877 
878       /* try using the specified resolution but current depth */
879       if (_set_gfx_mode(driver, w, h, 0, 0, TRUE) == 0)
880          return 0;
881 
882       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, buf);
883 
884       /* finally use the safe settings */
885       set_color_depth(mode.bpp);
886       if (_set_gfx_mode(driver, mode.width, mode.height, 0, 0, TRUE) == 0)
887          return 0;
888 
889       ASSERT(FALSE);  /* the safe graphics mode must always work */
890    }
891    else {
892       TRACE(PREFIX_W "The system driver was unable to get a safe mode, "
893 	    "I'll try with the specified parameters...\n");
894       /* no safe graphics mode, try hard-coded autodetected modes with
895        * custom settings */
896       _safe_gfx_mode_change = 1;
897 
898       ret = _set_gfx_mode(GFX_AUTODETECT, w, h, 0, 0, TRUE);
899 
900       _safe_gfx_mode_change = 0;
901 
902       if (ret == 0)
903          return 0;
904    }
905 
906    /* failing to set GFX_SAFE is a fatal error */
907    TRACE(PREFIX_E "Bad bad, not even GFX_SAFE works?\n");
908    _set_gfx_mode(GFX_TEXT, 0, 0, 0, 0, TRUE);
909    allegro_message(uconvert_ascii("%s\n", tmp1),
910 		   get_config_text("Fatal error: unable to set GFX_SAFE"));
911    return -1;
912 }
913 
914 
915 
916 /* _sort_out_virtual_width:
917  *  Decides how wide the virtual screen really needs to be. That is more
918  *  complicated than it sounds, because the Allegro graphics primitives
919  *  require that each scanline be contained within a single bank. That
920  *  causes problems on cards that don't have overlapping banks, unless the
921  *  bank size is a multiple of the virtual width. So we may need to adjust
922  *  the width just to keep things running smoothly...
923  */
_sort_out_virtual_width(int * width,GFX_DRIVER * driver)924 void _sort_out_virtual_width(int *width, GFX_DRIVER *driver)
925 {
926    int w = *width;
927 
928    /* hah! I love VBE 2.0... */
929    if (driver->linear)
930       return;
931 
932    /* if banks can overlap, we are ok... */
933    if (driver->bank_size > driver->bank_gran)
934       return;
935 
936    /* damn, have to increase the virtual width */
937    while (((driver->bank_size / w) * w) != driver->bank_size) {
938       w++;
939       if (w > driver->bank_size)
940 	 break; /* oh shit */
941    }
942 
943    *width = w;
944 }
945 
946 
947 
948 /* _make_bitmap:
949  *  Helper function for creating the screen bitmap. Sets up a bitmap
950  *  structure for addressing video memory at addr, and fills the bank
951  *  switching table using bank size/granularity information from the
952  *  specified graphics driver.
953  */
_make_bitmap(int w,int h,uintptr_t addr,GFX_DRIVER * driver,int color_depth,int bpl)954 BITMAP *_make_bitmap(int w, int h, uintptr_t addr, GFX_DRIVER *driver, int color_depth, int bpl)
955 {
956    GFX_VTABLE *vtable = _get_vtable(color_depth);
957    int i, bank, size;
958    BITMAP *b;
959 
960    if (!vtable)
961       return NULL;
962 
963    size = sizeof(BITMAP) + sizeof(char *) * h;
964 
965    b = (BITMAP *)_AL_MALLOC(size);
966    if (!b)
967       return NULL;
968 
969    _gfx_bank = _AL_REALLOC(_gfx_bank, h * sizeof(int));
970    if (!_gfx_bank) {
971       _AL_FREE(b);
972       return NULL;
973    }
974 
975    LOCK_DATA(b, size);
976    LOCK_DATA(_gfx_bank, h * sizeof(int));
977 
978    b->w = b->cr = w;
979    b->h = b->cb = h;
980    b->clip = TRUE;
981    b->cl = b->ct = 0;
982    b->vtable = &_screen_vtable;
983    b->write_bank = b->read_bank = _stub_bank_switch;
984    b->dat = NULL;
985    b->id = BMP_ID_VIDEO;
986    b->extra = NULL;
987    b->x_ofs = 0;
988    b->y_ofs = 0;
989    b->seg = _video_ds();
990 
991    memcpy(&_screen_vtable, vtable, sizeof(GFX_VTABLE));
992    LOCK_DATA(&_screen_vtable, sizeof(GFX_VTABLE));
993 
994    _last_bank_1 = _last_bank_2 = -1;
995 
996    driver->vid_phys_base = addr;
997 
998    b->line[0] = (unsigned char *)addr;
999    _gfx_bank[0] = 0;
1000 
1001    if (driver->linear) {
1002       for (i=1; i<h; i++) {
1003 	 b->line[i] = b->line[i-1] + bpl;
1004 	 _gfx_bank[i] = 0;
1005       }
1006    }
1007    else {
1008       bank = 0;
1009 
1010       for (i=1; i<h; i++) {
1011 	 b->line[i] = b->line[i-1] + bpl;
1012 	 if (b->line[i]+bpl-1 >= (unsigned char *)addr + driver->bank_size) {
1013 	    while (b->line[i] >= (unsigned char *)addr + driver->bank_gran) {
1014 	       b->line[i] -= driver->bank_gran;
1015 	       bank++;
1016 	    }
1017 	 }
1018 	 _gfx_bank[i] = bank;
1019       }
1020    }
1021 
1022    return b;
1023 }
1024 
1025 
1026 
1027 /* create_bitmap_ex
1028  *  Creates a new memory bitmap in the specified color_depth
1029  */
create_bitmap_ex(int color_depth,int width,int height)1030 BITMAP *create_bitmap_ex(int color_depth, int width, int height)
1031 {
1032    GFX_VTABLE *vtable;
1033    BITMAP *bitmap;
1034    int nr_pointers;
1035    int padding;
1036    int i;
1037 
1038    ASSERT(width >= 0);
1039    ASSERT(height > 0);
1040    ASSERT(system_driver);
1041 
1042    if (system_driver->create_bitmap)
1043       return system_driver->create_bitmap(color_depth, width, height);
1044 
1045    vtable = _get_vtable(color_depth);
1046    if (!vtable)
1047       return NULL;
1048 
1049    /* We need at least two pointers when drawing, otherwise we get crashes with
1050     * Electric Fence.  We think some of the assembly code assumes a second line
1051     * pointer is always available.
1052     */
1053    nr_pointers = MAX(2, height);
1054    bitmap = _AL_MALLOC(sizeof(BITMAP) + (sizeof(char *) * nr_pointers));
1055    if (!bitmap)
1056       return NULL;
1057 
1058    /* This avoids a crash for assembler code accessing the last pixel, as it
1059     * read 4 bytes instead of 3.
1060     */
1061    padding = (color_depth == 24) ? 1 : 0;
1062 
1063    bitmap->dat = _AL_MALLOC_ATOMIC(width * height * BYTES_PER_PIXEL(color_depth) + padding);
1064    if (!bitmap->dat) {
1065       _AL_FREE(bitmap);
1066       return NULL;
1067    }
1068 
1069    bitmap->w = bitmap->cr = width;
1070    bitmap->h = bitmap->cb = height;
1071    bitmap->clip = TRUE;
1072    bitmap->cl = bitmap->ct = 0;
1073    bitmap->vtable = vtable;
1074    bitmap->write_bank = bitmap->read_bank = _stub_bank_switch;
1075    bitmap->id = 0;
1076    bitmap->extra = NULL;
1077    bitmap->x_ofs = 0;
1078    bitmap->y_ofs = 0;
1079    bitmap->seg = _default_ds();
1080 
1081    if (height > 0) {
1082       bitmap->line[0] = bitmap->dat;
1083       for (i=1; i<height; i++)
1084          bitmap->line[i] = bitmap->line[i-1] + width * BYTES_PER_PIXEL(color_depth);
1085    }
1086 
1087    if (system_driver->created_bitmap)
1088       system_driver->created_bitmap(bitmap);
1089 
1090    return bitmap;
1091 }
1092 
1093 
1094 
1095 /* create_bitmap:
1096  *  Creates a new memory bitmap.
1097  */
create_bitmap(int width,int height)1098 BITMAP *create_bitmap(int width, int height)
1099 {
1100    ASSERT(width >= 0);
1101    ASSERT(height > 0);
1102    return create_bitmap_ex(_color_depth, width, height);
1103 }
1104 
1105 
1106 
1107 /* create_sub_bitmap:
1108  *  Creates a sub bitmap, ie. a bitmap sharing drawing memory with a
1109  *  pre-existing bitmap, but possibly with different clipping settings.
1110  *  Usually will be smaller, and positioned at some arbitrary point.
1111  *
1112  *  Mark Wodrich is the owner of the brain responsible this hugely useful
1113  *  and beautiful function.
1114  */
create_sub_bitmap(BITMAP * parent,int x,int y,int width,int height)1115 BITMAP *create_sub_bitmap(BITMAP *parent, int x, int y, int width, int height)
1116 {
1117    BITMAP *bitmap;
1118    int nr_pointers;
1119    int i;
1120 
1121    ASSERT(parent);
1122    ASSERT((x >= 0) && (y >= 0) && (x < parent->w) && (y < parent->h));
1123    ASSERT((width > 0) && (height > 0));
1124    ASSERT(system_driver);
1125 
1126    if (x+width > parent->w)
1127       width = parent->w-x;
1128 
1129    if (y+height > parent->h)
1130       height = parent->h-y;
1131 
1132    if (parent->vtable->create_sub_bitmap)
1133       return parent->vtable->create_sub_bitmap(parent, x, y, width, height);
1134 
1135    if (system_driver->create_sub_bitmap)
1136       return system_driver->create_sub_bitmap(parent, x, y, width, height);
1137 
1138    /* get memory for structure and line pointers */
1139    /* (see create_bitmap for the reason we need at least two) */
1140    nr_pointers = MAX(2, height);
1141    bitmap = _AL_MALLOC(sizeof(BITMAP) + (sizeof(char *) * nr_pointers));
1142    if (!bitmap)
1143       return NULL;
1144 
1145    acquire_bitmap(parent);
1146 
1147    bitmap->w = bitmap->cr = width;
1148    bitmap->h = bitmap->cb = height;
1149    bitmap->clip = TRUE;
1150    bitmap->cl = bitmap->ct = 0;
1151    bitmap->vtable = parent->vtable;
1152    bitmap->write_bank = parent->write_bank;
1153    bitmap->read_bank = parent->read_bank;
1154    bitmap->dat = NULL;
1155    bitmap->extra = NULL;
1156    bitmap->x_ofs = x + parent->x_ofs;
1157    bitmap->y_ofs = y + parent->y_ofs;
1158    bitmap->seg = parent->seg;
1159 
1160    /* All bitmaps are created with zero ID's. When a sub-bitmap is created,
1161     * a unique ID is needed to identify the relationship when blitting from
1162     * one to the other. This is obtained from the global variable
1163     * _sub_bitmap_id_count, which provides a sequence of integers (yes I
1164     * know it will wrap eventually, but not for a long time :-) If the
1165     * parent already has an ID the sub-bitmap adopts it, otherwise a new
1166     * ID is given to both the parent and the child.
1167     */
1168    if (!(parent->id & BMP_ID_MASK)) {
1169       parent->id |= _sub_bitmap_id_count;
1170       _sub_bitmap_id_count = (_sub_bitmap_id_count+1) & BMP_ID_MASK;
1171    }
1172 
1173    bitmap->id = parent->id | BMP_ID_SUB;
1174    bitmap->id &= ~BMP_ID_LOCKED;
1175 
1176    if (is_planar_bitmap(bitmap))
1177       x /= 4;
1178 
1179    x *= BYTES_PER_PIXEL(bitmap_color_depth(bitmap));
1180 
1181    /* setup line pointers: each line points to a line in the parent bitmap */
1182    for (i=0; i<height; i++)
1183       bitmap->line[i] = parent->line[y+i] + x;
1184 
1185    if (bitmap->vtable->set_clip)
1186       bitmap->vtable->set_clip(bitmap);
1187 
1188    if (parent->vtable->created_sub_bitmap)
1189       parent->vtable->created_sub_bitmap(bitmap, parent);
1190 
1191    if (system_driver->created_sub_bitmap)
1192       system_driver->created_sub_bitmap(bitmap, parent);
1193 
1194    if (parent->id & BMP_ID_VIDEO)
1195       _register_switch_bitmap(bitmap, parent);
1196 
1197    release_bitmap(parent);
1198 
1199    return bitmap;
1200 }
1201 
1202 
1203 
1204 /* add_vram_block:
1205  *  Creates a video memory bitmap out of the specified region
1206  *  of the larger screen surface, returning a pointer to it.
1207  */
add_vram_block(int x,int y,int w,int h)1208 static BITMAP *add_vram_block(int x, int y, int w, int h)
1209 {
1210    VRAM_BITMAP *b, *new_b;
1211    VRAM_BITMAP **last_p;
1212 
1213    new_b = _AL_MALLOC(sizeof(VRAM_BITMAP));
1214    if (!new_b)
1215       return NULL;
1216 
1217    new_b->x = x;
1218    new_b->y = y;
1219    new_b->w = w;
1220    new_b->h = h;
1221 
1222    new_b->bmp = create_sub_bitmap(screen, x, y, w, h);
1223    if (!new_b->bmp) {
1224       _AL_FREE(new_b);
1225       return NULL;
1226    }
1227 
1228    /* find sorted y-position */
1229    last_p = &vram_bitmap_list;
1230    for (b = vram_bitmap_list; b && (b->y < new_b->y); b = b->next_y)
1231       last_p = &b->next_y;
1232 
1233    /* insert */
1234    *last_p = new_b;
1235    new_b->next_y = b;
1236 
1237    return new_b->bmp;
1238 }
1239 
1240 
1241 
1242 /* create_video_bitmap:
1243  *  Attempts to make a bitmap object for accessing offscreen video memory.
1244  *
1245  *  The algorithm is similar to algorithms for drawing polygons. Think of
1246  *  a horizontal stripe whose height is equal to that of the new bitmap.
1247  *  It is initially aligned to the top of video memory and then it moves
1248  *  downwards, stopping each time its top coincides with the bottom of a
1249  *  video bitmap. For each stop, create a list of video bitmaps intersecting
1250  *  the stripe, sorted by the left coordinate, from left to right, in the
1251  *  next_x linked list. We look through this list and stop as soon as the
1252  *  gap between the rightmost right edge seen so far and the current left
1253  *  edge is big enough for the new video bitmap. In that case, we are done.
1254  *  If we don't find such a gap, we move the stripe further down.
1255  *
1256  *  To make it efficient to find new bitmaps intersecting the stripe, the
1257  *  list of all bitmaps is always sorted by top, from top to bottom, in
1258  *  the next_y linked list. The list of bitmaps intersecting the stripe is
1259  *  merely updated, not recalculated from scratch, when we move the stripe.
1260  *  So every bitmap gets bubbled to its correct sorted x-position at most
1261  *  once. Bubbling a bitmap takes at most as many steps as the number of
1262  *  video bitmaps. So the algorithm behaves at most quadratically with
1263  *  regard to the number of video bitmaps. I think that a linear behaviour
1264  *  is more typical in practical applications (this happens, for instance,
1265  *  if you allocate many bitmaps of the same height).
1266  *
1267  *  There's one more optimization: if a call fails, we cache the size of the
1268  *  requested bitmap, so that next time we can detect very quickly that this
1269  *  size is too large (this needs to be maintained when destroying bitmaps).
1270  */
create_video_bitmap(int width,int height)1271 BITMAP *create_video_bitmap(int width, int height)
1272 {
1273    VRAM_BITMAP *active_list, *b, *vram_bitmap;
1274    VRAM_BITMAP **last_p;
1275    BITMAP *bmp;
1276    int x = 0, y = 0;
1277 
1278    ASSERT(width >= 0);
1279    ASSERT(height > 0);
1280 
1281    if (_dispsw_status)
1282       return NULL;
1283 
1284    /* let the driver handle the request if it can */
1285    if (gfx_driver->create_video_bitmap) {
1286       bmp = gfx_driver->create_video_bitmap(width, height);
1287       if (!bmp)
1288 	 return NULL;
1289 
1290       b = _AL_MALLOC(sizeof(VRAM_BITMAP));
1291       b->x = -1;
1292       b->y = -1;
1293       b->w = 0;
1294       b->h = 0;
1295       b->bmp = bmp;
1296       b->next_y = vram_bitmap_list;
1297       vram_bitmap_list = b;
1298 
1299       return bmp;
1300    }
1301 
1302    /* check bad args */
1303    if ((width > VIRTUAL_W) || (height > VIRTUAL_H) ||
1304        (width < 0) || (height < 0))
1305       return NULL;
1306 
1307    /* check cached bitmap size */
1308    if ((width >= failed_bitmap_w) && (height >= failed_bitmap_h))
1309       return NULL;
1310 
1311    vram_bitmap = vram_bitmap_list;
1312    active_list = NULL;
1313    y = 0;
1314 
1315    while (TRUE) {
1316       /* Move the blocks from the VRAM_BITMAP_LIST that intersect the
1317        * stripe to the ACTIVE_LIST: look through the VRAM_BITMAP_LIST
1318        * following the next_y link, grow the ACTIVE_LIST following
1319        * the next_x link and sorting by x-position.
1320        * (this loop runs in amortized quadratic time)
1321        */
1322       while (vram_bitmap && (vram_bitmap->y < y+height)) {
1323 	 /* find sorted x-position */
1324 	 last_p = &active_list;
1325 	 for (b = active_list; b && (vram_bitmap->x > b->x); b = b->next_x)
1326 	    last_p = &b->next_x;
1327 
1328 	 /* insert */
1329 	 *last_p = vram_bitmap;
1330 	 vram_bitmap->next_x = b;
1331 
1332 	 /* next video bitmap */
1333 	 vram_bitmap = vram_bitmap->next_y;
1334       }
1335 
1336       x = 0;
1337 
1338       /* Look for holes to put our bitmap in.
1339        * (this loop runs in quadratic time)
1340        */
1341       for (b = active_list; b; b = b->next_x) {
1342 	 if (x+width <= b->x)  /* hole is big enough? */
1343 	    return add_vram_block(x, y, width, height);
1344 
1345          /* Move search x-position to the right edge of the
1346           * skipped bitmap if we are not already past it.
1347           * And check there is enough room before continuing.
1348           */
1349 	 if (x < b->x + b->w) {
1350 	    x = (b->x + b->w + 15) & ~15;
1351 	    if (x+width > VIRTUAL_W)
1352 	       break;
1353 	 }
1354       }
1355 
1356       /* If the whole ACTIVE_LIST was scanned, there is a big
1357        * enough hole to the right of the rightmost bitmap.
1358        */
1359       if (b == NULL)
1360 	 return add_vram_block(x, y, width, height);
1361 
1362       /* Move search y-position to the topmost bottom edge
1363        * of the bitmaps intersecting the stripe.
1364        * (this loop runs in quadratic time)
1365        */
1366       y = active_list->y + active_list->h;
1367       for (b = active_list->next_x; b; b = b->next_x) {
1368 	 if (y > b->y + b->h)
1369 	    y = b->y + b->h;
1370       }
1371 
1372       if (y+height > VIRTUAL_H) {  /* too close to bottom? */
1373 	 /* Before failing, cache this bitmap size so that later calls can
1374 	  * learn from it. Use area as a measure to sort the bitmap sizes.
1375           */
1376 	 if (width * height < failed_bitmap_w * failed_bitmap_h) {
1377 	    failed_bitmap_w = width;
1378 	    failed_bitmap_h = height;
1379 	 }
1380 
1381 	 return NULL;
1382       }
1383 
1384       /* Remove the blocks that don't intersect the new stripe from ACTIVE_LIST.
1385        * (this loop runs in quadratic time)
1386        */
1387       last_p = &active_list;
1388       for (b = active_list; b; b = b->next_x) {
1389 	 if (y >= b->y + b->h)
1390 	    *last_p = b->next_x;
1391 	 else
1392 	    last_p = &b->next_x;
1393       }
1394    }
1395 }
1396 
1397 
1398 
1399 /* create_system_bitmap:
1400  *  Attempts to make a system-specific (eg. DirectX surface) bitmap object.
1401  */
create_system_bitmap(int width,int height)1402 BITMAP *create_system_bitmap(int width, int height)
1403 {
1404    BITMAP *bmp;
1405 
1406    ASSERT(width >= 0);
1407    ASSERT(height > 0);
1408    ASSERT(gfx_driver != NULL);
1409 
1410    if (gfx_driver->create_system_bitmap)
1411       return gfx_driver->create_system_bitmap(width, height);
1412 
1413    bmp = create_bitmap(width, height);
1414 
1415    return bmp;
1416 }
1417 
1418 
1419 
1420 /* destroy_bitmap:
1421  *  Destroys a memory bitmap.
1422  */
destroy_bitmap(BITMAP * bitmap)1423 void destroy_bitmap(BITMAP *bitmap)
1424 {
1425    VRAM_BITMAP *prev, *pos;
1426 
1427    if (bitmap) {
1428       if (is_video_bitmap(bitmap)) {
1429 	 /* special case for getting rid of video memory bitmaps */
1430 	 ASSERT(!_dispsw_status);
1431 
1432 	 prev = NULL;
1433 	 pos = vram_bitmap_list;
1434 
1435 	 while (pos) {
1436 	    if (pos->bmp == bitmap) {
1437 	       if (prev)
1438 		  prev->next_y = pos->next_y;
1439 	       else
1440 		  vram_bitmap_list = pos->next_y;
1441 
1442 	       if (pos->x < 0) {
1443 		  /* the driver is in charge of this object */
1444 		  gfx_driver->destroy_video_bitmap(bitmap);
1445 		  _AL_FREE(pos);
1446 		  return;
1447 	       }
1448 
1449 	       /* Update cached bitmap size using worst case scenario:
1450 		* the bitmap lies between two holes whose size is the cached
1451 		* size on each axis respectively.
1452 		*/
1453 	       failed_bitmap_w = failed_bitmap_w * 2 + ((bitmap->w + 15) & ~15);
1454 	       if (failed_bitmap_w > BMP_MAX_SIZE)
1455 		  failed_bitmap_w = BMP_MAX_SIZE;
1456 
1457 	       failed_bitmap_h = failed_bitmap_h * 2 + bitmap->h;
1458 	       if (failed_bitmap_h > BMP_MAX_SIZE)
1459 		  failed_bitmap_h = BMP_MAX_SIZE;
1460 
1461 	       _AL_FREE(pos);
1462 	       break;
1463 	    }
1464 
1465 	    prev = pos;
1466 	    pos = pos->next_y;
1467 	 }
1468 
1469 	 _unregister_switch_bitmap(bitmap);
1470       }
1471       else if (is_system_bitmap(bitmap)) {
1472 	 /* special case for getting rid of system memory bitmaps */
1473 	 ASSERT(gfx_driver != NULL);
1474 
1475 	 if (gfx_driver->destroy_system_bitmap) {
1476 	    gfx_driver->destroy_system_bitmap(bitmap);
1477 	    return;
1478 	 }
1479       }
1480 
1481       /* normal memory or sub-bitmap destruction */
1482       if (system_driver->destroy_bitmap) {
1483 	 if (system_driver->destroy_bitmap(bitmap))
1484 	    return;
1485       }
1486 
1487       if (bitmap->dat)
1488 	 _AL_FREE(bitmap->dat);
1489 
1490       _AL_FREE(bitmap);
1491    }
1492 }
1493 
1494 
1495 
1496 /* set_clip_rect:
1497  *  Sets the two opposite corners of the clipping rectangle to be used when
1498  *  drawing to the bitmap. Nothing will be drawn to positions outside of this
1499  *  rectangle. When a new bitmap is created the clipping rectangle will be
1500  *  set to the full area of the bitmap.
1501  */
set_clip_rect(BITMAP * bitmap,int x1,int y1,int x2,int y2)1502 void set_clip_rect(BITMAP *bitmap, int x1, int y1, int x2, int y2)
1503 {
1504    ASSERT(bitmap);
1505 
1506    /* internal clipping is inclusive-exclusive */
1507    x2++;
1508    y2++;
1509 
1510    bitmap->cl = CLAMP(0, x1, bitmap->w-1);
1511    bitmap->ct = CLAMP(0, y1, bitmap->h-1);
1512    bitmap->cr = CLAMP(0, x2, bitmap->w);
1513    bitmap->cb = CLAMP(0, y2, bitmap->h);
1514 
1515    if (bitmap->vtable->set_clip)
1516       bitmap->vtable->set_clip(bitmap);
1517 }
1518 
1519 
1520 
1521 /* add_clip_rect:
1522  *  Makes the new clipping rectangle the intersection between the given
1523  *  rectangle and the current one.
1524  */
add_clip_rect(BITMAP * bitmap,int x1,int y1,int x2,int y2)1525 void add_clip_rect(BITMAP *bitmap, int x1, int y1, int x2, int y2)
1526 {
1527    int cx1, cy1, cx2, cy2;
1528 
1529    ASSERT(bitmap);
1530 
1531    get_clip_rect(bitmap, &cx1, &cy1, &cx2, &cy2);
1532 
1533    x1 = MAX(x1, cx1);
1534    y1 = MAX(y1, cy1);
1535    x2 = MIN(x2, cx2);
1536    y2 = MIN(y2, cy2);
1537 
1538    set_clip_rect(bitmap, x1, y1, x2, y2);
1539 }
1540 
1541 
1542 
1543 /* set_clip:
1544  *  Sets the two opposite corners of the clipping rectangle to be used when
1545  *  drawing to the bitmap. Nothing will be drawn to positions outside of this
1546  *  rectangle. When a new bitmap is created the clipping rectangle will be
1547  *  set to the full area of the bitmap. If x1, y1, x2 and y2 are all zero
1548  *  clipping will be turned off, which will slightly speed up drawing
1549  *  operations but will allow memory to be corrupted if you attempt to draw
1550  *  off the edge of the bitmap.
1551  */
set_clip(BITMAP * bitmap,int x1,int y1,int x2,int y2)1552 void set_clip(BITMAP *bitmap, int x1, int y1, int x2, int y2)
1553 {
1554    int t;
1555 
1556    ASSERT(bitmap);
1557 
1558    if ((!x1) && (!y1) && (!x2) && (!y2)) {
1559       set_clip_rect(bitmap, 0, 0, bitmap->w-1, bitmap->h-1);
1560       set_clip_state(bitmap, FALSE);
1561       return;
1562    }
1563 
1564    if (x2 < x1) {
1565       t = x1;
1566       x1 = x2;
1567       x2 = t;
1568    }
1569 
1570    if (y2 < y1) {
1571       t = y1;
1572       y1 = y2;
1573       y2 = t;
1574    }
1575 
1576    set_clip_rect(bitmap, x1, y1, x2, y2);
1577    set_clip_state(bitmap, TRUE);
1578 }
1579 
1580 
1581 
1582 /* scroll_screen:
1583  *  Attempts to scroll the hardware screen, returning 0 on success.
1584  *  Check the VIRTUAL_W and VIRTUAL_H values to see how far the screen
1585  *  can be scrolled. Note that a lot of VESA drivers can only handle
1586  *  horizontal scrolling in four pixel increments.
1587  */
scroll_screen(int x,int y)1588 int scroll_screen(int x, int y)
1589 {
1590    int ret = 0;
1591    int h;
1592 
1593    /* can driver handle hardware scrolling? */
1594    if ((!gfx_driver->scroll) || (_dispsw_status))
1595       return -1;
1596 
1597    /* clip x */
1598    if (x < 0) {
1599       x = 0;
1600       ret = -1;
1601    }
1602    else if (x > (VIRTUAL_W - SCREEN_W)) {
1603       x = VIRTUAL_W - SCREEN_W;
1604       ret = -1;
1605    }
1606 
1607    /* clip y */
1608    if (y < 0) {
1609       y = 0;
1610       ret = -1;
1611    }
1612    else {
1613       h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
1614       if (y > (VIRTUAL_H - h)) {
1615 	 y = VIRTUAL_H - h;
1616 	 ret = -1;
1617       }
1618    }
1619 
1620    /* scroll! */
1621    if (gfx_driver->scroll(x, y) != 0)
1622       ret = -1;
1623 
1624    return ret;
1625 }
1626 
1627 
1628 
1629 /* request_scroll:
1630  *  Attempts to initiate a triple buffered hardware scroll, which will
1631  *  take place during the next retrace. Returns 0 on success.
1632  */
request_scroll(int x,int y)1633 int request_scroll(int x, int y)
1634 {
1635    int ret = 0;
1636    int h;
1637 
1638    /* can driver handle triple buffering? */
1639    if ((!gfx_driver->request_scroll) || (_dispsw_status)) {
1640       scroll_screen(x, y);
1641       return -1;
1642    }
1643 
1644    /* clip x */
1645    if (x < 0) {
1646       x = 0;
1647       ret = -1;
1648    }
1649    else if (x > (VIRTUAL_W - SCREEN_W)) {
1650       x = VIRTUAL_W - SCREEN_W;
1651       ret = -1;
1652    }
1653 
1654    /* clip y */
1655    if (y < 0) {
1656       y = 0;
1657       ret = -1;
1658    }
1659    else {
1660       h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
1661       if (y > (VIRTUAL_H - h)) {
1662 	 y = VIRTUAL_H - h;
1663 	 ret = -1;
1664       }
1665    }
1666 
1667    /* scroll! */
1668    if (gfx_driver->request_scroll(x, y) != 0)
1669       ret = -1;
1670 
1671    return ret;
1672 }
1673 
1674 
1675 
1676 /* poll_scroll:
1677  *  Checks whether a requested triple buffer flip has actually taken place.
1678  */
poll_scroll(void)1679 int poll_scroll(void)
1680 {
1681    if ((!gfx_driver->poll_scroll) || (_dispsw_status))
1682       return FALSE;
1683 
1684    return gfx_driver->poll_scroll();
1685 }
1686 
1687 
1688 
1689 /* show_video_bitmap:
1690  *  Page flipping function: swaps to display the specified video memory
1691  *  bitmap object (this must be the same size as the physical screen).
1692  */
show_video_bitmap(BITMAP * bitmap)1693 int show_video_bitmap(BITMAP *bitmap)
1694 {
1695    if ((!is_video_bitmap(bitmap)) ||
1696        (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
1697        (_dispsw_status))
1698       return -1;
1699 
1700    if (gfx_driver->show_video_bitmap)
1701       return gfx_driver->show_video_bitmap(bitmap);
1702 
1703    return scroll_screen(bitmap->x_ofs, bitmap->y_ofs);
1704 }
1705 
1706 
1707 
1708 /* request_video_bitmap:
1709  *  Triple buffering function: triggers a swap to display the specified
1710  *  video memory bitmap object, which will take place on the next retrace.
1711  */
request_video_bitmap(BITMAP * bitmap)1712 int request_video_bitmap(BITMAP *bitmap)
1713 {
1714    if ((!is_video_bitmap(bitmap)) ||
1715        (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
1716        (_dispsw_status))
1717       return -1;
1718 
1719    if (gfx_driver->request_video_bitmap)
1720       return gfx_driver->request_video_bitmap(bitmap);
1721 
1722    return request_scroll(bitmap->x_ofs, bitmap->y_ofs);
1723 }
1724 
1725 
1726 
1727 /* enable_triple_buffer:
1728  *  Asks a driver to turn on triple buffering mode, if it is capable
1729  *  of that.
1730  */
enable_triple_buffer(void)1731 int enable_triple_buffer(void)
1732 {
1733    if (gfx_capabilities & GFX_CAN_TRIPLE_BUFFER)
1734       return 0;
1735 
1736    if (_dispsw_status)
1737       return -1;
1738 
1739    if (gfx_driver->enable_triple_buffer) {
1740       gfx_driver->enable_triple_buffer();
1741 
1742       if ((gfx_driver->request_scroll) || (gfx_driver->request_video_bitmap)) {
1743 	 gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
1744 	 return 0;
1745       }
1746    }
1747 
1748    return -1;
1749 }
1750 
1751 
1752 
1753 /* get_gfx_mode_type:
1754  *  Evaluates the type of the graphics driver card
1755  *  and tells you whether it is a windowed, fullscreen,
1756  *  definitely windowed or fullscreen, and/or a magic driver.
1757  *  See gfx.h for the GFX_TYPE_* defines.
1758  */
get_gfx_mode_type(int graphics_card)1759 int get_gfx_mode_type(int graphics_card)
1760 {
1761    int gfx_type = GFX_TYPE_UNKNOWN;
1762    _DRIVER_INFO *gfx_driver_info;
1763    GFX_DRIVER *gfx_driver_entry;
1764 
1765    ASSERT(system_driver);
1766 
1767    /* Ask the system driver for a list of graphics hardware drivers */
1768    if (system_driver->gfx_drivers) {
1769       gfx_driver_info = system_driver->gfx_drivers();
1770    }
1771    else {
1772       gfx_driver_info = _gfx_driver_list;
1773    }
1774 
1775    ASSERT(gfx_driver_info);
1776 
1777    while (gfx_driver_info->driver) {
1778       if (gfx_driver_info->id == graphics_card) {
1779          gfx_driver_entry = (GFX_DRIVER*)gfx_driver_info->driver;
1780          if (gfx_driver_entry->windowed) {
1781             gfx_type |= (GFX_TYPE_WINDOWED   | GFX_TYPE_DEFINITE);
1782          }
1783          else {
1784             gfx_type |= (GFX_TYPE_FULLSCREEN | GFX_TYPE_DEFINITE);
1785          }
1786          break;
1787       }
1788       gfx_driver_info++;
1789    }
1790 
1791    switch (graphics_card) {
1792       case GFX_AUTODETECT:
1793          gfx_type |= GFX_TYPE_MAGIC;
1794          break;
1795       case GFX_AUTODETECT_FULLSCREEN:
1796          gfx_type |= (GFX_TYPE_MAGIC | GFX_TYPE_FULLSCREEN | GFX_TYPE_DEFINITE);
1797          break;
1798       case GFX_AUTODETECT_WINDOWED:
1799          gfx_type |= (GFX_TYPE_MAGIC | GFX_TYPE_WINDOWED   | GFX_TYPE_DEFINITE);
1800          break;
1801       case GFX_SAFE:
1802          gfx_type |= GFX_TYPE_MAGIC;
1803          break;
1804       case GFX_TEXT:
1805          gfx_type |= GFX_TYPE_MAGIC;
1806          break;
1807    }
1808    return gfx_type;
1809 }
1810 
1811 
1812 
1813 /* get_gfx_mode:
1814  *  Tells you which graphics mode is currently set.
1815  *  Useful for determining the actual driver that
1816  *  GFX_AUTODETECT* or GFX_SAFE set successfully.
1817  */
get_gfx_mode(void)1818 int get_gfx_mode(void)
1819 {
1820    if (!gfx_driver)
1821       return GFX_NONE;
1822 
1823    return gfx_driver->id;
1824 }
1825 
1826 
1827 
1828