Re: [AD] Proposal for new branch

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


> Anyone who wants it: cvs update -r new_api_branch

Checked it out, and ported the changes I made to the graphics code to it. 
The attached patch contains a good deal of the inversion to convert the 
old display API with a newer one (essentially, the one I posted earlier).
The underlying gfx_driver structure has not changed though, so this does 
not add actual new functionality (well, transparent triple/double 
buffering) to the code, although it should be flexible enough to do more 
than the current code does.

Evert
diff -N -u -r allegro/include/allegro/display.h allegro-new-gfx/include/allegro/display.h
--- allegro/include/allegro/display.h	1970-01-01 01:00:00.000000000 +0100
+++ allegro-new-gfx/include/allegro/display.h	2004-08-27 16:48:30.000000000 +0200
@@ -0,0 +1,86 @@
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
+ *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
+ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
+ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
+ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
+ *                                           /\____/
+ *                                           \_/__/
+ *
+ *      Improved screen display API, draft.
+ *
+ *      See readme.txt for copyright information.
+ */
+#ifndef ALLEGRO_DISPLAY_H
+#define ALLEGRO_DISPLAY_H
+
+#include "base.h"
+#include "gfx.h"
+
+#ifdef __cplusplus
+   extern "C" {
+#endif
+
+/* Colour depth defines */
+#define AL_DEPTH_AUTO   0
+#define AL_DEPTH_8      8
+#define AL_DEPTH_15     15
+#define AL_DEPTH_16     16
+#define AL_DEPTH_24     24
+#define AL_DEPTH_32     32
+
+/* Update method flags */
+#define AL_UPDATE_NONE              0x0000
+#define AL_UPDATE_TRIPLE_BUFFER     0x0001
+#define AL_UPDATE_PAGE_FLIP         0x0002
+#define AL_UPDATE_SYSTEM_BUFFER     0x0004
+#define AL_UPDATE_DOUBLE_BUFFER     0x0008
+
+#define AL_UPDATE_ALL               0x000F
+
+/* Misc. flags */
+#define AL_DISABLE_VSYNC            0x1000
+
+typedef struct AL_DISPLAY {   /* Allegro display struct */
+   GFX_DRIVER *gfx_driver;    /* Graphics driver for this display */
+   BITMAP *screen;            /* Screen bitmap */
+   BITMAP **page;             /* Display pages */
+   int num_pages;             /* Number of display pages */
+   int active_page;           /* Number of active page (tri/dbl buffer) */
+   int flags;                 /* Display flags */
+   int depth;                 /* Colour depth */
+   int gfx_capabilities;      /* Driver capabilities */
+} AL_DISPLAY;
+
+AL_VAR(AL_DISPLAY *, al_main_display);
+
+AL_FUNC(BITMAP *, al_create_video_bitmap, (AL_DISPLAY *display, int width, int height));
+AL_FUNC(BITMAP *, al_create_system_bitmap, (AL_DISPLAY *display, int width, int height));
+
+AL_FUNC(int, al_scroll_display, (AL_DISPLAY *display, int x, int y));
+AL_FUNC(int, al_request_scroll, (AL_DISPLAY *display, int x, int y));
+AL_FUNC(int, al_poll_scroll, (AL_DISPLAY *display));
+AL_FUNC(int, al_show_video_bitmap, (AL_DISPLAY *display, BITMAP *bitmap));
+AL_FUNC(int, al_request_video_bitmap, (AL_DISPLAY *display, BITMAP *bitmap));
+AL_FUNC(int, al_enable_triple_buffer, (AL_DISPLAY *display));
+
+AL_FUNC(AL_DISPLAY *, al_create_display, (int driver, int flags, int depth, int w, int h, int v_w, int v_h));
+AL_FUNC(int, al_set_update_method, (AL_DISPLAY *display, int method));
+AL_FUNC(void, al_destroy_display, (AL_DISPLAY *display));
+
+AL_FUNC(void, al_flip_display, (AL_DISPLAY *display));
+AL_FUNC(BITMAP *, al_get_buffer, (const AL_DISPLAY *display));
+AL_FUNC(int, al_get_update_method, (const AL_DISPLAY *display));
+
+AL_FUNC(void, al_enable_vsync, (AL_DISPLAY *display));
+AL_FUNC(void, al_disable_vsync, (AL_DISPLAY *display));
+AL_FUNC(void, al_toggle_vsync, (AL_DISPLAY *display));
+AL_FUNC(int, al_vsync_is_enabled, (const AL_DISPLAY *display));
+
+#ifdef __cplusplus
+   }
+#endif
+
+
+#endif      /* #ifndef ALLEGRO_DISPLAY_H */
diff -N -u -r allegro/makefile.lst allegro-new-gfx/makefile.lst
--- allegro/makefile.lst	2004-08-27 15:09:35.000000000 +0200
+++ allegro-new-gfx/makefile.lst	2004-08-27 15:11:26.000000000 +0200
@@ -13,6 +13,7 @@
 	src/dataregi.c \
 	src/digmid.c \
 	src/dither.c \
+        src/display.c \
 	src/dispsw.c \
 	src/dtor.c \
 	src/drvlist.c \
