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