diff src/video/macdsp/SDL_dspvideo.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/macdsp/SDL_dspvideo.c	Thu Apr 26 16:45:43 2001 +0000
@@ -0,0 +1,1386 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@devolution.com
+*/
+
+/*
+ Written by Darrell Walisser <dwaliss1@purdue.edu>
+
+ Implementation notes ----------------------------------------------------------------------
+
+ A bit on GWorlds in VRAM from technote 1182:
+
+ There are two important things to note about GWorld's allocated in
+ VRAM. First, the base address retrieved through GetPixBaseAddr or
+ read directly from the PixMap structure can become invalid anytime
+ memory is allocated in VRAM. This can occur either by explicit
+ allocations, such as calls to NewGWorld, or by implicit ones, such as
+ those associated with the internal texture allocation of OpenGL. The
+ stored pixel images themselves will still be valid but may have been
+ moved in VRAM, thus rendering any stored base addresses invalid.
+ You should never store an image's base address for longer than is
+ necessary and especially never across calls to NewGWorld or
+ texture-creation routines. 
+
+ Secondly, an offscreen pixel image allocated in VRAM can be
+ purged at system task time by the display driver. This means any
+ time your application yields time such by calling WaitNextEvent or
+ SystemTask you can lose your VRAM GWorld contents. While this
+ happens infrequently, usually associated with display resolution or
+ pixel depth changes you must code for this eventuality. This purge
+ can occur whether or not the GWorld is locked or not. A return value
+ of false from LockPixels, a NULL return value from GetPixBaseAddr
+ or NULL in the baseAddr field of the PixMap mean that the pixel
+ image has been purged. To reallocate it you can either call
+ UpdateGWorld or Dispose your current GWorld through
+ DisposeGWorld and reallocate it via NewGWorld. Either way you must
+ then rebuild the pixel image. 
+
+------------------------------------------------------------------------------------
+
+  Currently, I don't account for (1). In my testing, NewGWorld never invalidated
+  other existing GWorlds in VRAM. However, I do have protection for (2).
+  Namely, I am using GetOSEvent() instead of WaitNextEvent() so that there are no
+  context switches (the app hogs the CPU). Eventually a book-keeping system should
+  be coded to take care of (1) and (2).
+  
+------------------------------------------------------------------------------------
+
+  System requirements (* denotes optional):
+  
+  1. DrawSprocket 1.7.3
+  2. *MacOS 9 or later for hardware accelerated blit / fill
+  3. *May also require certain graphics hardware for (2). I trust that all Apple OEM
+     hardware will work. Third party accelerators may work if they have QuickDraw
+     acceleration in the drivers and the drivers have been updated for OS 9. The current
+     Voodoo 3 drivers (1.0b12) do not work.
+  
+  Coding suggestions:
+  
+  1. Use SDL_UpdateRects !
+  
+    If no QuickDraw acceleration is present, double-buffered surfaces will use a back buffer
+    in System memory. I recommend you use SDL_UpdateRects with double-buffered surfaces
+    for best performance on these cards, since the overhead is nearly zero for VRAM back buffer.
+    
+  2. Load most-resident surfaces first.
+  
+    If you fill up VRAM or AGP memory, there is no contingency for purging to make room for the next one.
+    Therefore, you should load the surfaces you plan to use the most frequently first.
+    Sooner or later, I will code LRU replacement to help this.
+  
+  TODO:
+  Some kind of posterized mode for resolutions < 640x480.
+  Window support / fullscreen toggle.
+  Figure out how much VRAM is available. Put in video->info->video_mem.
+  Track VRAM usage.
+  
+  BUGS:
+  I can't create a hardware surface the same size as the screen?! How to fix?
+  
+  
+
+   COMPILE OPTIONS:
+   
+   DSP_TRY_CC_AND_AA - Define if you want to try HWA color-key and alpha blitters
+                       HW color-key blitting gives substantial improvements,
+                       but hw alpha is neck-and-neck with SDL's soft bitter.
+
+   DSP_NO_SYNC_VBL   - Define for HWA double-buffered surfaces: don't sync
+                       pseudo-flip to monitor redraw.
+
+   DSP_NO_SYNC_OPENGL - Define for OpenGL surfaces: don't sync buffer swap. Synching buffer
+                        swap may result in reduced performance, but can eliminate some
+                        tearing artifacts.
+   CHANGELOG:
+   09/17/00 Lots of little tweaks. Build modelist in reverse order so largest contexts
+            list first. Compared various methods with ROM methods and fixed rez switch
+            crashing bug in GL Tron. (Woohoo!)
+*/
+
+#define DSP_TRY_CC_AND_AA
+
+/* #define DSP_NO_SYNC_VBL */
+
+#define DSP_NO_SYNC_OPENGL
+
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if TARGET_API_MAC_CARBON
+#include <Carbon.h>
+#else
+#include <LowMem.h>
+#include <Gestalt.h>
+#include <Devices.h>
+#include <DiskInit.h>
+#include <QDOffscreen.h>
+#endif
+
+#include "SDL_video.h"
+#include "SDL_blit.h"
+#include "SDL_error.h"
+#include "SDL_syswm.h"
+#include "SDL_sysvideo.h"
+#include "SDL_dspvideo.h"
+#include "SDL_macgl_c.h"
+#include "SDL_macwm_c.h"
+#include "SDL_macmouse_c.h"
+#include "SDL_macevents_c.h"
+
+/* Initialization/Query functions */
+static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat);
+static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
+static SDL_Surface *DSp_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
+static int DSp_SetColors(_THIS, int firstcolor, int ncolors,
+			 SDL_Color *colors);
+static int DSp_CreatePalette(_THIS);
+static int DSp_DestroyPalette(_THIS);
+static void DSp_VideoQuit(_THIS);
+
+static int DSp_GetMainDevice (_THIS, GDHandle *device);
+static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat);
+static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
+static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
+
+/* Hardware surface functions */
+static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha);
+static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key);
+static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height);
+static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface);
+static int DSp_LockHWSurface(_THIS, SDL_Surface *surface);
+static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface);
+static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface);
+static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface);
+static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest);
+static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
+                           SDL_Surface *dst, SDL_Rect *dstrect);
+static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
+
+#ifdef HAVE_OPENGL
+   static void DSp_GL_SwapBuffers (_THIS);
+#endif
+
+#if ! TARGET_API_MAC_CARBON
+
+    #define GetPortPixRowBytes(x)  ( (*(x->portPixMap))->rowBytes )
+   #define GetGDevPixMap(x) ((**(x)).gdPMap)   
+   #define GetPortPixMap(x) ((*(x)).portPixMap)
+   
+   #define GetPixDepth(y)    ((**(y)).pixelSize)
+   //#define GetPixRowBytes(y) ((**(y)).rowBytes)
+   //#define GetPixBaseAddr(y) ((**(y)).baseAddr)
+   #define GetPixCTab(y)     ((**(y)).pmTable)
+    #define GetPortBitMapForCopyBits(x) (&(((GrafPtr)(x))->portBits))
+   
+#else
+    #define GetPortPixRowBytes(x) (GetPixRowBytes(GetPortPixMap(x)) )
+    #define GetGDevPixMap(x) ((**(x)).gdPMap)
+
+#endif
+
+typedef struct private_hwdata {
+
+  GWorldPtr offscreen;    // offscreen gworld in VRAM or AGP
+  
+  #ifdef DSP_TRY_CC_AND_AA
+    GWorldPtr mask;         // transparent mask
+    RGBColor  alpha;        // alpha color
+    RGBColor  trans;        // transparent color
+  #endif
+  
+} private_hwdata;
+
+typedef private_hwdata private_swdata ; /* have same fields */
+
+/* Macintosh toolbox driver bootstrap functions */
+
+static int DSp_Available(void)
+{
+	/* Check for DrawSprocket */
+	/* This check is only meaningful if you weak-link DrawSprocketLib */  
+	return ((Ptr)DSpStartup != (Ptr)kUnresolvedCFragSymbolAddress);
+}
+
+static void DSp_DeleteDevice(SDL_VideoDevice *device)
+{
+	/* -dw- taking no chances with null pointers */
+	if (device) {
+		
+   	if (device->hidden) {
+   	   
+   	   if (device->hidden->dspinfo)
+	         free(device->hidden->dspinfo);
+   	   
+   	   free(device->hidden);
+   	}
+	   free(device);	
+	}
+}
+
+static SDL_VideoDevice *DSp_CreateDevice(int devindex)
+{
+	SDL_VideoDevice *device;
+
+	/* Initialize all variables that we clean on shutdown */
+	device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
+	if ( device ) {
+		memset(device, 0, sizeof (*device));
+		device->hidden = (struct SDL_PrivateVideoData *)
+				malloc((sizeof *device->hidden));
+	    if (device->hidden)
+	        memset(device->hidden, 0, sizeof ( *(device->hidden) ) );
+	}
+	if ( (device == NULL) || (device->hidden == NULL) ) {
+		SDL_OutOfMemory();
+			
+		if ( device ) {
+			
+			if (device->hidden)
+		        free (device->hidden);			
+			
+			free(device);
+		}
+		
+		return(NULL);
+	}
+	
+	/* Allocate DrawSprocket information */
+	device->hidden->dspinfo = (struct DSpInfo *)malloc(
+					(sizeof *device->hidden->dspinfo));
+	if ( device->hidden->dspinfo == NULL ) {
+		SDL_OutOfMemory();
+		free(device->hidden);
+		free(device);
+		return(0);
+	}
+	memset(device->hidden->dspinfo, 0, (sizeof *device->hidden->dspinfo));
+
+	/* Set the function pointers */
+	device->VideoInit       = DSp_VideoInit;
+	device->ListModes       = DSp_ListModes;
+	device->SetVideoMode    = DSp_SetVideoMode;
+	device->SetColors       = DSp_SetColors;
+	device->UpdateRects     = NULL;
+	device->VideoQuit       = DSp_VideoQuit;
+	device->AllocHWSurface  = DSp_AllocHWSurface;
+	device->CheckHWBlit     = NULL;
+	device->FillHWRect      = NULL;
+	device->SetHWColorKey   = NULL;
+	device->SetHWAlpha      = NULL;
+	device->LockHWSurface   = DSp_LockHWSurface;
+	device->UnlockHWSurface = DSp_UnlockHWSurface;
+	device->FlipHWSurface   = DSp_FlipHWSurface;
+	device->FreeHWSurface   = DSp_FreeHWSurface;
+#ifdef HAVE_OPENGL
+	device->GL_MakeCurrent  = Mac_GL_MakeCurrent;
+	device->GL_SwapBuffers  = DSp_GL_SwapBuffers;
+#endif
+	device->SetCaption = NULL;
+	device->SetIcon = NULL;
+	device->IconifyWindow = NULL;
+	device->GrabInput = NULL;
+	device->GetWMInfo = NULL;
+	device->FreeWMCursor    = Mac_FreeWMCursor;
+	device->CreateWMCursor  = Mac_CreateWMCursor;
+	device->ShowWMCursor    = Mac_ShowWMCursor;
+	device->WarpWMCursor    = Mac_WarpWMCursor;
+	device->InitOSKeymap    = Mac_InitOSKeymap;
+	device->PumpEvents      = Mac_PumpEvents;
+	
+	device->GrabInput      = NULL;
+	device->CheckMouseMode = NULL;
+	
+	device->free = DSp_DeleteDevice;
+
+	return device;
+}
+
+VideoBootStrap DSp_bootstrap = {
+	"DSp", "MacOS DrawSprocket",
+	DSp_Available, DSp_CreateDevice
+};
+
+/* Use DSp/Display Manager to build mode list for given screen */
+static SDL_Rect**  DSp_BuildModeList (const GDHandle gDevice)
+{
+	DSpContextAttributes  attributes;
+	DSpContextReference   context;
+	DisplayIDType         displayID;
+	SDL_Rect temp_list [16];
+	SDL_Rect **mode_list;
+	int width, height, i, j;
+        
+        #if TARGET_API_MAC_OSX		
+	
+        displayID = 0;
+        
+        #else
+        /* Ask Display Manager for integer id of screen device */
+	if ( DMGetDisplayIDByGDevice (gDevice, &displayID, SDL_TRUE) != noErr ) {
+		return NULL;
+	}
+	#endif
+	/* Get the first possible DSp context on this device */
+	if ( DSpGetFirstContext (displayID, &context) != noErr ) {
+		return NULL;
+	}
+	
+	if ( DSpContext_GetAttributes (context, &attributes) != noErr )
+		return NULL;
+			
+	for ( i = 0; i < SDL_TABLESIZE(temp_list); i++ ) {
+		width  = attributes.displayWidth;
+		height = attributes.displayHeight;
+		
+		temp_list [i].x = 0 | attributes.displayBestDepth;
+		temp_list [i].y = 0;
+		temp_list [i].w = width;
+		temp_list [i].h = height;
+	
+		/* DSp will report many different contexts with the same width and height. */
+		/* They will differ in bit depth and refresh rate. */
+		/* We will ignore them until we reach one with a different width/height */
+		/* When there are no more contexts to look at, we will quit building the list*/
+		while ( width == attributes.displayWidth && height == attributes.displayHeight ) {
+		
+			OSStatus err = DSpGetNextContext (context, &context);
+			if (err != noErr)
+				if (err == kDSpContextNotFoundErr)
+					goto done;
+				else
+					return NULL;		
+			
+			if ( DSpContext_GetAttributes (context, &attributes) != noErr )
+				return NULL;
+				
+			temp_list [i].x |= attributes.displayBestDepth;
+		}
+	}
+done:
+	i++;          /* i was not incremented before kicking out of the loop */
+	
+	mode_list = (SDL_Rect**) malloc (sizeof (SDL_Rect*) * (i+1));
+	if (mode_list) {
+	
+	   /* -dw- new stuff: build in reverse order so largest sizes list first */
+		for (j = i-1; j >= 0; j--) {
+			mode_list [j] = (SDL_Rect*) malloc (sizeof (SDL_Rect));	
+			if (mode_list [j])
+				memcpy (mode_list [j], &(temp_list [j]), sizeof (SDL_Rect));
+			else {
+				SDL_OutOfMemory ();
+				return NULL;
+			}
+		}
+		mode_list [i] = NULL;		/* append null to the end */
+	}
+	else {
+		SDL_OutOfMemory ();
+		return NULL;
+	}
+		
+	return mode_list;
+}
+
+static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat)
+{
+  /* 
+     VRAM GWorlds are only available on OS 9 or later.
+     Even with OS 9, some display drivers won't support it, 
+     so we create a test GWorld and check for errors. 
+  */
+
+  long versionSystem;
+
+  dsp_vram_available = SDL_FALSE;
+  dsp_agp_available  = SDL_FALSE;
+  
+  Gestalt ('sysv', &versionSystem);
+  if (0x00000860 < (versionSystem & 0x0000FFFF)) {
+    
+    GWorldPtr offscreen;
+    OSStatus  err;
+    Rect      bounds;
+    
+    SetRect (&bounds, 0, 0, 320, 240);
+    
+    err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useDistantHdwrMem | noNewDevice);
+    if (err == noErr) {
+      dsp_vram_available = SDL_TRUE;
+      DisposeGWorld (offscreen);
+    }
+	
+    err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useLocalHdwrMem | noNewDevice);
+    if (err == noErr) {
+      DisposeGWorld (offscreen);
+      dsp_agp_available = SDL_TRUE;
+    }
+  }
+}
+
+static int DSp_GetMainDevice (_THIS, GDHandle *device)
+{
+    
+#if TARGET_API_MAC_OSX
+        /* DSpUserSelectContext not available on OS X */
+        *device = GetMainDevice();
+        return 0;
+#else
+        
+	DSpContextAttributes attrib;
+	DSpContextReference  context;
+	DisplayIDType        display_id;
+	GDHandle             main_device;
+	GDHandle             device_list;
+	
+	device_list = GetDeviceList ();
+	main_device = GetMainDevice ();
+	
+	/* Quick check to avoid slower method when only one display exists */
+	if ( (**device_list).gdNextGD == NULL ) {
+	  *device = main_device;
+	  return 0;
+	}
+		
+	memset (&attrib, 0, sizeof (DSpContextAttributes));
+
+	/* These attributes are hopefully supported on all devices...*/
+	attrib.displayWidth         = 640;
+	attrib.displayHeight        = 480;
+	attrib.displayBestDepth     = 8;
+	attrib.backBufferBestDepth  = 8;
+	attrib.displayDepthMask     = kDSpDepthMask_All;
+	attrib.backBufferDepthMask  = kDSpDepthMask_All;
+	attrib.colorNeeds           = kDSpColorNeeds_Require;
+	attrib.pageCount            = 1;
+			 
+	if (noErr != DMGetDisplayIDByGDevice (main_device, &display_id, SDL_FALSE)) {
+		SDL_SetError ("Display Manager couldn't associate GDevice with a Display ID");
+		return (-1);
+	}
+	
+	/* Put up dialog on main display to select which display to use */
+	if (noErr != DSpUserSelectContext (&attrib, display_id, NULL, &context)) {
+		SDL_SetError ("DrawSprocket couldn't create a context");
+		return (-1);
+	}
+         
+	if (noErr != DSpContext_GetDisplayID (context, &display_id)) {
+		SDL_SetError ("DrawSprocket couldn't get display ID");
+		return (-1);
+	}
+  
+	if (noErr != DMGetGDeviceByDisplayID  (display_id, &main_device, SDL_FALSE)) {
+		SDL_SetError ("Display Manager couldn't associate Display ID with GDevice");
+		return (-1);  
+	}
+
+	*device = main_device;
+	return (0);
+#endif
+}
+
+static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat)
+{
+	
+	NumVersion dsp_version = DSpGetVersion ();
+	
+	if (  (dsp_version.majorRev == 1 && dsp_version.minorAndBugRev < 0x73) ||
+	      (dsp_version.majorRev < 1)  ) {                          
+	    
+	   /* StandardAlert (kAlertStopAlert, "\pError!", 
+	                "\pI need DrawSprocket 1.7.3 or later!\n"
+	                  "You can find a newer version at http://www.apple.com/swupdates.",
+	                   NULL, NULL);
+	    */              
+	    SDL_SetError ("DrawSprocket version is too old. Need 1.7.3 or later.");
+	    return (-1);
+	}
+	
+	if ( DSpStartup () != noErr ) {
+		SDL_SetError ("DrawSprocket couldn't startup");
+		return(-1);
+	}
+	
+	/* Start DSpintosh events */
+	Mac_InitEvents(this);
+
+	/* Get a handle to the main monitor, or choose one on multiple monitor setups */
+	if ( DSp_GetMainDevice(this, &SDL_Display) <  0)
+		return (-1);
+
+	/* Determine pixel format */
+    vformat->BitsPerPixel = GetPixDepth ( (**SDL_Display).gdPMap );
+	dsp_old_depth = vformat->BitsPerPixel;
+		
+	switch (vformat->BitsPerPixel) {
+		case 16:	
+			vformat->Rmask = 0x00007c00;
+			vformat->Gmask = 0x000003e0;
+			vformat->Bmask = 0x0000001f;
+			break;
+		default:
+			break;
+	}
+   
+   if ( DSp_CreatePalette (this) < 0 ) {
+   
+      SDL_SetError ("Could not create palette");
+      return (-1);
+   }
+   
+	/* Get a list of available fullscreen modes */
+	SDL_modelist = DSp_BuildModeList (SDL_Display);
+	if (SDL_modelist == NULL) {
+		SDL_SetError ("DrawSprocket could not build a mode list");
+		return (-1);
+	}
+	
+	/* Check for VRAM and AGP GWorlds for HW Blitting */
+	DSp_IsHWAvailable (this, vformat);
+	
+	this->info.wm_available = 0;
+
+	if (dsp_vram_available || dsp_agp_available) {
+    
+	  this->info.hw_available = SDL_TRUE;
+	  
+	  this->CheckHWBlit  = DSp_CheckHWBlit;
+	  this->info.blit_hw = SDL_TRUE; 
+  
+	  this->FillHWRect     = DSp_FillHWRect;
+	  this->info.blit_fill = SDL_TRUE;
+	  
+	#ifdef DSP_TRY_CC_AND_AA  
+	  this->SetHWColorKey   = DSp_SetHWColorKey;
+	  this->info.blit_hw_CC = SDL_TRUE;
+	  
+	  this->SetHWAlpha      = DSp_SetHWAlpha;
+	  this->info.blit_hw_A  = SDL_TRUE;
+	#endif
+	
+	}  
+    
+	return(0);
+}
+
+static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
+{
+	static SDL_Rect *dsp_modes[16];
+	int i = 0, j = 0;
+	
+	if ( format->BitsPerPixel == 0 )
+	   return ( (SDL_Rect**) NULL );
+	
+	while (SDL_modelist[i] != NULL) {
+	
+	   if (SDL_modelist[i]->x & format->BitsPerPixel) {
+	      dsp_modes[j] = SDL_modelist[i];
+	      j++;
+	   }
+	   i++;
+	}
+	
+	dsp_modes[j] = NULL;
+
+	return dsp_modes;
+}
+
+/* Various screen update functions available */
+static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
+
+static volatile unsigned int retrace_count = 0; /* -dw- need volatile because it updates asychronously */
+
+#if ! TARGET_API_MAC_OSX
+Boolean DSp_VBLProc ( DSpContextReference context, void *ref_con )
+{
+	retrace_count++;
+	
+	return 1; /* Darrell, is this right? */
+}
+#endif
+
+static void DSp_SetHWError (OSStatus err, int is_agp)
+{
+	char message[1024];
+	const char *fmt, *mem;
+
+	if ( is_agp ) {
+		mem = "AGP Memory";
+	} else {
+		mem = "VRAM";
+	}
+	switch(err) {
+	    case memFullErr:
+		fmt = "Hardware surface possible but not enough %s available";
+		break;
+	    case cDepthErr:
+		fmt = "Hardware surface possible but invalid color depth";
+		break;
+	    default:
+		fmt = "Hardware surface could not be allocated in %s - unknown error";
+		break;
+	}
+	sprintf(message, fmt, mem);
+	SDL_SetError(message);
+}
+
+/* put up a dialog to verify display change */
+static int DSp_ConfirmSwitch () {
+
+  /* resource id's for dialog */
+  const int rDialog = 1002;
+  const int bCancel = 1;
+  const int bOK     = 2;
+  
+  DialogPtr dialog;
+  OSStatus  err;
+  SInt32    response;
+  DialogItemIndex       item = 0;
+  GrafPtr   savePort;
+    
+  GetPort (&savePort);
+  
+  dialog = GetNewDialog (rDialog, NULL, (WindowPtr) -1);
+  if (dialog == NULL)
+	 return (0);
+  
+  SetPort (dialog);
+  
+  SetDialogDefaultItem (dialog, bCancel);
+  SetDialogCancelItem  (dialog, bCancel);
+  
+  SetEventMask (everyEvent);  
+  FlushEvents (everyEvent, 0);
+   
+   /* On MacOS 8.5 or later, we can make the dialog go away after 15 seconds */
+   /* This is good since it's possible user can't even see the dialog! */
+   /* Requires linking to DialogsLib */
+   err = Gestalt(gestaltSystemVersion,&response);
+   if (err == noErr && response >= 0x00000850) {
+   	SetDialogTimeout(dialog, bCancel, 15);
+   }
+
+   do {      
+    
+    ModalDialog ( NULL, &item );  
+
+   } while ( item != bCancel && item != bOK && err != noErr);
+
+  DisposeWindow (dialog);
+  SetPort (savePort);
+  
+  SetEventMask(everyEvent - autoKeyMask);
+  FlushEvents(everyEvent, 0);
+   
+  return (item - 1);
+}
+
+static void DSp_UnsetVideoMode(_THIS, SDL_Surface *current)
+{
+			
+		
+	 if ( current->flags & SDL_OPENGL )  { 
+	   Mac_GL_Quit (this);	   	
+	}
+		
+	if (dsp_context != NULL) {
+		
+		GWorldPtr front;
+		DSpContext_GetFrontBuffer (dsp_context, &front);
+		
+		if (front != dsp_back_buffer)
+		   DisposeGWorld (dsp_back_buffer);
+		
+		if (current->hwdata)
+		   free (current->hwdata);
+		   
+		DSpContext_SetState (dsp_context, kDSpContextState_Inactive );
+		DSpContext_Release  (dsp_context);
+		
+		dsp_context = NULL;
+	}
+    	
+    if (SDL_Window != NULL) {
+        DisposeWindow (SDL_Window);
+        SDL_Window = NULL;
+    }    
+    
+    current->pixels = NULL;
+    current->flags  = 0;
+}
+
+static SDL_Surface *DSp_SetVideoMode(_THIS,
+	SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
+{
+	
+	DisplayIDType        display_id;
+	DSpContextAttributes attrib;
+	Fixed freq;
+	OSStatus err;
+	UInt32 rmask = 0, gmask = 0, bmask = 0;
+		
+	int   page_count;
+	int   double_buf;
+	int   hw_surface;
+	int   use_dsp_back_buffer;
+     
+	DSp_UnsetVideoMode (this, current);
+       
+    if (bpp != dsp_old_depth)
+        DSp_DestroyPalette (this);
+   
+	double_buf = (flags & SDL_DOUBLEBUF) != 0;
+	hw_surface = (flags & SDL_HWSURFACE) != 0;
+	use_dsp_back_buffer = !dsp_vram_available || !hw_surface ;
+	
+	current->flags |= SDL_FULLSCREEN;
+
+rebuild:  
+  
+	if ( double_buf && use_dsp_back_buffer ) {
+		page_count = 2;
+	} else {
+		page_count = 1;
+	}
+
+	memset (&attrib, 0, sizeof (DSpContextAttributes));
+	attrib.displayWidth         = width;
+	attrib.displayHeight        = height;
+	attrib.displayBestDepth     = bpp;
+	attrib.backBufferBestDepth  = bpp;
+	attrib.displayDepthMask     = kDSpDepthMask_All;
+	attrib.backBufferDepthMask  = kDSpDepthMask_All;
+	attrib.colorNeeds           = kDSpColorNeeds_Require;
+	attrib.colorTable           = 0;
+	attrib.pageCount            = page_count;
+        #if TARGET_API_MAC_OSX
+        
+        if ( DSpFindBestContext (&attrib, &dsp_context) != noErr ) {
+            SDL_SetError ("DrawSprocket couldn't find a context");
+            return NULL;
+        }
+        
+        #else
+	if ( noErr != DMGetDisplayIDByGDevice (SDL_Display, &display_id, SDL_FALSE) ) {
+		SDL_SetError ("Display Manager couldn't associate GDevice with display_id");
+		return NULL;
+	}	
+	if ( DSpFindBestContextOnDisplayID (&attrib, &dsp_context, display_id) != noErr ) {
+		SDL_SetError ("DrawSprocket couldn't find a suitable context on given display");
+		return NULL;
+	}
+	
+        #endif		
+	if ( DSpContext_Reserve (dsp_context, &attrib) != noErr ) {
+		SDL_SetError ("DrawSprocket couldn't get the needed resources to build the display");
+		return NULL;
+	}
+	
+	if ( (err = DSpContext_SetState (dsp_context, kDSpContextState_Active)) != noErr ) {
+		
+		if (err == kDSpConfirmSwitchWarning) {     
+		  
+		   if ( ! DSp_ConfirmSwitch () ) {
+		   
+		      DSpContext_Release (dsp_context);
+		      dsp_context = NULL;
+		      SDL_SetError ("User cancelled display switch");
+		      return NULL;
+		   }
+		   else
+		     /* Have to reactivate context. Why? */
+		     DSpContext_SetState (dsp_context, kDSpContextState_Active);
+		      
+	   }
+	   else {
+	      SDL_SetError ("DrawSprocket couldn't activate the context");
+		  return NULL;
+	   }
+	}
+   
+   
+	if (bpp != dsp_old_depth) {
+   	
+   	    DSp_CreatePalette  (this);
+   
+       	/* update format if display depth changed */
+       	if (bpp == 16) {
+       	
+       	   rmask = 0x00007c00;
+       	   gmask = 0x000003e0;
+       	   bmask = 0x0000001f;
+       	}
+       	if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, 0 ) ) {
+       		
+       	   SDL_SetError ("Could not reallocate video format.");
+       	   return(NULL);
+       	}
+	}
+	
+	if (!double_buf) {
+		
+		/* single-buffer context */
+		DSpContext_GetFrontBuffer (dsp_context, &dsp_back_buffer);
+			
+		current->hwdata   = (private_hwdata*) malloc (sizeof (private_hwdata));
+		if (current ->hwdata == NULL) {
+			SDL_OutOfMemory ();
+	  		return NULL;		  
+		}
+		current->hwdata->offscreen = dsp_back_buffer;
+	    current->flags   |= SDL_HWSURFACE;
+	    this->UpdateRects = DSp_DirectUpdate;
+	} 
+	else if ( use_dsp_back_buffer ) {
+	
+		DSpContext_GetBackBuffer  (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
+		
+		current->flags   |= SDL_DOUBLEBUF | SDL_SWSURFACE; /* only front buffer is in VRAM */                                     
+	    this->UpdateRects = DSp_DSpUpdate;	
+	} 
+	else if ( DSp_NewHWSurface(this, &dsp_back_buffer, bpp, width-1, height-1) == 0 ) {
+      
+      current->hwdata = (private_hwdata*) malloc (sizeof (private_hwdata));
+      if (current ->hwdata == NULL) {
+      	SDL_OutOfMemory ();
+      	return NULL;		  
+      }
+      
+      memset (current->hwdata, 0, sizeof (private_hwdata));
+      current->hwdata->offscreen = dsp_back_buffer;
+      current->flags |= SDL_DOUBLEBUF | SDL_HWSURFACE; 
+      this->UpdateRects = DSp_DirectUpdate; /* hardware doesn't do update rects, must be page-flipped */	   
+   }  	
+   else {
+
+	   DSpContext_Release (dsp_context);	
+	   use_dsp_back_buffer = SDL_TRUE;
+	   goto  rebuild;
+    }
+	   	
+    current->pitch  = GetPortPixRowBytes(dsp_back_buffer) & 0x3FFF;
+	current->pixels = GetPixBaseAddr(GetPortPixMap(dsp_back_buffer));
+	
+	current->w = width;
+	current->h = height;
+	
+    #if ! TARGET_API_MAC_OSX
+        
+	if (use_dsp_back_buffer) {
+	   
+	   DSpContext_GetMonitorFrequency (dsp_context, &freq);
+	   DSpContext_SetMaxFrameRate     (dsp_context, freq >> 16);
+	}
+	
+    
+	if ( (current->flags & SDL_HWSURFACE) || (current->flags & SDL_OPENGL) )
+		DSpContext_SetVBLProc (dsp_context, DSp_VBLProc, NULL);
+    #endif
+	
+	if (bpp == 8)	
+	   current->flags |= SDL_HWPALETTE;
+	
+	if (flags & SDL_OPENGL) {
+		   
+	   Rect rect;
+	   RGBColor rgb = { 0.0, 0.0, 0.0 };
+	   GrafPtr save_port;
+	   
+	   SetRect (&rect, 0, 0, width, height);
+	   SDL_Window = NewCWindow(nil, &( (**SDL_Display).gdRect), "\p", SDL_TRUE, plainDBox, (WindowPtr)-1, SDL_FALSE, 0);
+		   
+	   if (SDL_Window == NULL) {
+		 
+		   SDL_SetError ("DSp_SetVideoMode : OpenGL window could not be created.");
+		   return NULL;  			   	
+	   }
+	   
+	   /* Set window color to black to avoid white flash*/
+	   GetPort (&save_port);
+	   SetPort (SDL_Window);
+	      RGBForeColor (&rgb);
+	      PaintRect    (&rect);	
+	   SetPort (save_port);
+	   
+	   SetPortWindowPort (SDL_Window);
+	   SelectWindow  (SDL_Window);
+	     
+	   if ( Mac_GL_Init (this) < 0 ) {
+	   
+	      SDL_SetError ("DSp_SetVideoMode : could not create OpenGL context.");
+	      return NULL;
+	   }
+	   	   	   	   
+	   current->flags |= SDL_OPENGL;	
+	}
+	
+	return current; 
+}
+
+#ifdef DSP_TRY_CC_AND_AA
+
+static int DSp_MakeHWMask (_THIS, SDL_Surface *surface)
+{
+    GDHandle save_device;
+    CGrafPtr save_port;
+    GWorldPtr temp;
+    RGBColor black = { 0, 0, 0 };
+    RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
+    Rect     rect;
+    
+    Uint32 depth = GetPixDepth ( GetGDevPixMap (SDL_Display) );
+    
+    SetRect (&rect, 0, 0, surface->w, surface->h);
+    
+    if ( noErr != NewGWorld (&(surface->hwdata->mask), depth, &rect, 0, SDL_Display, 0 ) < 0 ) {
+    
+        SDL_OutOfMemory ();
+        return (-1);
+    }   
+    
+    if ( noErr != NewGWorld (&temp, depth, &rect, 0 , SDL_Display, 0 ) ) {
+    
+        SDL_OutOfMemory ();
+        return (-1);
+    }                         
+
+            
+    GetGWorld (&save_port, &save_device);
+    SetGWorld (surface->hwdata->mask, SDL_Display);
+    
+    RGBForeColor (&white);
+    PaintRect    (&rect);
+                 
+    RGBBackColor (&(surface->hwdata->trans));
+    
+    CopyBits ( GetPortBitMapForCopyBits(surface->hwdata->offscreen),
+                 GetPortBitMapForCopyBits(surface->hwdata->mask),
+    	       &rect, &rect, transparent, NULL );
+        
+    SetGWorld (surface->hwdata->mask, SDL_Display);    
+    SetGWorld (save_port, save_device);     
+    return (0);
+}
+
+static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha)
+{
+    surface->hwdata->alpha.red   = (alpha / 255.0) * 65535;
+    surface->hwdata->alpha.blue  = (alpha / 255.0) * 65535;
+    surface->hwdata->alpha.green = (alpha / 255.0) * 65535;
+
+    surface->flags |= SDL_SRCALPHA;
+
+    if (surface->flags & SDL_SRCCOLORKEY) {
+        return(DSp_MakeHWMask (this, surface));
+    }
+    return(0);
+}
+
+static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
+{
+    CGrafPtr save_port;
+    GDHandle save_device;
+    
+    GetGWorld (&save_port, &save_device);
+    SetGWorld (surface->hwdata->offscreen, NULL);
+    
+    Index2Color (key, &(surface->hwdata->trans));
+    surface->flags |= SDL_SRCCOLORKEY;    
+    
+    SetGWorld (save_port, save_device);
+    
+    if ( surface->flags & SDL_SRCALPHA ) {
+        return(DSp_MakeHWMask (this, surface));    
+    } 
+    return(0);
+}
+
+#endif /* DSP_TRY_CC_AND_AA */
+
+static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height) {
+   
+   OSStatus err;
+   Rect     bounds;
+		
+	SetRect (&bounds, 0, 0, width, height);
+   
+    if (dsp_vram_available) {
+	   /* try VRAM */
+   	  err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useDistantHdwrMem | noNewDevice );
+      if (err != noErr)
+         DSp_SetHWError (err, SDL_FALSE);        
+      else
+         return (0);      
+    }
+    
+    if (dsp_agp_available) {
+      /* try AGP */
+      err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useLocalHdwrMem | noNewDevice );
+                                            
+      if (err != noErr)
+         DSp_SetHWError (err, SDL_TRUE);
+      else   
+         return (0);     
+     }  
+                  
+   return (-1);  
+}
+
+static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface)
+{
+	GWorldPtr temp;
+	 	 
+	if ( DSp_NewHWSurface (this, &temp, surface->format->BitsPerPixel, surface->w, surface->h) < 0 )
+	   return (-1);
+			
+	surface->hwdata = (private_hwdata*) malloc (sizeof (private_hwdata));
+	if (surface->hwdata == NULL) {
+		SDL_OutOfMemory ();
+		return -1;
+	}
+	
+	memset (surface->hwdata, 0, sizeof(private_hwdata));
+	surface->hwdata->offscreen = temp;
+	surface->pitch	 = GetPixRowBytes (GetPortPixMap (temp)) & 0x3FFF;
+	surface->pixels  = GetPixBaseAddr (GetPortPixMap (temp));
+	surface->flags	|= SDL_HWSURFACE;
+#ifdef DSP_TRY_CC_AND_AA	
+	surface->flags  |= SDL_HWACCEL;
+#endif	
+	return 0;
+}
+
+static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface)
+{	
+	if (surface->hwdata->offscreen != NULL)
+		DisposeGWorld (surface->hwdata->offscreen);
+	free (surface->hwdata);
+
+    surface->pixels = NULL;
+}
+
+static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest)
+{
+	int accelerated;
+
+	/* Set initial acceleration on */
+	src->flags |= SDL_HWACCEL;
+
+	/* Set the surface attributes */
+	if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
+		if ( ! this->info.blit_hw_A ) {
+			src->flags &= ~SDL_HWACCEL;
+		}
+	}
+	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
+		if ( ! this->info.blit_hw_CC ) {
+			src->flags &= ~SDL_HWACCEL;
+		}
+	}
+
+	/* Check to see if final surface blit is accelerated */
+	accelerated = !!(src->flags & SDL_HWACCEL);
+	if ( accelerated ) {
+		src->map->hw_blit = DSp_HWAccelBlit;
+	}
+	return(accelerated);
+}
+
+static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
+                           SDL_Surface *dst, SDL_Rect *dstrect)
+{
+	CGrafPtr save_port;
+	GDHandle save_device;
+	Rect src_rect, dst_rect;
+    RGBColor black = { 0, 0, 0 };
+    RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
+
+#ifdef DSP_TRY_CC_AND_AA		
+	UInt32 mode;	
+#endif
+	
+	SetRect (&src_rect, srcrect->x, srcrect->y, srcrect->x + srcrect->w, srcrect->y + srcrect->h);
+	SetRect (&dst_rect, dstrect->x, dstrect->y, dstrect->x + dstrect->w, dstrect->y + dstrect->h);
+	
+	GetGWorld (&save_port, &save_device);
+	SetGWorld (dst->hwdata->offscreen, NULL);		
+		
+	RGBForeColor (&black);
+	RGBBackColor (&white);
+		
+#ifdef DSP_TRY_CC_AND_AA
+	
+	if ( (src->flags & SDL_SRCCOLORKEY) &&
+	     (src->flags & SDL_SRCALPHA)  ) {
+	     
+	     OpColor (&(src->hwdata->alpha));	           
+    
+         CopyDeepMask ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
+                        GetPortBitMapForCopyBits(src->hwdata->mask),
+                        GetPortBitMapForCopyBits(dst->hwdata->offscreen),
+	                    &src_rect, &src_rect, &dst_rect,
+	                    blend,
+	                    NULL );                	                    
+	}
+	else {
+    	
+    	if ( src->flags & SDL_SRCCOLORKEY) {		    	    	    
+    	    RGBBackColor (&(src->hwdata->trans) );	    
+    	    mode = transparent;
+    	}
+    	else if (src->flags & SDL_SRCALPHA) {
+    	
+    	    OpColor (&(src->hwdata->alpha));
+    	    mode = blend;
+    	}    	
+    	else {
+    	
+    	    mode = srcCopy;   	    
+    	}            
+    	
+        CopyBits ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
+                   GetPortBitMapForCopyBits(dst->hwdata->offscreen),
+    	           &src_rect, &dst_rect, mode, NULL );
+    }	
+#else
+    
+    CopyBits ( &(((GrafPtr)(src->hwdata->offscreen))->portBits),
+    	           &(((GrafPtr)(dst->hwdata->offscreen))->portBits),
+    	           &src_rect, &dst_rect, srcCopy, NULL );
+
+#endif /* DSP_TRY_CC_AND_AA */           
+	                             
+	SetGWorld (save_port, save_device);
+
+	return(0);
+}
+
+static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
+{
+	CGrafPtr save_port;
+	GDHandle save_device;
+	Rect     fill_rect;
+	RGBColor rgb;
+		
+	SetRect (&fill_rect, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
+	
+	GetGWorld (&save_port, &save_device);
+	SetGWorld (dst->hwdata->offscreen, NULL);
+
+    Index2Color (color, &rgb);
+    
+	RGBForeColor (&rgb);
+	PaintRect (&fill_rect);
+
+	SetGWorld (save_port, save_device);    
+
+	return(0);
+}
+
+static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface)
+{
+	  if ( (surface->flags & SDL_HWSURFACE) ) {
+		CGrafPtr dsp_front_buffer, save_port;
+		Rect rect;
+		
+		unsigned int old_count;
+		
+		/* pseudo page flipping for VRAM back buffer*/ 
+		DSpContext_GetFrontBuffer (dsp_context, &dsp_front_buffer);
+		SetRect (&rect, 0, 0, surface->w-1, surface->h-1);  	
+  		
+  		GetPort ((GrafPtr *)&save_port);
+  		SetPort ((GrafPtr)dsp_front_buffer);
+  		
+  		/* wait for retrace */
+  		/* I have tried doing the swap in interrupt routine (VBL Proc) to do */
+  		/* it asynchronously, but apparently CopyBits isn't interrupt safe  */		   
+        
+            #if ! TARGET_API_MAC_OSX
+		#ifndef DSP_NO_SYNC_VBL
+    		old_count = retrace_count;
+    		while (old_count == retrace_count)
+    			  ;
+		#endif				  
+            #endif
+  		
+          CopyBits ( GetPortBitMapForCopyBits(dsp_back_buffer),
+                      GetPortBitMapForCopyBits(dsp_front_buffer),
+  			   &rect, &rect, srcCopy, NULL );
+  	
+  		SetPort ((GrafPtr)save_port);
+  		
+	} else {
+		/* not really page flipping at all: DSp just blits the dirty rectangles from DSp_UpdateRects */	    
+		Boolean busy_flag;
+		DSpContext_SwapBuffers (dsp_context, NULL, &busy_flag); /* this  waits for VBL */
+		DSpContext_GetBackBuffer (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
+        surface->pixels =  GetPixBaseAddr( GetPortPixMap(dsp_back_buffer) );
+	}
+	return(0);
+}
+
+static int DSp_LockHWSurface(_THIS, SDL_Surface *surface)
+{
+	if ( LockPixels (GetGWorldPixMap (surface->hwdata->offscreen)) )
+		return 0;
+	else
+		return -1;
+}
+
+static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface)
+{
+	UnlockPixels (GetGWorldPixMap (surface->hwdata->offscreen));
+}
+
+static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
+{
+	return;
+}
+
+static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
+{
+#if ! TARGET_API_MAC_OSX /* Unsupported DSp in here */
+	int i;
+	Rect rect;
+	
+	for (i = 0; i < numrects; i++) {
+	
+		rect.top    = sdl_rects[i].y;
+		rect.left   = sdl_rects[i].x;
+		rect.bottom = sdl_rects[i].h + sdl_rects[i].y;
+		rect.right  = sdl_rects[i].w + sdl_rects[i].x;
+		
+		DSpContext_InvalBackBufferRect (dsp_context, &rect);		
+	}
+#endif
+}
+
+static int DSp_CreatePalette(_THIS) {
+
+
+	/* Create our palette */
+	SDL_CTab = (CTabHandle)NewHandle(sizeof(ColorSpec)*256 + 8);
+	if ( SDL_CTab == nil ) {
+		SDL_OutOfMemory();
+		return(-1);
+	}
+	(**SDL_CTab).ctSeed = GetCTSeed();
+	(**SDL_CTab).ctFlags = 0;
+	(**SDL_CTab).ctSize = 255;
+	CTabChanged(SDL_CTab);
+	SDL_CPal = NewPalette(256, SDL_CTab, pmExplicit+pmTolerant, 0);
+	
+	return 0;
+}
+
+static int DSp_DestroyPalette(_THIS) {
+
+	/* Free palette and restore original one */
+	if ( SDL_CTab != nil ) {
+		DisposeHandle((Handle)SDL_CTab);
+		SDL_CTab = nil;
+	}
+	if ( SDL_CPal != nil ) {
+		DisposePalette(SDL_CPal);
+		SDL_CPal = nil;
+	}
+	RestoreDeviceClut(SDL_Display);
+	
+   return (0);
+}
+
+static int DSp_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
+{
+	CTabHandle   cTab;
+	
+	int i;
+
+	cTab = SDL_CTab;
+	
+	/* Verify the range of colors */
+	if ( (firstcolor+ncolors) > ((**cTab).ctSize+1) ) {
+		return(0);
+	}
+	
+	/* Set the screen palette and update the display */
+	for(i = 0; i < ncolors; i++) {
+	        int j = firstcolor + i;
+	        (**cTab).ctTable[j].value = j;
+		(**cTab).ctTable[j].rgb.red = colors[i].r << 8 | colors[i].r;
+		(**cTab).ctTable[j].rgb.green = colors[i].g << 8 | colors[i].g;
+		(**cTab).ctTable[j].rgb.blue = colors[i].b << 8 | colors[i].b;
+	}
+	
+	SetGDevice(SDL_Display);
+	SetEntries(0, (**cTab).ctSize, (ColorSpec *)&(**cTab).ctTable);
+
+	return(1);
+}
+
+void DSp_VideoQuit(_THIS)
+{
+	int i;
+	
+	/* Free current video mode */
+	DSp_UnsetVideoMode(this, this->screen);
+
+   /* Free Palette and restore original */
+   DSp_DestroyPalette (this);
+
+	/* Free list of video modes */
+	if ( SDL_modelist != NULL ) {
+		for ( i=0; SDL_modelist[i]; i++ ) {
+			free(SDL_modelist[i]);
+		}
+		free(SDL_modelist);
+		SDL_modelist = NULL;
+	}
+	
+	/* Unload DrawSprocket */
+   DSpShutdown ();
+}
+
+#ifdef HAVE_OPENGL
+
+/* swap buffers with v-sync */
+static void DSp_GL_SwapBuffers (_THIS) {
+
+   #ifndef DSP_NO_SYNC_OPENGL
+   
+       unsigned int old_count;
+          
+       old_count = retrace_count;
+       while (old_count == retrace_count)
+          ;
+   #endif
+      
+   aglSwapBuffers (glContext);
+}
+
+#endif