diff -N -u -r allegro/src/display.c allegro-new-gfx/src/display.c
--- allegro/src/display.c	1970-01-01 01:00:00.000000000 +0100
+++ allegro-new-gfx/src/display.c	2004-08-27 16:47:24.000000000 +0200
@@ -0,0 +1,1564 @@
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
+ *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
+ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
+ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
+ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
+ *                                           /\____/
+ *                                           \_/__/
+ *
+ *      Improved screen display API, draft.
+ *
+ *      See readme.txt for copyright information.
+ */
+
+#include <string.h>
+
+#include "allegro.h"
+#include "allegro/internal/aintern.h"
+
+#include "allegro/display.h"
+
+AL_DISPLAY *al_main_display = NULL;
+
+static _AL_VECTOR display_list = _AL_VECTOR_INITIALIZER(AL_DISPLAY);
+
+static int gfx_virgin = TRUE;          /* is the graphics system active? */
+
+typedef struct VRAM_BITMAP             /* list of video memory bitmaps */
+{
+   int x, y, w, h;
+   BITMAP *bmp;
+   struct VRAM_BITMAP *next_x, *next_y;
+   AL_DISPLAY *root_display;
+} VRAM_BITMAP;
+
+static VRAM_BITMAP *vram_bitmap_list = NULL;
+
+typedef struct SYSTEM_BITMAP
+{
+   BITMAP *bmp;
+   AL_DISPLAY *root_display;
+} SYSTEM_BITMAP;
+
+static _AL_VECTOR sysbmp_list = _AL_VECTOR_INITIALIZER(SYSTEM_BITMAP);
+
+#define BMP_MAX_SIZE  46340   /* sqrt(INT_MAX) */
+
+/* the product of these must fit in an int */
+static int failed_bitmap_w = BMP_MAX_SIZE;
+static int failed_bitmap_h = BMP_MAX_SIZE;
+
+
+
+/* destroy_video_bitmaps:
+ *  Destroys all video bitmaps
+ */
+static void destroy_video_bitmaps(void)
+{
+   while (vram_bitmap_list)
+      destroy_bitmap(vram_bitmap_list->bmp);
+}
+
+
+/* add_vram_block:
+ *  Creates a video memory bitmap out of the specified region
+ *  of the larger screen surface, returning a pointer to it.
+ */
+static BITMAP *add_vram_block(AL_DISPLAY *display, int x, int y, int w, int h)
+{
+   VRAM_BITMAP *b, *new_b;
+   VRAM_BITMAP **last_p;
+
+   new_b = malloc(sizeof(VRAM_BITMAP));
+   if (!new_b)
+      return NULL;
+
+   new_b->x = x;
+   new_b->y = y;
+   new_b->w = w;
+   new_b->h = h;
+   new_b->root_display = display;
+
+   new_b->bmp = create_sub_bitmap(display->screen, x, y, w, h);
+   if (!new_b->bmp) {
+      free(new_b);
+      return NULL;
+   }
+
+   /* find sorted y-position */
+   last_p = &vram_bitmap_list;
+   for (b = vram_bitmap_list; b && (b->y < new_b->y); b = b->next_y)
+      last_p = &b->next_y;
+
+   /* insert */
+   *last_p = new_b;
+   new_b->next_y = b;
+
+   return new_b->bmp;
+}
+
+
+
+/* al_create_video_bitmap:
+ *  Attempts to make a bitmap object for accessing offscreen video memory.
+ *
+ *  The algorithm is similar to algorithms for drawing polygons. Think of
+ *  a horizontal stripe whose height is equal to that of the new bitmap.
+ *  It is initially aligned to the top of video memory and then it moves
+ *  downwards, stopping each time its top coincides with the bottom of a
+ *  video bitmap. For each stop, create a list of video bitmaps intersecting
+ *  the stripe, sorted by the left coordinate, from left to right, in the
+ *  next_x linked list. We look through this list and stop as soon as the
+ *  gap between the rightmost right edge seen so far and the current left
+ *  edge is big enough for the new video bitmap. In that case, we are done.
+ *  If we don't find such a gap, we move the stripe further down.
+ *
+ *  To make it efficient to find new bitmaps intersecting the stripe, the
+ *  list of all bitmaps is always sorted by top, from top to bottom, in
+ *  the next_y linked list. The list of bitmaps intersecting the stripe is
+ *  merely updated, not recalculated from scratch, when we move the stripe.
+ *  So every bitmap gets bubbled to its correct sorted x-position at most
+ *  once. Bubbling a bitmap takes at most as many steps as the number of
+ *  video bitmaps. So the algorithm behaves at most quadratically with
+ *  regard to the number of video bitmaps. I think that a linear behaviour
+ *  is more typical in practical applications (this happens, for instance,
+ *  if you allocate many bitmaps of the same height).
+ *
+ *  There's one more optimization: if a call fails, we cache the size of the
+ *  requested bitmap, so that next time we can detect very quickly that this
+ *  size is too large (this needs to be maintained when destroying bitmaps).
+ */
+BITMAP *al_create_video_bitmap(AL_DISPLAY *display, int width, int height)
+{
+   VRAM_BITMAP *active_list, *b, *vram_bitmap;
+   VRAM_BITMAP **last_p;
+   BITMAP *bmp;
+   int x = 0, y = 0;
+
+   ASSERT(width >= 0);
+   ASSERT(height > 0);
+   
+   if (_dispsw_status)
+      return NULL;
+
+   /* let the driver handle the request if it can */
+   if (display->gfx_driver->create_video_bitmap) {
+      bmp = display->gfx_driver->create_video_bitmap(width, height);
+      if (!bmp)
+	 return NULL;
+
+      b = malloc(sizeof(VRAM_BITMAP));
+      b->x = -1;
+      b->y = -1;
+      b->w = 0;
+      b->h = 0;
+      b->bmp = bmp;
+      b->next_y = vram_bitmap_list;
+      vram_bitmap_list = b;
+
+      return bmp;
+   }
+
+   /* check bad args */
+   if ((width > VIRTUAL_W) || (height > VIRTUAL_H) ||
+       (width < 0) || (height < 0))
+      return NULL;
+
+   /* check cached bitmap size */
+   if ((width >= failed_bitmap_w) && (height >= failed_bitmap_h))
+      return NULL;
+
+   vram_bitmap = vram_bitmap_list;
+   active_list = NULL;
+   y = 0;
+
+   while (TRUE) {
+      /* Move the blocks from the VRAM_BITMAP_LIST that intersect the
+       * stripe to the ACTIVE_LIST: look through the VRAM_BITMAP_LIST
+       * following the next_y link, grow the ACTIVE_LIST following
+       * the next_x link and sorting by x-position.
+       * (this loop runs in amortized quadratic time)
+       */
+      while (vram_bitmap && (vram_bitmap->y < y+height)) {
+	 /* find sorted x-position */
+	 last_p = &active_list;
+	 for (b = active_list; b && (vram_bitmap->x > b->x); b = b->next_x)
+	    last_p = &b->next_x;
+
+	 /* insert */
+	 *last_p = vram_bitmap;
+	 vram_bitmap->next_x = b;
+
+	 /* next video bitmap */
+	 vram_bitmap = vram_bitmap->next_y;
+      }
+
+      x = 0;
+
+      /* Look for holes to put our bitmap in.
+       * (this loop runs in quadratic time)
+       */
+      for (b = active_list; b; b = b->next_x) {
+	 if (x+width <= b->x)  /* hole is big enough? */
+	    return add_vram_block(display, x, y, width, height);
+
+         /* Move search x-position to the right edge of the
+          * skipped bitmap if we are not already past it.
+          * And check there is enough room before continuing.
+          */
+	 if (x < b->x + b->w) {
+	    x = (b->x + b->w + 15) & ~15;
+	    if (x+width > VIRTUAL_W)
+	       break;
+	 }
+      }
+
+      /* If the whole ACTIVE_LIST was scanned, there is a big
+       * enough hole to the right of the rightmost bitmap.
+       */
+      if (b == NULL)
+	 return add_vram_block(display, x, y, width, height);
+
+      /* Move search y-position to the topmost bottom edge
+       * of the bitmaps intersecting the stripe.
+       * (this loop runs in quadratic time)
+       */
+      y = active_list->y + active_list->h;
+      for (b = active_list->next_x; b; b = b->next_x) {
+	 if (y > b->y + b->h)
+	    y = b->y + b->h;
+      }
+
+      if (y+height > VIRTUAL_H) {  /* too close to bottom? */
+	 /* Before failing, cache this bitmap size so that later calls can
+	  * learn from it. Use area as a measure to sort the bitmap sizes.
+          */
+	 if (width * height < failed_bitmap_w * failed_bitmap_h) {
+	    failed_bitmap_w = width;
+	    failed_bitmap_h = height;
+	 }
+
+	 return NULL;
+      }
+
+      /* Remove the blocks that don't intersect the new stripe from ACTIVE_LIST.
+       * (this loop runs in quadratic time)
+       */
+      last_p = &active_list;
+      for (b = active_list; b; b = b->next_x) {
+	 if (y >= b->y + b->h)
+	    *last_p = b->next_x;
+	 else
+	    last_p = &b->next_x;
+      }
+   }
+}
+
+
+
+/* al_create_system_bitmap:
+ *  Attempts to make a system-specific (eg. DirectX surface) bitmap object.
+ */
+BITMAP *al_create_system_bitmap(AL_DISPLAY *display, int width, int height)
+{
+   SYSTEM_BITMAP *sysbmp;
+   
+   ASSERT(width >= 0);
+   ASSERT(height > 0);
+   ASSERT(display);
+   ASSERT(display->gfx_driver != NULL);
+
+
+   sysbmp = _al_vector_alloc_back(&sysbmp_list);
+   if (display->gfx_driver->create_system_bitmap) {
+      sysbmp->root_display = display;
+      sysbmp->bmp = display->gfx_driver->create_system_bitmap(width, height);
+   } else {
+      sysbmp->bmp = create_bitmap(width, height);
+      sysbmp->bmp->id |= BMP_ID_SYSTEM;
+   }
+
+   return sysbmp->bmp;
+}
+
+
+
+/* destroy_bitmap:
+ *  Destroys a memory bitmap.
+ */
+void destroy_bitmap(BITMAP *bitmap)
+{
+   VRAM_BITMAP *prev, *pos;
+
+   if (bitmap) {
+      if (is_video_bitmap(bitmap)) {
+	 /* special case for getting rid of video memory bitmaps */
+	 ASSERT(!_dispsw_status);
+
+	 prev = NULL;
+	 pos = vram_bitmap_list;
+
+	 while (pos) {
+	    if (pos->bmp == bitmap) {
+	       if (prev)
+		  prev->next_y = pos->next_y;
+	       else
+		  vram_bitmap_list = pos->next_y;
+
+	       if (pos->x < 0) {
+		  /* the driver is in charge of this object */
+		  pos->root_display->gfx_driver->destroy_video_bitmap(bitmap);
+		  free(pos);
+		  return;
+	       } 
+
+	       /* Update cached bitmap size using worst case scenario:
+		* the bitmap lies between two holes whose size is the cached
+		* size on each axis respectively.
+		*/
+	       failed_bitmap_w = failed_bitmap_w * 2 + ((bitmap->w + 15) & ~15);
+	       if (failed_bitmap_w > BMP_MAX_SIZE)
+		  failed_bitmap_w = BMP_MAX_SIZE;
+
+	       failed_bitmap_h = failed_bitmap_h * 2 + bitmap->h;
+	       if (failed_bitmap_h > BMP_MAX_SIZE)
+		  failed_bitmap_h = BMP_MAX_SIZE;
+
+	       free(pos);
+	       break;
+	    }
+
+	    prev = pos;
+	    pos = pos->next_y;
+	 }
+
+	 _unregister_switch_bitmap(bitmap);
+      }
+      else if (is_system_bitmap(bitmap)) {
+	 /* special case for getting rid of system memory bitmaps */
+         int c;
+         for (c = 0; c < _al_vector_size(&sysbmp_list); c++) {
+            SYSTEM_BITMAP *sysbmp = _al_vector_ref(&sysbmp_list, c);
+            if (sysbmp->bmp == bitmap) {
+	       ASSERT(sysbmp->root_display->gfx_driver != NULL);
+
+	       if (sysbmp->root_display->gfx_driver->destroy_system_bitmap) {
+	          sysbmp->root_display->gfx_driver->destroy_system_bitmap(bitmap);
+                  _al_vector_delete_at(&display_list, c);
+	          return;
+	       }
+               
+               _al_vector_delete_at(&display_list, c);
+               break;
+            }
+         }
+      }
+
+      /* normal memory or sub-bitmap destruction */
+      if (system_driver->destroy_bitmap) {
+	 if (system_driver->destroy_bitmap(bitmap))
+	    return;
+      }
+
+      if (bitmap->dat)
+	 free(bitmap->dat);
+
+      free(bitmap);
+   }
+}
+
+
+
+
+
+/* _get_vtable:
+ *  Returns a pointer to the linear vtable for the specified color depth.
+ */
+GFX_VTABLE *_get_vtable(int color_depth)
+{
+   GFX_VTABLE *vt;
+   int i;
+
+   ASSERT(system_driver);
+
+   if (system_driver->get_vtable) {
+      vt = system_driver->get_vtable(color_depth);
+
+      if (vt) {
+	 LOCK_DATA(vt, sizeof(GFX_VTABLE));
+	 LOCK_CODE(vt->draw_sprite, (long)vt->draw_sprite_end - (long)vt->draw_sprite);
+	 LOCK_CODE(vt->blit_from_memory, (long)vt->blit_end - (long)vt->blit_from_memory);
+	 return vt;
+      }
+   }
+
+   for (i=0; _vtable_list[i].vtable; i++) {
+      if (_vtable_list[i].color_depth == color_depth) {
+	 LOCK_DATA(_vtable_list[i].vtable, sizeof(GFX_VTABLE));
+	 LOCK_CODE(_vtable_list[i].vtable->draw_sprite, (long)_vtable_list[i].vtable->draw_sprite_end - (long)_vtable_list[i].vtable->draw_sprite);
+	 LOCK_CODE(_vtable_list[i].vtable->blit_from_memory, (long)_vtable_list[i].vtable->blit_end - (long)_vtable_list[i].vtable->blit_from_memory);
+	 return _vtable_list[i].vtable;
+      }
+   }
+
+   return NULL;
+}
+
+
+
+/* shutdown_gfx:
+ *  Used by allegro_exit() to return the system to text mode.
+ */
+static void shutdown_gfx(void)
+{
+   int i;
+   
+   /* Destroy all remaining displays */
+   while (!_al_vector_is_empty(&display_list)) {
+      AL_DISPLAY *display = _al_vector_ref_back(&display_list);
+      
+      al_destroy_display(display);
+   }
+   _al_vector_free(&display_list);
+   
+   if (system_driver->restore_console_state)
+      system_driver->restore_console_state();
+
+   _remove_exit_func(shutdown_gfx);
+
+   gfx_virgin = TRUE;
+}
+
+
+#define GFX_DRIVER_FULLSCREEN_FLAG    0x01
+#define GFX_DRIVER_WINDOWED_FLAG      0x02
+
+
+/* gfx_driver_is_valid:
+ *  Checks that the graphics driver 'drv' fulfills the condition
+ *  expressed by the bitmask 'flags'.
+ */
+static int gfx_driver_is_valid(GFX_DRIVER *drv, int flags)
+{
+   if ((flags & GFX_DRIVER_FULLSCREEN_FLAG) && drv->windowed)
+      return FALSE;
+
+   if ((flags & GFX_DRIVER_WINDOWED_FLAG) && !drv->windowed)
+      return FALSE;
+
+   return TRUE;
+}
+
+
+
+/* get_gfx_driver_from_id:
+ *  Retrieves a pointer to the graphics driver identified by 'card' from
+ *  the list 'driver_list' or NULL if it doesn't exist.
+ */
+static GFX_DRIVER *get_gfx_driver_from_id(int card, _DRIVER_INFO *driver_list)
+{
+   int c;
+
+   for (c=0; driver_list[c].driver; c++) {
+      if (driver_list[c].id == card)
+	 return driver_list[c].driver;
+   }
+
+   return NULL;
+}
+
+
+
+/* init_gfx_driver:
+ *  Helper function for initializing a graphics driver.
+ */
+static BITMAP *init_gfx_driver(AL_DISPLAY *display, GFX_DRIVER *drv, int w, int h, int v_w, int v_h, int depth)
+{
+   drv->name = drv->desc = get_config_text(drv->ascii_name);
+
+   /* set gfx_driver so that it is visible when initializing the driver */
+   display->gfx_driver = drv;
+
+   return drv->init(w, h, v_w, v_h, depth);
+}
+
+
+
+/* get_config_gfx_driver:
+ *  Helper function for set_gfx_mode: it reads the gfx_card* config variables and
+ *  tries to set the graphics mode if a matching driver is found. Returns TRUE if
+ *  at least one matching driver was found, FALSE otherwise.
+ */
+static int get_config_gfx_driver(AL_DISPLAY *display, char *gfx_card, int w, int h, int v_w, int v_h, int depth, int flags, _DRIVER_INFO *driver_list)
+{
+   char buf[512], tmp[64];
+   GFX_DRIVER *drv;
+   int found = FALSE;
+   int card, n;
+
+   /* try the drivers that are listed in the config file */
+   for (n=-2; n<255; n++) {
+      switch (n) {
+
+	 case -2:
+	    /* example: gfx_card_640x480x16 = */
+	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dx%dx%d", tmp), gfx_card, w, h, depth);
+	    break;
+
+	 case -1:
+	    /* example: gfx_card_24bpp = */
+	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dbpp", tmp), gfx_card, depth);
+	    break;
+
+	 case 0:
+	    /* example: gfx_card = */
+	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s", tmp), gfx_card);
+	    break;
+
+	 default:
+	    /* example: gfx_card1 = */
+	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s%d", tmp), gfx_card, n);
+	    break;
+      }
+
+      card = get_config_id(uconvert_ascii("graphics", tmp), buf, 0);
+
+      if (card) {
+	 drv = get_gfx_driver_from_id(card, driver_list);
+
+	 if (drv && gfx_driver_is_valid(drv, flags)) {
+	    found = TRUE;
+	    display->screen = init_gfx_driver(display, drv, w, h, v_w, v_h, depth);
+
+	    if (display->screen)
+	       break;
+	 }
+      }
+      else {
+	 /* Stop searching the gfx_card#n (n>0) family at the first missing member,
+	  * except gfx_card1 which could have been identified with gfx_card.
+	  */
+	 if (n > 1)
+	    break;
+      }
+   }
+
+   return found;
+}
+
+
+
+/* set_gfx_mode:
+ *  Sets the graphics mode. The card should be one of the GFX_* constants
+ *  from allegro.h, or GFX_AUTODETECT to accept any graphics driver. Pass
+ *  GFX_TEXT to return to text mode (although allegro_exit() will usually 
+ *  do this for you). The w and h parameters specify the screen resolution 
+ *  you want, and v_w and v_h specify the minumum virtual screen size. 
+ *  The graphics drivers may actually create a much larger virtual screen, 
+ *  so you should check the values of VIRTUAL_W and VIRTUAL_H after you
+ *  set the mode. If unable to select an appropriate mode, this function 
+ *  returns -1.
+ */
+static int do_set_gfx_mode(AL_DISPLAY *display, int card, int w, int h, int v_w, int v_h, int depth)
+{
+   static int allow_config = TRUE;
+   extern void blit_end(void);
+   _DRIVER_INFO *driver_list;
+   GFX_DRIVER *drv;
+   struct GFX_MODE mode;
+   char buf[ALLEGRO_ERROR_SIZE], tmp1[64], tmp2[64];
+   AL_CONST char *dv;
+   int flags = 0;
+   int c, driver, ret;
+   ASSERT(system_driver);
+
+   _gfx_mode_set_count++;
+
+   /* special bodge for the GFX_SAFE driver */
+   if (card == GFX_SAFE) {
+      if (system_driver->get_gfx_safe_mode) {
+	 ustrzcpy(buf, sizeof(buf), allegro_error);
+
+	 /* retrieve the safe graphics mode */
+	 system_driver->get_gfx_safe_mode(&driver, &mode);
+
+	 /* try using the specified depth and resolution */
+	 if (do_set_gfx_mode(display, driver, w, h, 0, 0, depth) == 0)
+	    return 0;
+
+	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, buf);
+
+	 /* finally use the safe settings */
+	 set_color_depth(mode.bpp);
+	 if (do_set_gfx_mode(display, driver, mode.width, mode.height, 0, 0, depth) == 0)
+	    return 0;
+
+	 ASSERT(FALSE);  /* the safe graphics mode must always work */
+      }
+      else {
+	 /* no safe graphics mode, try hard-coded autodetected modes with custom settings */
+	 allow_config = FALSE;
+	 _safe_gfx_mode_change = 1;
+
+	 ret = do_set_gfx_mode(display, GFX_AUTODETECT, w, h, 0, 0, depth);
+
+	 _safe_gfx_mode_change = 0;
+	 allow_config = TRUE;
+
+	 if (ret == 0)
+	    return 0;
+      }
+
+      /* failing to set GFX_SAFE is a fatal error */
+      do_set_gfx_mode(display, GFX_TEXT, 0, 0, 0, 0, 0);
+      allegro_message(uconvert_ascii("%s\n", tmp1), get_config_text("Fatal error: unable to set GFX_SAFE"));
+      return -1;
+   }
+
+   /* remember the current console state */
+   if (gfx_virgin) {
+      LOCK_FUNCTION(_stub_bank_switch);
+      LOCK_FUNCTION(blit);
+
+      if (system_driver->save_console_state)
+	 system_driver->save_console_state();
+
+      _add_exit_func(shutdown_gfx);
+
+      gfx_virgin = FALSE;
+   }
+
+   /* lock the application in the foreground */
+   if (system_driver->display_switch_lock)
+      system_driver->display_switch_lock(TRUE, TRUE);
+
+   timer_simulate_retrace(FALSE);
+   _screen_split_position = 0;
+
+   /* close down any existing graphics driver */
+   if (display->gfx_driver) {
+      if (_al_linker_mouse)
+         _al_linker_mouse->show_mouse(NULL);
+
+      destroy_video_bitmaps();
+      
+      bmp_read_line(display->screen, 0);
+      bmp_write_line(display->screen, 0);
+      bmp_unwrite_line(display->screen);
+
+      if (display->gfx_driver->scroll)
+	 display->gfx_driver->scroll(0, 0);
+
+      if (display->gfx_driver->exit)
+	 display->gfx_driver->exit(display->screen);
+
+      destroy_bitmap(display->screen);
+
+      display->gfx_driver = NULL;
+      display->screen = NULL;
+      display->gfx_capabilities = 0;
+   }
+
+   /* We probably don't want to do this because it makes
+    * Allegro "forget" the color layout of previously set
+    * graphics modes. But it should be retained if bitmaps
+    * created in those modes are to be used in the new mode.
+    */
+#if 0
+   /* restore default truecolor pixel format */
+   _rgb_r_shift_15 = 0; 
+   _rgb_g_shift_15 = 5;
+   _rgb_b_shift_15 = 10;
+   _rgb_r_shift_16 = 0;
+   _rgb_g_shift_16 = 5;
+   _rgb_b_shift_16 = 11;
+   _rgb_r_shift_24 = 0;
+   _rgb_g_shift_24 = 8;
+   _rgb_b_shift_24 = 16;
+   _rgb_r_shift_32 = 0;
+   _rgb_g_shift_32 = 8;
+   _rgb_b_shift_32 = 16;
+   _rgb_a_shift_32 = 24;
+#endif
+
+   display->gfx_capabilities = 0;
+
+   _set_current_refresh_rate(0);
+
+   /* return to text mode? */
+   if (card == GFX_TEXT) {
+      if (system_driver->restore_console_state)
+	 system_driver->restore_console_state();
+
+      if (_gfx_bank) {
+	 free(_gfx_bank);
+	 _gfx_bank = NULL;
+      }
+
+      if (system_driver->display_switch_lock)
+	 system_driver->display_switch_lock(FALSE, FALSE);
+
+      return 0;
+   }
+
+   /* now to the interesting part: let's try to find a graphics driver */
+   usetc(allegro_error, 0);
+
+   /* ask the system driver for a list of graphics hardware drivers */
+   if (system_driver->gfx_drivers)
+      driver_list = system_driver->gfx_drivers();
+   else
+      driver_list = _gfx_driver_list;
+
+   /* filter specific fullscreen/windowed driver requests */
+   if (card == GFX_AUTODETECT_FULLSCREEN) {
+      flags |= GFX_DRIVER_FULLSCREEN_FLAG;
+      card = GFX_AUTODETECT;
+   }
+   else if (card == GFX_AUTODETECT_WINDOWED) {
+      flags |= GFX_DRIVER_WINDOWED_FLAG;
+      card = GFX_AUTODETECT;
+   }
+
+   if (card == GFX_AUTODETECT) {
+      /* autodetect the driver */
+      int found = FALSE;
+
+      /* first try the config variables */
+      if (allow_config) {
+	 /* try the gfx_card variable if GFX_AUTODETECT or GFX_AUTODETECT_FULLSCREEN was selected */
+	 if (!(flags & GFX_DRIVER_WINDOWED_FLAG))
+	    found = get_config_gfx_driver(display, uconvert_ascii("gfx_card", tmp1), w, h, v_w, v_h, depth, flags, driver_list);
+
+	 /* try the gfx_cardw variable if GFX_AUTODETECT or GFX_AUTODETECT_WINDOWED was selected */
+	 if (!(flags & GFX_DRIVER_FULLSCREEN_FLAG) && !found)
+	    found = get_config_gfx_driver(display, uconvert_ascii("gfx_cardw", tmp1), w, h, v_w, v_h, depth, flags, driver_list);
+      }
+
+      /* go through the list of autodetected drivers if none was previously found */
+      if (!found) {
+	 for (c=0; driver_list[c].driver; c++) {
+	    if (driver_list[c].autodetect) {
+	       drv = driver_list[c].driver;
+
+	       if (gfx_driver_is_valid(drv, flags)) {
+		  display->screen = init_gfx_driver(display, drv, w, h, v_w, v_h, depth);
+
+		  if (display->screen)
+		     break;
+	       }
+	    }
+	 }
+      }
+   }
+   else {
+      /* search the list for the requested driver */
+      drv = get_gfx_driver_from_id(card, driver_list);
+
+      if (drv)
+	 display->screen = init_gfx_driver(display, drv, w, h, v_w, v_h, depth);
+   }
+
+   /* gracefully handle failure */
+   if (!display->screen) {
+      display->gfx_driver = NULL;  /* set by init_gfx_driver() */
+
+      if (!ugetc(allegro_error))
+	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to find a suitable graphics driver"));
+
+      if (system_driver->display_switch_lock)
+	 system_driver->display_switch_lock(FALSE, FALSE);
+
+      return -1;
+   }
+   
+   /* Set global variables */
+   screen = display->screen;
+   gfx_driver = display->gfx_driver;
+
+   /* set the basic capabilities of the driver */
+   if ((VIRTUAL_W > SCREEN_W) || (VIRTUAL_H > SCREEN_H)) {
+      if (display->gfx_driver->scroll)
+	 display->gfx_capabilities |= GFX_CAN_SCROLL;
+
+      if ((display->gfx_driver->request_scroll) || (display->gfx_driver->request_video_bitmap))
+	 display->gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
+   }
+   
+   gfx_capabilities = display->gfx_capabilities;
+
+   /* check whether we are instructed to disable vsync */
+   dv = get_config_string(uconvert_ascii("graphics", tmp1),
+                          uconvert_ascii("disable_vsync", tmp2),
+                          NULL);
+
+   if ((dv) && ((c = ugetc(dv)) != 0) && ((c == 'y') || (c == 'Y') || (c == '1')))
+      _wait_for_vsync = FALSE;
+   else
+      _wait_for_vsync = TRUE;
+
+   clear_bitmap(screen);
+
+   /* set up the default colors */
+   for (c=0; c<256; c++)
+      _palette_color8[c] = c;
+
+   set_palette(default_palette);
+
+   if (_color_depth == 8) {
+      gui_fg_color = 255;
+      gui_mg_color = 8;
+      gui_bg_color = 0;
+   }
+   else {
+      gui_fg_color = makecol(0, 0, 0);
+      gui_mg_color = makecol(128, 128, 128);
+      gui_bg_color = makecol(255, 255, 255);
+   }
+
+   if (_al_linker_mouse)
+      _al_linker_mouse->set_mouse_etc();
+
+   LOCK_DATA(display->gfx_driver, sizeof(GFX_DRIVER));
+
+   _register_switch_bitmap(screen, NULL);
+
+   if (system_driver->display_switch_lock)
+      system_driver->display_switch_lock(FALSE, FALSE);
+
+   return 0;
+}
+
+
+
+/* _sort_out_virtual_width:
+ *  Decides how wide the virtual screen really needs to be. That is more 
+ *  complicated than it sounds, because the Allegro graphics primitives 
+ *  require that each scanline be contained within a single bank. That 
+ *  causes problems on cards that don't have overlapping banks, unless the 
+ *  bank size is a multiple of the virtual width. So we may need to adjust 
+ *  the width just to keep things running smoothly...
+ */
+void _sort_out_virtual_width(int *width, GFX_DRIVER *driver)
+{
+   int w = *width;
+
+   /* hah! I love VBE 2.0... */
+   if (driver->linear)
+      return;
+
+   /* if banks can overlap, we are ok... */ 
+   if (driver->bank_size > driver->bank_gran)
+      return;
+
+   /* damn, have to increase the virtual width */
+   while (((driver->bank_size / w) * w) != driver->bank_size) {
+      w++;
+      if (w > driver->bank_size)
+	 break; /* oh shit */
+   }
+
+   *width = w;
+}
+
+
+
+/* _make_bitmap:
+ *  Helper function for creating the screen bitmap. Sets up a bitmap 
+ *  structure for addressing video memory at addr, and fills the bank 
+ *  switching table using bank size/granularity information from the 
+ *  specified graphics driver.
+ */
+BITMAP *_make_bitmap(int w, int h, unsigned long addr, GFX_DRIVER *driver, int color_depth, int bpl)
+{
+   GFX_VTABLE *vtable = _get_vtable(color_depth);
+   int i, bank, size;
+   BITMAP *b;
+
+   if (!vtable)
+      return NULL;
+
+   size = sizeof(BITMAP) + sizeof(char *) * h;
+
+   b = (BITMAP *)malloc(size);
+   if (!b)
+      return NULL;
+
+   _gfx_bank = realloc(_gfx_bank, h * sizeof(int));
+   if (!_gfx_bank) {
+      free(b);
+      return NULL;
+   }
+
+   LOCK_DATA(b, size);
+   LOCK_DATA(_gfx_bank, h * sizeof(int));
+
+   b->w = b->cr = w;
+   b->h = b->cb = h;
+   b->clip = TRUE;
+   b->cl = b->ct = 0;
+   b->vtable = &_screen_vtable;
+   b->write_bank = b->read_bank = _stub_bank_switch;
+   b->dat = NULL;
+   b->id = BMP_ID_VIDEO;
+   b->extra = NULL;
+   b->x_ofs = 0;
+   b->y_ofs = 0;
+   b->seg = _video_ds();
+
+   memcpy(&_screen_vtable, vtable, sizeof(GFX_VTABLE));
+   LOCK_DATA(&_screen_vtable, sizeof(GFX_VTABLE));
+
+   _last_bank_1 = _last_bank_2 = -1;
+
+   driver->vid_phys_base = addr;
+
+   b->line[0] = (unsigned char *)addr;
+   _gfx_bank[0] = 0;
+
+   if (driver->linear) {
+      for (i=1; i<h; i++) {
+	 b->line[i] = b->line[i-1] + bpl;
+	 _gfx_bank[i] = 0;
+      }
+   }
+   else {
+      bank = 0;
+
+      for (i=1; i<h; i++) {
+	 b->line[i] = b->line[i-1] + bpl;
+	 if (b->line[i]+bpl-1 >= (unsigned char *)addr + driver->bank_size) {
+	    while (b->line[i] >= (unsigned char *)addr + driver->bank_gran) {
+	       b->line[i] -= driver->bank_gran;
+	       bank++;
+	    }
+	 }
+	 _gfx_bank[i] = bank;
+      }
+   }
+
+   return b;
+}
+
+
+
+/* al_scroll_screen:
+ *  Attempts to scroll the hardware screen, returning 0 on success. 
+ *  Check the VIRTUAL_W and VIRTUAL_H values to see how far the screen
+ *  can be scrolled. Note that a lot of VESA drivers can only handle
+ *  horizontal scrolling in four pixel increments.
+ */
+int al_scroll_display(AL_DISPLAY *display, int x, int y)
+{
+   int ret = 0;
+   int h;
+   
+   ASSERT(display);
+
+   /* can driver handle hardware scrolling? */
+   if ((!display->gfx_driver->scroll) || (_dispsw_status))
+      return -1;
+
+   /* clip x */
+   if (x < 0) {
+      x = 0;
+      ret = -1;
+   }
+   else if (x > (VIRTUAL_W - SCREEN_W)) {
+      x = VIRTUAL_W - SCREEN_W;
+      ret = -1;
+   }
+
+   /* clip y */
+   if (y < 0) {
+      y = 0;
+      ret = -1;
+   }
+   else {
+      h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
+      if (y > (VIRTUAL_H - h)) {
+	 y = VIRTUAL_H - h;
+	 ret = -1;
+      }
+   }
+
+   /* scroll! */
+   if (display->gfx_driver->scroll(x, y) != 0)
+      ret = -1;
+
+   return ret;
+}
+
+
+
+/* al_request_scroll:
+ *  Attempts to initiate a triple buffered hardware scroll, which will
+ *  take place during the next retrace. Returns 0 on success.
+ */
+int al_request_scroll(AL_DISPLAY *display, int x, int y)
+{
+   int ret = 0;
+   int h;
+
+   /* can driver handle triple buffering? */
+   if ((!display->gfx_driver->request_scroll) || (_dispsw_status)) {
+      al_scroll_display(display, x, y);
+      return -1;
+   }
+
+   /* clip x */
+   if (x < 0) {
+      x = 0;
+      ret = -1;
+   }
+   else if (x > (VIRTUAL_W - SCREEN_W)) {
+      x = VIRTUAL_W - SCREEN_W;
+      ret = -1;
+   }
+
+   /* clip y */
+   if (y < 0) {
+      y = 0;
+      ret = -1;
+   }
+   else {
+      h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
+      if (y > (VIRTUAL_H - h)) {
+	 y = VIRTUAL_H - h;
+	 ret = -1;
+      }
+   }
+
+   /* scroll! */
+   if (display->gfx_driver->request_scroll(x, y) != 0)
+      ret = -1;
+
+   return ret;
+}
+
+
+
+/* al_poll_scroll:
+ *  Checks whether a requested triple buffer flip has actually taken place.
+ */
+int al_poll_scroll(AL_DISPLAY *display)
+{
+   if ((!display->gfx_driver->poll_scroll) || (_dispsw_status))
+      return FALSE;
+
+   return display->gfx_driver->poll_scroll();
+}
+
+
+
+/* al_show_video_bitmap:
+ *  Page flipping function: swaps to display the specified video memory 
+ *  bitmap object (this must be the same size as the physical screen).
+ */
+int al_show_video_bitmap(AL_DISPLAY *display, BITMAP *bitmap)
+{
+   if ((!is_video_bitmap(bitmap)) || 
+       (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
+       (_dispsw_status))
+      return -1;
+
+   if (display->gfx_driver->show_video_bitmap)
+      return display->gfx_driver->show_video_bitmap(bitmap);
+
+   return al_scroll_display(display, bitmap->x_ofs, bitmap->y_ofs);
+}
+
+
+
+/* al_request_video_bitmap:
+ *  Triple buffering function: triggers a swap to display the specified 
+ *  video memory bitmap object, which will take place on the next retrace.
+ */
+int al_request_video_bitmap(AL_DISPLAY *display, BITMAP *bitmap)
+{
+   if ((!is_video_bitmap(bitmap)) || 
+       (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
+       (_dispsw_status))
+      return -1;
+
+   if (display->gfx_driver->request_video_bitmap)
+      return display->gfx_driver->request_video_bitmap(bitmap);
+
+   return al_request_scroll(display, bitmap->x_ofs, bitmap->y_ofs);
+}
+
+
+
+/* al_enable_triple_buffer:
+ *  Asks a driver to turn on triple buffering mode, if it is capable
+ *  of that.
+ */
+int al_enable_triple_buffer(AL_DISPLAY *display)
+{
+   if (display->gfx_capabilities & GFX_CAN_TRIPLE_BUFFER)
+      return 0;
+
+   if (_dispsw_status)
+      return -1;
+
+   if (display->gfx_driver->enable_triple_buffer) {
+      display->gfx_driver->enable_triple_buffer();
+
+      if ((display->gfx_driver->request_scroll) || (display->gfx_driver->request_video_bitmap)) {
+	 display->gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
+	 return 0;
+      }
+   }
+
+   return -1;
+}
+
+
+
+/* al_create_display
+ * Create a new Allegro display object, return NULL on failure
+ * The first display object created becomes the al_main_display
+ */
+AL_DISPLAY *al_create_display(int driver, int flags, int depth, int w, int h, int v_w, int v_h)
+{
+   AL_DISPLAY *new_display;
+   int c;
+
+   ASSERT(system_driver);
+   
+   /* It's an error to select more than one update method */
+   if ( (flags & AL_UPDATE_ALL) & ( (flags & AL_UPDATE_ALL) - 1) )
+      return NULL;
+
+   /* Create a new display object */
+   new_display = _al_vector_alloc_back(&display_list);
+
+   if (!new_display)
+      return NULL;
+      
+   memset(new_display, 0, sizeof *new_display);
+      
+   /* Adjust virtual width and virtual height if needed and allowed */
+#ifdef ALLEGRO_VRAM_SINGLE_SURFACE
+   if ((v_w==0) && (v_h==0) && (flags&(AL_UPDATE_TRIPLE_BUFFER|AL_UPDATE_PAGE_FLIP))) {
+      v_w = w;
+      v_h = h * (flags&AL_UPDATE_TRIPLE_BUFFER?3:2);
+   }
+#endif
+
+   /* Set graphics mode */
+   gfx_capabilities = 0;
+   if (depth>0)
+      set_color_depth(depth);
+   if (do_set_gfx_mode(new_display, driver, w, h, v_w, v_h, depth) == -1) {
+      free(new_display);
+      return NULL;
+   }
+   
+   new_display->page = NULL;
+   new_display->num_pages = 0;
+   new_display->active_page = 0;
+   new_display->flags = flags;
+   new_display->depth = get_color_depth();
+   new_display->gfx_capabilities |= gfx_capabilities;
+   
+   /* Select update method */
+   switch(new_display->flags & AL_UPDATE_ALL) {
+      case AL_UPDATE_TRIPLE_BUFFER:
+         /* Try to enable triple buffering */
+         if (!(new_display->gfx_capabilities & GFX_CAN_TRIPLE_BUFFER))
+            al_enable_triple_buffer(new_display);
+
+         if (new_display->gfx_capabilities & GFX_CAN_TRIPLE_BUFFER) {
+            new_display->num_pages = 3;
+            new_display->page = malloc(new_display->num_pages * sizeof *(new_display->page));
+
+            for (c=0; c<new_display->num_pages; c++)
+               new_display->page[c] = al_create_video_bitmap(new_display, w, h);
+            
+            /* Check for succes */
+            if (new_display->page[0] && new_display->page[1] && new_display->page[2]) {
+               for (c=0; c<new_display->num_pages; c++)
+                  clear_bitmap(new_display->page[c]);
+               al_show_video_bitmap(new_display, new_display->page[2]);
+            }
+            else {
+               for (c=0; c<new_display->num_pages; c++)
+                  destroy_bitmap(new_display->page[c]);
+               free(new_display->page);
+               do_set_gfx_mode(new_display, GFX_TEXT, 0, 0, 0, 0, 0);
+               free(new_display);
+               return NULL;
+            }
+         }
+         else {
+            do_set_gfx_mode(new_display, GFX_TEXT, 0, 0, 0, 0, 0);
+            free(new_display);
+            return NULL;
+         }
+         break;
+
+      case AL_UPDATE_PAGE_FLIP:
+         new_display->num_pages = 2;
+         new_display->page = malloc(new_display->num_pages * sizeof *(new_display->page));
+
+         for (c=0; c<new_display->num_pages; c++)
+            new_display->page[c] = al_create_video_bitmap(new_display, w, h);
+         
+         /* Check for succes */
+         if (new_display->page[0] && new_display->page[1]) {
+            for (c=0; c<new_display->num_pages; c++)
+               clear_bitmap(new_display->page[c]);
+            al_show_video_bitmap(new_display, new_display->page[1]);
+         }
+         else {
+            for (c=0; c<new_display->num_pages; c++)
+               destroy_bitmap(new_display->page[c]);
+            free(new_display->page);
+            do_set_gfx_mode(new_display, GFX_TEXT, 0, 0, 0, 0, 0);
+            free(new_display);
+            return NULL;
+         }
+         break;
+
+      case AL_UPDATE_SYSTEM_BUFFER:
+      case AL_UPDATE_DOUBLE_BUFFER:
+         new_display->num_pages = 1;
+         new_display->page = malloc(new_display->num_pages * sizeof *(new_display->page));
+
+         for (c=0; c<new_display->num_pages; c++)
+            if (new_display->flags & AL_UPDATE_SYSTEM_BUFFER)
+               new_display->page[c] = al_create_system_bitmap(new_display, w, h);
+            else
+               new_display->page[c] = create_bitmap(w, h);
+         
+         /* Check for succes */
+         if (new_display->page[0]) {
+            for (c=0; c<new_display->num_pages; c++)
+               clear_bitmap(new_display->page[c]);
+            al_show_video_bitmap(new_display, new_display->page[1]);
+         }
+         else {
+            for (c=0; c<new_display->num_pages; c++)
+               destroy_bitmap(new_display->page[c]);
+            free(new_display->page);
+            do_set_gfx_mode(new_display, GFX_TEXT, 0, 0, 0, 0, 0);
+            free(new_display);
+            return NULL;
+         }
+         break;
+   }
+   
+   gfx_capabilities |= new_display->gfx_capabilities;
+   
+   if (!al_main_display)
+      al_main_display = new_display;
+      
+   return new_display;
+}
+
+/* al_set_update_method:
+ * Change the update method for the selected display. If the method change 
+ * fails the current method is either retained or reset to AL_UPDATE_NONE.
+ * Returns the method being used after this call.
+ */
+int al_set_update_method(AL_DISPLAY *display, int method)
+{
+   int c, w, h;
+   ASSERT(display);
+   ASSERT(display->gfx_driver);
+
+   /* Requesting multiple modes is not valid */
+   if ( (method & (method - 1)) ||  (method & ~AL_UPDATE_ALL) )
+      return display->flags & AL_UPDATE_ALL;
+
+   /* Do nothing if the methods are the same */      
+   if (method == (display->flags & AL_UPDATE_ALL))
+      return display->flags & AL_UPDATE_ALL;
+
+   /* Retain current method if triple buffering was requested, but can't work */
+   if ( (method & AL_UPDATE_TRIPLE_BUFFER) && 
+        (!(display->gfx_capabilities & GFX_CAN_TRIPLE_BUFFER)))
+      return display->flags & AL_UPDATE_ALL;
+      
+   /* Destroy old setup */
+   display->flags &= ~AL_UPDATE_ALL;
+   for(c=0; c<display->num_pages; c++)
+      destroy_bitmap(display->page[c]);
+   free(display->page);
+   display->page = NULL;
+   display->num_pages = 0;
+   display->active_page = 0;
+
+   w = display->gfx_driver->w;
+   h = display->gfx_driver->h;
+
+   /* Set new method */
+   switch(method) {
+      case AL_UPDATE_TRIPLE_BUFFER:
+         display->num_pages = 3;
+         display->page = malloc(display->num_pages * sizeof *(display->page));
+
+         for (c=0; c<display->num_pages; c++)
+            display->page[c] = al_create_video_bitmap(display, w, h);
+            
+         /* Check for succes */
+         if (display->page[0] && display->page[1] && display->page[2]) {
+            for (c=0; c<display->num_pages; c++)
+               clear_bitmap(display->page[c]);
+            al_show_video_bitmap(display, display->page[2]);
+            display->flags |= method;
+         }
+         else {
+            for (c=0; c<display->num_pages; c++)
+               destroy_bitmap(display->page[c]);
+            display->page = NULL;
+            display->num_pages = 0;
+         }
+         break;
+
+      case AL_UPDATE_PAGE_FLIP:
+         display->num_pages = 2;
+         display->page = malloc(display->num_pages * sizeof *(display->page));
+
+         for (c=0; c<display->num_pages; c++)
+            display->page[c] = al_create_video_bitmap(display, w, h);
+         
+         /* Check for succes */
+         if (display->page[0] && display->page[1]) {
+            for (c=0; c<display->num_pages; c++)
+               clear_bitmap(display->page[c]);
+            al_show_video_bitmap(display, display->page[1]);
+            display->flags |= method;
+         }
+         else {
+            for (c=0; c<display->num_pages; c++)
+               destroy_bitmap(display->page[c]);
+            display->page = NULL;
+            display->num_pages = 0;
+         }
+         break;
+
+      case AL_UPDATE_SYSTEM_BUFFER:
+      case AL_UPDATE_DOUBLE_BUFFER:
+         display->num_pages = 1;
+         display->page = malloc(display->num_pages * sizeof *(display->page));
+
+         for (c=0; c<display->num_pages; c++)
+            if (display->flags & AL_UPDATE_SYSTEM_BUFFER)
+               display->page[c] = al_create_system_bitmap(display, w, h);
+            else
+               display->page[c] = create_bitmap(w, h);
+         
+         /* Check for succes */
+         if (display->page[0]) {
+            for (c=0; c<display->num_pages; c++)
+               clear_bitmap(display->page[c]);
+            al_show_video_bitmap(display, display->page[1]);
+            display->flags |= method;
+         }
+         else {
+            for (c=0; c<display->num_pages; c++)
+               destroy_bitmap(display->page[c]);
+            display->page = NULL;
+            display->num_pages = 0;
+         }
+         break;
+   }
+
+   return display->flags & AL_UPDATE_ALL;
+}
+
+/* al_destroy_display:
+ * Destroys an Allegro display and returns to text mode
+ */
+void al_destroy_display(AL_DISPLAY *display)
+{
+   int c;
+   
+   ASSERT(system_driver);
+   
+   if (!display)
+      return;
+
+   for(c=0; c<display->num_pages; c++)
+      destroy_bitmap(display->page[c]);
+   free(display->page);
+   
+   do_set_gfx_mode(display, GFX_TEXT, 0, 0, 0, 0, 0);
+   
+   if (display == al_main_display)
+      al_main_display = NULL;
+
+   /* Remove the display from the list */   
+   for (c = 0; c < _al_vector_size(&display_list); c++) {
+      AL_DISPLAY *dpy = _al_vector_ref(&display_list, c);
+      if (dpy == display) {
+         _al_vector_delete_at(&display_list, c);
+         break;
+      }
+   }
+}
+
+/* al_flip_display:
+ * Flip the front and back buffers
+ */
+void al_flip_display(AL_DISPLAY *display)
+{
+   ASSERT(display);
+
+   switch(display->flags & AL_UPDATE_ALL) {
+      case AL_UPDATE_TRIPLE_BUFFER:
+         while (al_poll_scroll(display));
+         al_request_video_bitmap(display, display->page[display->active_page]);
+         
+         display->active_page = (display->active_page+1)%display->num_pages;
+         return;
+
+      case AL_UPDATE_PAGE_FLIP:
+         al_show_video_bitmap(display, display->page[display->active_page]);
+
+         display->active_page = (display->active_page+1)%display->num_pages;
+         return;
+
+      case AL_UPDATE_SYSTEM_BUFFER:
+      case AL_UPDATE_DOUBLE_BUFFER:
+         /* Wait for vsync */
+         if (!(display->flags&AL_DISABLE_VSYNC))
+            vsync();
+         blit(display->page[0], display->screen, 0, 0, 0, 0, display->page[0]->w, display->page[0]->h);
+         return;
+   } /* End of switch */
+}
+
+/* al_get_buffer:
+ * Get a pointer to the backbuffer
+ */
+BITMAP *al_get_buffer(const AL_DISPLAY *display)
+{
+   ASSERT(display);
+   
+   if (display->flags & AL_UPDATE_ALL)
+      return display->page[display->active_page];
+      
+   return display->screen;
+}
+
+/* al_get_update_method:
+ * Get the update method being used to update the display
+ */
+int al_get_update_method(const AL_DISPLAY *display)
+{
+   ASSERT(system_driver);
+
+   return display->flags & AL_UPDATE_ALL;
+}
+
+
+/* VSync settings */
+
+/* al_enable_vsync:
+ * Enable vsync for the display
+ */
+void al_enable_vsync(AL_DISPLAY *display)
+{
+   ASSERT(display);
+   
+   display->flags&=~AL_DISABLE_VSYNC;
+}
+
+/* al_disable_vsync:
+ * disable vsync for the display
+ */
+void al_disable_vsync(AL_DISPLAY *display)
+{
+   ASSERT(display);
+   
+   display->flags|=AL_DISABLE_VSYNC;
+}
+
+/* al_toggle_vsync:
+ * Toggle vsync for the display
+ */
+void al_toggle_vsync(AL_DISPLAY *display)
+{
+   ASSERT(display);
+   
+   display->flags^=AL_DISABLE_VSYNC;
+}
+
+/* al_vsync_is_enabled:
+ * returns TRUE if vsync is enabled on the display
+ */
+int al_vsync_is_enabled(const AL_DISPLAY *display)
+{
+   ASSERT(display);
+   
+   return (display->flags&AL_DISABLE_VSYNC) == 0;
+}
+
+/***********************/
+/* Compatibility stuff */
+/***********************/
+int set_gfx_mode(int card, int w, int h, int v_w, int v_h)
+{
+   al_destroy_display(al_main_display);
+   
+   al_create_display(card, 0, get_color_depth(), w, h, v_w, v_h);
+   if (!al_main_display) {
+      return -1;
+   }
+
+   screen = al_main_display->screen;
+   gfx_driver = al_main_display->gfx_driver;
+   
+   return 0;
+}
+
+
+
+BITMAP *create_video_bitmap(int width, int height)
+{
+   return al_create_video_bitmap(al_main_display, width, height);
+}
+
+
+
+BITMAP *create_system_bitmap(int width, int height)
+{
+   return al_create_system_bitmap(al_main_display, width, height);
+}
+
+
+
+int scroll_screen(int x, int y)
+{
+   return al_scroll_display(al_main_display, x, y);
+}
+
+int request_scroll(int x, int y)
+{
+   return al_request_scroll(al_main_display, x, y);
+}
+
+int poll_scroll(void)
+{
+   return al_poll_scroll(al_main_display);
+}
+
+int show_video_bitmap(BITMAP *bitmap)
+{
+   return al_show_video_bitmap(al_main_display, bitmap);
+}
+
+int request_video_bitmap(BITMAP *bitmap)
+{
+   return al_request_video_bitmap(al_main_display, bitmap);
+}
+
+int enable_triple_buffer(void)
+{
+   return al_enable_triple_buffer(al_main_display);
+}
diff -N -u -r allegro/src/graphics.c allegro-new-gfx/src/graphics.c
--- allegro/src/graphics.c	2003-12-28 22:37:51.000000000 +0100
+++ allegro-new-gfx/src/graphics.c	2004-08-27 16:31:53.000000000 +0200
@@ -23,8 +23,6 @@
 
 
 
-static int gfx_virgin = TRUE;          /* is the graphics system active? */
-
 int _sub_bitmap_id_count = 1;          /* hash value for sub-bitmaps */
 
 int _gfx_mode_set_count = 0;           /* has the graphics mode changed? */
@@ -114,25 +112,6 @@
 GFX_VTABLE _screen_vtable;             /* accelerated drivers change this */
 
 
-typedef struct VRAM_BITMAP             /* list of video memory bitmaps */
-{
-   int x, y, w, h;
-   BITMAP *bmp;
-   struct VRAM_BITMAP *next_x, *next_y;
-} VRAM_BITMAP;
-
-
-static VRAM_BITMAP *vram_bitmap_list = NULL;
-
-
-#define BMP_MAX_SIZE  46340   /* sqrt(INT_MAX) */
-
-/* the product of these must fit in an int */
-static int failed_bitmap_w = BMP_MAX_SIZE;
-static int failed_bitmap_h = BMP_MAX_SIZE;
-
-
-
 /* lock_bitmap:
  *  Locks all the memory used by a bitmap structure.
  */
@@ -402,565 +381,6 @@
 
 
 
-/* _get_vtable:
- *  Returns a pointer to the linear vtable for the specified color depth.
- */
-GFX_VTABLE *_get_vtable(int color_depth)
-{
-   GFX_VTABLE *vt;
-   int i;
-
-   ASSERT(system_driver);
-
-   if (system_driver->get_vtable) {
-      vt = system_driver->get_vtable(color_depth);
-
-      if (vt) {
-	 LOCK_DATA(vt, sizeof(GFX_VTABLE));
-	 LOCK_CODE(vt->draw_sprite, (long)vt->draw_sprite_end - (long)vt->draw_sprite);
-	 LOCK_CODE(vt->blit_from_memory, (long)vt->blit_end - (long)vt->blit_from_memory);
-	 return vt;
-      }
-   }
-
-   for (i=0; _vtable_list[i].vtable; i++) {
-      if (_vtable_list[i].color_depth == color_depth) {
-	 LOCK_DATA(_vtable_list[i].vtable, sizeof(GFX_VTABLE));
-	 LOCK_CODE(_vtable_list[i].vtable->draw_sprite, (long)_vtable_list[i].vtable->draw_sprite_end - (long)_vtable_list[i].vtable->draw_sprite);
-	 LOCK_CODE(_vtable_list[i].vtable->blit_from_memory, (long)_vtable_list[i].vtable->blit_end - (long)_vtable_list[i].vtable->blit_from_memory);
-	 return _vtable_list[i].vtable;
-      }
-   }
-
-   return NULL;
-}
-
-
-
-/* shutdown_gfx:
- *  Used by allegro_exit() to return the system to text mode.
- */
-static void shutdown_gfx(void)
-{
-   if (gfx_driver)
-      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
-
-   if (system_driver->restore_console_state)
-      system_driver->restore_console_state();
-
-   _remove_exit_func(shutdown_gfx);
-
-   gfx_virgin = TRUE;
-}
-
-
-#define GFX_DRIVER_FULLSCREEN_FLAG    0x01
-#define GFX_DRIVER_WINDOWED_FLAG      0x02
-
-
-/* gfx_driver_is_valid:
- *  Checks that the graphics driver 'drv' fulfills the condition
- *  expressed by the bitmask 'flags'.
- */
-static int gfx_driver_is_valid(GFX_DRIVER *drv, int flags)
-{
-   if ((flags & GFX_DRIVER_FULLSCREEN_FLAG) && drv->windowed)
-      return FALSE;
-
-   if ((flags & GFX_DRIVER_WINDOWED_FLAG) && !drv->windowed)
-      return FALSE;
-
-   return TRUE;
-}
-
-
-
-/* get_gfx_driver_from_id:
- *  Retrieves a pointer to the graphics driver identified by 'card' from
- *  the list 'driver_list' or NULL if it doesn't exist.
- */
-static GFX_DRIVER *get_gfx_driver_from_id(int card, _DRIVER_INFO *driver_list)
-{
-   int c;
-
-   for (c=0; driver_list[c].driver; c++) {
-      if (driver_list[c].id == card)
-	 return driver_list[c].driver;
-   }
-
-   return NULL;
-}
-
-
-
-/* init_gfx_driver:
- *  Helper function for initializing a graphics driver.
- */
-static BITMAP *init_gfx_driver(GFX_DRIVER *drv, int w, int h, int v_w, int v_h)
-{
-   drv->name = drv->desc = get_config_text(drv->ascii_name);
-
-   /* set gfx_driver so that it is visible when initializing the driver */
-   gfx_driver = drv;
-
-   return drv->init(w, h, v_w, v_h, _color_depth);
-}
-
-
-
-/* get_config_gfx_driver:
- *  Helper function for set_gfx_mode: it reads the gfx_card* config variables and
- *  tries to set the graphics mode if a matching driver is found. Returns TRUE if
- *  at least one matching driver was found, FALSE otherwise.
- */
-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)
-{
-   char buf[512], tmp[64];
-   GFX_DRIVER *drv;
-   int found = FALSE;
-   int card, n;
-
-   /* try the drivers that are listed in the config file */
-   for (n=-2; n<255; n++) {
-      switch (n) {
-
-	 case -2:
-	    /* example: gfx_card_640x480x16 = */
-	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dx%dx%d", tmp), gfx_card, w, h, _color_depth);
-	    break;
-
-	 case -1:
-	    /* example: gfx_card_24bpp = */
-	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s_%dbpp", tmp), gfx_card, _color_depth);
-	    break;
-
-	 case 0:
-	    /* example: gfx_card = */
-	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s", tmp), gfx_card);
-	    break;
-
-	 default:
-	    /* example: gfx_card1 = */
-	    uszprintf(buf, sizeof(buf), uconvert_ascii("%s%d", tmp), gfx_card, n);
-	    break;
-      }
-
-      card = get_config_id(uconvert_ascii("graphics", tmp), buf, 0);
-
-      if (card) {
-	 drv = get_gfx_driver_from_id(card, driver_list);
-
-	 if (drv && gfx_driver_is_valid(drv, flags)) {
-	    found = TRUE;
-	    screen = init_gfx_driver(drv, w, h, v_w, v_h);
-
-	    if (screen)
-	       break;
-	 }
-      }
-      else {
-	 /* Stop searching the gfx_card#n (n>0) family at the first missing member,
-	  * except gfx_card1 which could have been identified with gfx_card.
-	  */
-	 if (n > 1)
-	    break;
-      }
-   }
-
-   return found;
-}
-
-
-
-/* set_gfx_mode:
- *  Sets the graphics mode. The card should be one of the GFX_* constants
- *  from allegro.h, or GFX_AUTODETECT to accept any graphics driver. Pass
- *  GFX_TEXT to return to text mode (although allegro_exit() will usually 
- *  do this for you). The w and h parameters specify the screen resolution 
- *  you want, and v_w and v_h specify the minumum virtual screen size. 
- *  The graphics drivers may actually create a much larger virtual screen, 
- *  so you should check the values of VIRTUAL_W and VIRTUAL_H after you
- *  set the mode. If unable to select an appropriate mode, this function 
- *  returns -1.
- */
-int set_gfx_mode(int card, int w, int h, int v_w, int v_h)
-{
-   static int allow_config = TRUE;
-   extern void blit_end(void);
-   _DRIVER_INFO *driver_list;
-   GFX_DRIVER *drv;
-   struct GFX_MODE mode;
-   char buf[ALLEGRO_ERROR_SIZE], tmp1[64], tmp2[64];
-   AL_CONST char *dv;
-   int flags = 0;
-   int c, driver, ret;
-   ASSERT(system_driver);
-
-   _gfx_mode_set_count++;
-
-   /* special bodge for the GFX_SAFE driver */
-   if (card == GFX_SAFE) {
-      if (system_driver->get_gfx_safe_mode) {
-	 ustrzcpy(buf, sizeof(buf), allegro_error);
-
-	 /* retrieve the safe graphics mode */
-	 system_driver->get_gfx_safe_mode(&driver, &mode);
-
-	 /* try using the specified depth and resolution */
-	 if (set_gfx_mode(driver, w, h, 0, 0) == 0)
-	    return 0;
-
-	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, buf);
-
-	 /* finally use the safe settings */
-	 set_color_depth(mode.bpp);
-	 if (set_gfx_mode(driver, mode.width, mode.height, 0, 0) == 0)
-	    return 0;
-
-	 ASSERT(FALSE);  /* the safe graphics mode must always work */
-      }
-      else {
-	 /* no safe graphics mode, try hard-coded autodetected modes with custom settings */
-	 allow_config = FALSE;
-	 _safe_gfx_mode_change = 1;
-
-	 ret = set_gfx_mode(GFX_AUTODETECT, w, h, 0, 0);
-
-	 _safe_gfx_mode_change = 0;
-	 allow_config = TRUE;
-
-	 if (ret == 0)
-	    return 0;
-      }
-
-      /* failing to set GFX_SAFE is a fatal error */
-      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
-      allegro_message(uconvert_ascii("%s\n", tmp1), get_config_text("Fatal error: unable to set GFX_SAFE"));
-      return -1;
-   }
-
-   /* remember the current console state */
-   if (gfx_virgin) {
-      LOCK_FUNCTION(_stub_bank_switch);
-      LOCK_FUNCTION(blit);
-
-      if (system_driver->save_console_state)
-	 system_driver->save_console_state();
-
-      _add_exit_func(shutdown_gfx);
-
-      gfx_virgin = FALSE;
-   }
-
-   /* lock the application in the foreground */
-   if (system_driver->display_switch_lock)
-      system_driver->display_switch_lock(TRUE, TRUE);
-
-   timer_simulate_retrace(FALSE);
-   _screen_split_position = 0;
-
-   /* close down any existing graphics driver */
-   if (gfx_driver) {
-      if (_al_linker_mouse)
-         _al_linker_mouse->show_mouse(NULL);
-
-      while (vram_bitmap_list)
-	 destroy_bitmap(vram_bitmap_list->bmp);
-
-      bmp_read_line(screen, 0);
-      bmp_write_line(screen, 0);
-      bmp_unwrite_line(screen);
-
-      if (gfx_driver->scroll)
-	 gfx_driver->scroll(0, 0);
-
-      if (gfx_driver->exit)
-	 gfx_driver->exit(screen);
-
-      destroy_bitmap(screen);
-
-      gfx_driver = NULL;
-      screen = NULL;
-      gfx_capabilities = 0;
-   }
-
-   /* We probably don't want to do this because it makes
-    * Allegro "forget" the color layout of previously set
-    * graphics modes. But it should be retained if bitmaps
-    * created in those modes are to be used in the new mode.
-    */
-#if 0
-   /* restore default truecolor pixel format */
-   _rgb_r_shift_15 = 0; 
-   _rgb_g_shift_15 = 5;
-   _rgb_b_shift_15 = 10;
-   _rgb_r_shift_16 = 0;
-   _rgb_g_shift_16 = 5;
-   _rgb_b_shift_16 = 11;
-   _rgb_r_shift_24 = 0;
-   _rgb_g_shift_24 = 8;
-   _rgb_b_shift_24 = 16;
-   _rgb_r_shift_32 = 0;
-   _rgb_g_shift_32 = 8;
-   _rgb_b_shift_32 = 16;
-   _rgb_a_shift_32 = 24;
-#endif
-
-   gfx_capabilities = 0;
-
-   _set_current_refresh_rate(0);
-
-   /* return to text mode? */
-   if (card == GFX_TEXT) {
-      if (system_driver->restore_console_state)
-	 system_driver->restore_console_state();
-
-      if (_gfx_bank) {
-	 free(_gfx_bank);
-	 _gfx_bank = NULL;
-      }
-
-      if (system_driver->display_switch_lock)
-	 system_driver->display_switch_lock(FALSE, FALSE);
-
-      return 0;
-   }
-
-   /* now to the interesting part: let's try to find a graphics driver */
-   usetc(allegro_error, 0);
-
-   /* ask the system driver for a list of graphics hardware drivers */
-   if (system_driver->gfx_drivers)
-      driver_list = system_driver->gfx_drivers();
-   else
-      driver_list = _gfx_driver_list;
-
-   /* filter specific fullscreen/windowed driver requests */
-   if (card == GFX_AUTODETECT_FULLSCREEN) {
-      flags |= GFX_DRIVER_FULLSCREEN_FLAG;
-      card = GFX_AUTODETECT;
-   }
-   else if (card == GFX_AUTODETECT_WINDOWED) {
-      flags |= GFX_DRIVER_WINDOWED_FLAG;
-      card = GFX_AUTODETECT;
-   }
-
-   if (card == GFX_AUTODETECT) {
-      /* autodetect the driver */
-      int found = FALSE;
-
-      /* first try the config variables */
-      if (allow_config) {
-	 /* try the gfx_card variable if GFX_AUTODETECT or GFX_AUTODETECT_FULLSCREEN was selected */
-	 if (!(flags & GFX_DRIVER_WINDOWED_FLAG))
-	    found = get_config_gfx_driver(uconvert_ascii("gfx_card", tmp1), w, h, v_w, v_h, flags, driver_list);
-
-	 /* try the gfx_cardw variable if GFX_AUTODETECT or GFX_AUTODETECT_WINDOWED was selected */
-	 if (!(flags & GFX_DRIVER_FULLSCREEN_FLAG) && !found)
-	    found = get_config_gfx_driver(uconvert_ascii("gfx_cardw", tmp1), w, h, v_w, v_h, flags, driver_list);
-      }
-
-      /* go through the list of autodetected drivers if none was previously found */
-      if (!found) {
-	 for (c=0; driver_list[c].driver; c++) {
-	    if (driver_list[c].autodetect) {
-	       drv = driver_list[c].driver;
-
-	       if (gfx_driver_is_valid(drv, flags)) {
-		  screen = init_gfx_driver(drv, w, h, v_w, v_h);
-
-		  if (screen)
-		     break;
-	       }
-	    }
-	 }
-      }
-   }
-   else {
-      /* search the list for the requested driver */
-      drv = get_gfx_driver_from_id(card, driver_list);
-
-      if (drv)
-	 screen = init_gfx_driver(drv, w, h, v_w, v_h);
-   }
-
-   /* gracefully handle failure */
-   if (!screen) {
-      gfx_driver = NULL;  /* set by init_gfx_driver() */
-
-      if (!ugetc(allegro_error))
-	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to find a suitable graphics driver"));
-
-      if (system_driver->display_switch_lock)
-	 system_driver->display_switch_lock(FALSE, FALSE);
-
-      return -1;
-   }
-
-   /* set the basic capabilities of the driver */
-   if ((VIRTUAL_W > SCREEN_W) || (VIRTUAL_H > SCREEN_H)) {
-      if (gfx_driver->scroll)
-	 gfx_capabilities |= GFX_CAN_SCROLL;
-
-      if ((gfx_driver->request_scroll) || (gfx_driver->request_video_bitmap))
-	 gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
-   }
-
-   /* check whether we are instructed to disable vsync */
-   dv = get_config_string(uconvert_ascii("graphics", tmp1),
-                          uconvert_ascii("disable_vsync", tmp2),
-                          NULL);
-
-   if ((dv) && ((c = ugetc(dv)) != 0) && ((c == 'y') || (c == 'Y') || (c == '1')))
-      _wait_for_vsync = FALSE;
-   else
-      _wait_for_vsync = TRUE;
-
-   clear_bitmap(screen);
-
-   /* set up the default colors */
-   for (c=0; c<256; c++)
-      _palette_color8[c] = c;
-
-   set_palette(default_palette);
-
-   if (_color_depth == 8) {
-      gui_fg_color = 255;
-      gui_mg_color = 8;
-      gui_bg_color = 0;
-   }
-   else {
-      gui_fg_color = makecol(0, 0, 0);
-      gui_mg_color = makecol(128, 128, 128);
-      gui_bg_color = makecol(255, 255, 255);
-   }
-
-   if (_al_linker_mouse)
-      _al_linker_mouse->set_mouse_etc();
-
-   LOCK_DATA(gfx_driver, sizeof(GFX_DRIVER));
-
-   _register_switch_bitmap(screen, NULL);
-
-   if (system_driver->display_switch_lock)
-      system_driver->display_switch_lock(FALSE, FALSE);
-
-   return 0;
-} 
-
-
-
-/* _sort_out_virtual_width:
- *  Decides how wide the virtual screen really needs to be. That is more 
- *  complicated than it sounds, because the Allegro graphics primitives 
- *  require that each scanline be contained within a single bank. That 
- *  causes problems on cards that don't have overlapping banks, unless the 
- *  bank size is a multiple of the virtual width. So we may need to adjust 
- *  the width just to keep things running smoothly...
- */
-void _sort_out_virtual_width(int *width, GFX_DRIVER *driver)
-{
-   int w = *width;
-
-   /* hah! I love VBE 2.0... */
-   if (driver->linear)
-      return;
-
-   /* if banks can overlap, we are ok... */ 
-   if (driver->bank_size > driver->bank_gran)
-      return;
-
-   /* damn, have to increase the virtual width */
-   while (((driver->bank_size / w) * w) != driver->bank_size) {
-      w++;
-      if (w > driver->bank_size)
-	 break; /* oh shit */
-   }
-
-   *width = w;
-}
-
-
-
-/* _make_bitmap:
- *  Helper function for creating the screen bitmap. Sets up a bitmap 
- *  structure for addressing video memory at addr, and fills the bank 
- *  switching table using bank size/granularity information from the 
- *  specified graphics driver.
- */
-BITMAP *_make_bitmap(int w, int h, unsigned long addr, GFX_DRIVER *driver, int color_depth, int bpl)
-{
-   GFX_VTABLE *vtable = _get_vtable(color_depth);
-   int i, bank, size;
-   BITMAP *b;
-
-   if (!vtable)
-      return NULL;
-
-   size = sizeof(BITMAP) + sizeof(char *) * h;
-
-   b = (BITMAP *)malloc(size);
-   if (!b)
-      return NULL;
-
-   _gfx_bank = realloc(_gfx_bank, h * sizeof(int));
-   if (!_gfx_bank) {
-      free(b);
-      return NULL;
-   }
-
-   LOCK_DATA(b, size);
-   LOCK_DATA(_gfx_bank, h * sizeof(int));
-
-   b->w = b->cr = w;
-   b->h = b->cb = h;
-   b->clip = TRUE;
-   b->cl = b->ct = 0;
-   b->vtable = &_screen_vtable;
-   b->write_bank = b->read_bank = _stub_bank_switch;
-   b->dat = NULL;
-   b->id = BMP_ID_VIDEO;
-   b->extra = NULL;
-   b->x_ofs = 0;
-   b->y_ofs = 0;
-   b->seg = _video_ds();
-
-   memcpy(&_screen_vtable, vtable, sizeof(GFX_VTABLE));
-   LOCK_DATA(&_screen_vtable, sizeof(GFX_VTABLE));
-
-   _last_bank_1 = _last_bank_2 = -1;
-
-   driver->vid_phys_base = addr;
-
-   b->line[0] = (unsigned char *)addr;
-   _gfx_bank[0] = 0;
-
-   if (driver->linear) {
-      for (i=1; i<h; i++) {
-	 b->line[i] = b->line[i-1] + bpl;
-	 _gfx_bank[i] = 0;
-      }
-   }
-   else {
-      bank = 0;
-
-      for (i=1; i<h; i++) {
-	 b->line[i] = b->line[i-1] + bpl;
-	 if (b->line[i]+bpl-1 >= (unsigned char *)addr + driver->bank_size) {
-	    while (b->line[i] >= (unsigned char *)addr + driver->bank_gran) {
-	       b->line[i] -= driver->bank_gran;
-	       bank++;
-	    }
-	 }
-	 _gfx_bank[i] = bank;
-      }
-   }
-
-   return b;
-}
-
-
-
 /* create_bitmap_ex
  *  Creates a new memory bitmap in the specified color_depth
  */
@@ -1120,299 +540,6 @@
 
 
 
-/* add_vram_block:
- *  Creates a video memory bitmap out of the specified region
- *  of the larger screen surface, returning a pointer to it.
- */
-static BITMAP *add_vram_block(int x, int y, int w, int h)
-{
-   VRAM_BITMAP *b, *new_b;
-   VRAM_BITMAP **last_p;
-
-   new_b = malloc(sizeof(VRAM_BITMAP));
-   if (!new_b)
-      return NULL;
-
-   new_b->x = x;
-   new_b->y = y;
-   new_b->w = w;
-   new_b->h = h;
-
-   new_b->bmp = create_sub_bitmap(screen, x, y, w, h);
-   if (!new_b->bmp) {
-      free(new_b);
-      return NULL;
-   }
-
-   /* find sorted y-position */
-   last_p = &vram_bitmap_list;
-   for (b = vram_bitmap_list; b && (b->y < new_b->y); b = b->next_y)
-      last_p = &b->next_y;
-
-   /* insert */
-   *last_p = new_b;
-   new_b->next_y = b;
-
-   return new_b->bmp;
-}
-
-
-
-/* create_video_bitmap:
- *  Attempts to make a bitmap object for accessing offscreen video memory.
- *
- *  The algorithm is similar to algorithms for drawing polygons. Think of
- *  a horizontal stripe whose height is equal to that of the new bitmap.
- *  It is initially aligned to the top of video memory and then it moves
- *  downwards, stopping each time its top coincides with the bottom of a
- *  video bitmap. For each stop, create a list of video bitmaps intersecting
- *  the stripe, sorted by the left coordinate, from left to right, in the
- *  next_x linked list. We look through this list and stop as soon as the
- *  gap between the rightmost right edge seen so far and the current left
- *  edge is big enough for the new video bitmap. In that case, we are done.
- *  If we don't find such a gap, we move the stripe further down.
- *
- *  To make it efficient to find new bitmaps intersecting the stripe, the
- *  list of all bitmaps is always sorted by top, from top to bottom, in
- *  the next_y linked list. The list of bitmaps intersecting the stripe is
- *  merely updated, not recalculated from scratch, when we move the stripe.
- *  So every bitmap gets bubbled to its correct sorted x-position at most
- *  once. Bubbling a bitmap takes at most as many steps as the number of
- *  video bitmaps. So the algorithm behaves at most quadratically with
- *  regard to the number of video bitmaps. I think that a linear behaviour
- *  is more typical in practical applications (this happens, for instance,
- *  if you allocate many bitmaps of the same height).
- *
- *  There's one more optimization: if a call fails, we cache the size of the
- *  requested bitmap, so that next time we can detect very quickly that this
- *  size is too large (this needs to be maintained when destroying bitmaps).
- */
-BITMAP *create_video_bitmap(int width, int height)
-{
-   VRAM_BITMAP *active_list, *b, *vram_bitmap;
-   VRAM_BITMAP **last_p;
-   BITMAP *bmp;
-   int x = 0, y = 0;
-
-   ASSERT(width >= 0);
-   ASSERT(height > 0);
-   
-   if (_dispsw_status)
-      return NULL;
-
-   /* let the driver handle the request if it can */
-   if (gfx_driver->create_video_bitmap) {
-      bmp = gfx_driver->create_video_bitmap(width, height);
-      if (!bmp)
-	 return NULL;
-
-      b = malloc(sizeof(VRAM_BITMAP));
-      b->x = -1;
-      b->y = -1;
-      b->w = 0;
-      b->h = 0;
-      b->bmp = bmp;
-      b->next_y = vram_bitmap_list;
-      vram_bitmap_list = b;
-
-      return bmp;
-   }
-
-   /* check bad args */
-   if ((width > VIRTUAL_W) || (height > VIRTUAL_H) ||
-       (width < 0) || (height < 0))
-      return NULL;
-
-   /* check cached bitmap size */
-   if ((width >= failed_bitmap_w) && (height >= failed_bitmap_h))
-      return NULL;
-
-   vram_bitmap = vram_bitmap_list;
-   active_list = NULL;
-   y = 0;
-
-   while (TRUE) {
-      /* Move the blocks from the VRAM_BITMAP_LIST that intersect the
-       * stripe to the ACTIVE_LIST: look through the VRAM_BITMAP_LIST
-       * following the next_y link, grow the ACTIVE_LIST following
-       * the next_x link and sorting by x-position.
-       * (this loop runs in amortized quadratic time)
-       */
-      while (vram_bitmap && (vram_bitmap->y < y+height)) {
-	 /* find sorted x-position */
-	 last_p = &active_list;
-	 for (b = active_list; b && (vram_bitmap->x > b->x); b = b->next_x)
-	    last_p = &b->next_x;
-
-	 /* insert */
-	 *last_p = vram_bitmap;
-	 vram_bitmap->next_x = b;
-
-	 /* next video bitmap */
-	 vram_bitmap = vram_bitmap->next_y;
-      }
-
-      x = 0;
-
-      /* Look for holes to put our bitmap in.
-       * (this loop runs in quadratic time)
-       */
-      for (b = active_list; b; b = b->next_x) {
-	 if (x+width <= b->x)  /* hole is big enough? */
-	    return add_vram_block(x, y, width, height);
-
-         /* Move search x-position to the right edge of the
-          * skipped bitmap if we are not already past it.
-          * And check there is enough room before continuing.
-          */
-	 if (x < b->x + b->w) {
-	    x = (b->x + b->w + 15) & ~15;
-	    if (x+width > VIRTUAL_W)
-	       break;
-	 }
-      }
-
-      /* If the whole ACTIVE_LIST was scanned, there is a big
-       * enough hole to the right of the rightmost bitmap.
-       */
-      if (b == NULL)
-	 return add_vram_block(x, y, width, height);
-
-      /* Move search y-position to the topmost bottom edge
-       * of the bitmaps intersecting the stripe.
-       * (this loop runs in quadratic time)
-       */
-      y = active_list->y + active_list->h;
-      for (b = active_list->next_x; b; b = b->next_x) {
-	 if (y > b->y + b->h)
-	    y = b->y + b->h;
-      }
-
-      if (y+height > VIRTUAL_H) {  /* too close to bottom? */
-	 /* Before failing, cache this bitmap size so that later calls can
-	  * learn from it. Use area as a measure to sort the bitmap sizes.
-          */
-	 if (width * height < failed_bitmap_w * failed_bitmap_h) {
-	    failed_bitmap_w = width;
-	    failed_bitmap_h = height;
-	 }
-
-	 return NULL;
-      }
-
-      /* Remove the blocks that don't intersect the new stripe from ACTIVE_LIST.
-       * (this loop runs in quadratic time)
-       */
-      last_p = &active_list;
-      for (b = active_list; b; b = b->next_x) {
-	 if (y >= b->y + b->h)
-	    *last_p = b->next_x;
-	 else
-	    last_p = &b->next_x;
-      }
-   }
-}
-
-
-
-/* create_system_bitmap:
- *  Attempts to make a system-specific (eg. DirectX surface) bitmap object.
- */
-BITMAP *create_system_bitmap(int width, int height)
-{
-   BITMAP *bmp;
-
-   ASSERT(width >= 0);
-   ASSERT(height > 0);
-   ASSERT(gfx_driver != NULL);
-
-   if (gfx_driver->create_system_bitmap)
-      return gfx_driver->create_system_bitmap(width, height);
-
-   bmp = create_bitmap(width, height);
-   bmp->id |= BMP_ID_SYSTEM;
-
-   return bmp;
-}
-
-
-
-/* destroy_bitmap:
- *  Destroys a memory bitmap.
- */
-void destroy_bitmap(BITMAP *bitmap)
-{
-   VRAM_BITMAP *prev, *pos;
-
-   if (bitmap) {
-      if (is_video_bitmap(bitmap)) {
-	 /* special case for getting rid of video memory bitmaps */
-	 ASSERT(!_dispsw_status);
-
-	 prev = NULL;
-	 pos = vram_bitmap_list;
-
-	 while (pos) {
-	    if (pos->bmp == bitmap) {
-	       if (prev)
-		  prev->next_y = pos->next_y;
-	       else
-		  vram_bitmap_list = pos->next_y;
-
-	       if (pos->x < 0) {
-		  /* the driver is in charge of this object */
-		  gfx_driver->destroy_video_bitmap(bitmap);
-		  free(pos);
-		  return;
-	       } 
-
-	       /* Update cached bitmap size using worst case scenario:
-		* the bitmap lies between two holes whose size is the cached
-		* size on each axis respectively.
-		*/
-	       failed_bitmap_w = failed_bitmap_w * 2 + ((bitmap->w + 15) & ~15);
-	       if (failed_bitmap_w > BMP_MAX_SIZE)
-		  failed_bitmap_w = BMP_MAX_SIZE;
-
-	       failed_bitmap_h = failed_bitmap_h * 2 + bitmap->h;
-	       if (failed_bitmap_h > BMP_MAX_SIZE)
-		  failed_bitmap_h = BMP_MAX_SIZE;
-
-	       free(pos);
-	       break;
-	    }
-
-	    prev = pos;
-	    pos = pos->next_y;
-	 }
-
-	 _unregister_switch_bitmap(bitmap);
-      }
-      else if (is_system_bitmap(bitmap)) {
-	 /* special case for getting rid of system memory bitmaps */
-	 ASSERT(gfx_driver != NULL);
-
-	 if (gfx_driver->destroy_system_bitmap) {
-	    gfx_driver->destroy_system_bitmap(bitmap);
-	    return;
-	 }
-      }
-
-      /* normal memory or sub-bitmap destruction */
-      if (system_driver->destroy_bitmap) {
-	 if (system_driver->destroy_bitmap(bitmap))
-	    return;
-      }
-
-      if (bitmap->dat)
-	 free(bitmap->dat);
-
-      free(bitmap);
-   }
-}
-
-
-
 /* set_clip_rect:
  *  Sets the two opposite corners of the clipping rectangle to be used when
  *  drawing to the bitmap. Nothing will be drawn to positions outside of this 
@@ -1496,176 +623,3 @@
    set_clip_rect(bitmap, x1, y1, x2, y2);
    set_clip_state(bitmap, TRUE);
 }
-
-
-
-/* scroll_screen:
- *  Attempts to scroll the hardware screen, returning 0 on success. 
- *  Check the VIRTUAL_W and VIRTUAL_H values to see how far the screen
- *  can be scrolled. Note that a lot of VESA drivers can only handle
- *  horizontal scrolling in four pixel increments.
- */
-int scroll_screen(int x, int y)
-{
-   int ret = 0;
-   int h;
-
-   /* can driver handle hardware scrolling? */
-   if ((!gfx_driver->scroll) || (_dispsw_status))
-      return -1;
-
-   /* clip x */
-   if (x < 0) {
-      x = 0;
-      ret = -1;
-   }
-   else if (x > (VIRTUAL_W - SCREEN_W)) {
-      x = VIRTUAL_W - SCREEN_W;
-      ret = -1;
-   }
-
-   /* clip y */
-   if (y < 0) {
-      y = 0;
-      ret = -1;
-   }
-   else {
-      h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
-      if (y > (VIRTUAL_H - h)) {
-	 y = VIRTUAL_H - h;
-	 ret = -1;
-      }
-   }
-
-   /* scroll! */
-   if (gfx_driver->scroll(x, y) != 0)
-      ret = -1;
-
-   return ret;
-}
-
-
-
-/* request_scroll:
- *  Attempts to initiate a triple buffered hardware scroll, which will
- *  take place during the next retrace. Returns 0 on success.
- */
-int request_scroll(int x, int y)
-{
-   int ret = 0;
-   int h;
-
-   /* can driver handle triple buffering? */
-   if ((!gfx_driver->request_scroll) || (_dispsw_status)) {
-      scroll_screen(x, y);
-      return -1;
-   }
-
-   /* clip x */
-   if (x < 0) {
-      x = 0;
-      ret = -1;
-   }
-   else if (x > (VIRTUAL_W - SCREEN_W)) {
-      x = VIRTUAL_W - SCREEN_W;
-      ret = -1;
-   }
-
-   /* clip y */
-   if (y < 0) {
-      y = 0;
-      ret = -1;
-   }
-   else {
-      h = (_screen_split_position > 0) ? _screen_split_position : SCREEN_H;
-      if (y > (VIRTUAL_H - h)) {
-	 y = VIRTUAL_H - h;
-	 ret = -1;
-      }
-   }
-
-   /* scroll! */
-   if (gfx_driver->request_scroll(x, y) != 0)
-      ret = -1;
-
-   return ret;
-}
-
-
-
-/* poll_scroll:
- *  Checks whether a requested triple buffer flip has actually taken place.
- */
-int poll_scroll()
-{
-   if ((!gfx_driver->poll_scroll) || (_dispsw_status))
-      return FALSE;
-
-   return gfx_driver->poll_scroll();
-}
-
-
-
-/* show_video_bitmap:
- *  Page flipping function: swaps to display the specified video memory 
- *  bitmap object (this must be the same size as the physical screen).
- */
-int show_video_bitmap(BITMAP *bitmap)
-{
-   if ((!is_video_bitmap(bitmap)) || 
-       (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
-       (_dispsw_status))
-      return -1;
-
-   if (gfx_driver->show_video_bitmap)
-      return gfx_driver->show_video_bitmap(bitmap);
-
-   return scroll_screen(bitmap->x_ofs, bitmap->y_ofs);
-}
-
-
-
-/* request_video_bitmap:
- *  Triple buffering function: triggers a swap to display the specified 
- *  video memory bitmap object, which will take place on the next retrace.
- */
-int request_video_bitmap(BITMAP *bitmap)
-{
-   if ((!is_video_bitmap(bitmap)) || 
-       (bitmap->w != SCREEN_W) || (bitmap->h != SCREEN_H) ||
-       (_dispsw_status))
-      return -1;
-
-   if (gfx_driver->request_video_bitmap)
-      return gfx_driver->request_video_bitmap(bitmap);
-
-   return request_scroll(bitmap->x_ofs, bitmap->y_ofs);
-}
-
-
-
-/* enable_triple_buffer:
- *  Asks a driver to turn on triple buffering mode, if it is capable
- *  of that.
- */
-int enable_triple_buffer()
-{
-   if (gfx_capabilities & GFX_CAN_TRIPLE_BUFFER)
-      return 0;
-
-   if (_dispsw_status)
-      return -1;
-
-   if (gfx_driver->enable_triple_buffer) {
-      gfx_driver->enable_triple_buffer();
-
-      if ((gfx_driver->request_scroll) || (gfx_driver->request_video_bitmap)) {
-	 gfx_capabilities |= GFX_CAN_TRIPLE_BUFFER;
-	 return 0;
-      }
-   }
-
-   return -1;
-}
-
-


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/