1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25 Written by Darrell Walisser <dwaliss1@purdue.edu>
26
27 Implementation notes ----------------------------------------------------------------------
28
29 A bit on GWorlds in VRAM from technote 1182:
30
31 There are two important things to note about GWorld's allocated in
32 VRAM. First, the base address retrieved through GetPixBaseAddr or
33 read directly from the PixMap structure can become invalid anytime
34 memory is allocated in VRAM. This can occur either by explicit
35 allocations, such as calls to NewGWorld, or by implicit ones, such as
36 those associated with the internal texture allocation of OpenGL. The
37 stored pixel images themselves will still be valid but may have been
38 moved in VRAM, thus rendering any stored base addresses invalid.
39 You should never store an image's base address for longer than is
40 necessary and especially never across calls to NewGWorld or
41 texture-creation routines.
42
43 Secondly, an offscreen pixel image allocated in VRAM can be
44 purged at system task time by the display driver. This means any
45 time your application yields time such by calling WaitNextEvent or
46 SystemTask you can lose your VRAM GWorld contents. While this
47 happens infrequently, usually associated with display resolution or
48 pixel depth changes you must code for this eventuality. This purge
49 can occur whether or not the GWorld is locked or not. A return value
50 of false from LockPixels, a NULL return value from GetPixBaseAddr
51 or NULL in the baseAddr field of the PixMap mean that the pixel
52 image has been purged. To reallocate it you can either call
53 UpdateGWorld or Dispose your current GWorld through
54 DisposeGWorld and reallocate it via NewGWorld. Either way you must
55 then rebuild the pixel image.
56
57------------------------------------------------------------------------------------
58
59  Currently, I don't account for (1). In my testing, NewGWorld never invalidated
60  other existing GWorlds in VRAM. However, I do have protection for (2).
61  Namely, I am using GetOSEvent() instead of WaitNextEvent() so that there are no
62  context switches (the app hogs the CPU). Eventually a book-keeping system should
63  be coded to take care of (1) and (2).
64
65------------------------------------------------------------------------------------
66
67  System requirements (* denotes optional):
68
69  1. DrawSprocket 1.7.3
70  2. *MacOS 9 or later (but *not* Mac OS X) for hardware accelerated blit / fill
71  3. *May also require certain graphics hardware for (2). I trust that all Apple OEM
72     hardware will work. Third party accelerators may work if they have QuickDraw
73     acceleration in the drivers and the drivers have been updated for OS 9. The current
74     Voodoo 3 drivers (1.0b12) do not work.
75
76  Coding suggestions:
77
78  1. Use SDL_UpdateRects !
79
80    If no QuickDraw acceleration is present, double-buffered surfaces will use a back buffer
81    in System memory. I recommend you use SDL_UpdateRects with double-buffered surfaces
82    for best performance on these cards, since the overhead is nearly zero for VRAM back buffer.
83
84  2. Load most-resident surfaces first.
85
86    If you fill up VRAM or AGP memory, there is no contingency for purging to make room for the next one.
87    Therefore, you should load the surfaces you plan to use the most frequently first.
88    Sooner or later, I will code LRU replacement to help this.
89
90  TODO:
91  Some kind of posterized mode for resolutions < 640x480.
92  Window support / fullscreen toggle.
93  Figure out how much VRAM is available. Put in video->info->video_mem.
94  Track VRAM usage.
95
96  BUGS:
97  I can't create a hardware surface the same size as the screen?! How to fix?
98
99
100
101   COMPILE OPTIONS:
102
103   DSP_TRY_CC_AND_AA - Define if you want to try HWA color-key and alpha blitters
104                       HW color-key blitting gives substantial improvements,
105                       but hw alpha is neck-and-neck with SDL's soft bitter.
106
107   DSP_NO_SYNC_VBL   - Define for HWA double-buffered surfaces: don't sync
108                       pseudo-flip to monitor redraw.
109
110   DSP_NO_SYNC_OPENGL - Define for OpenGL surfaces: don't sync buffer swap. Synching buffer
111                        swap may result in reduced performance, but can eliminate some
112                        tearing artifacts.
113   CHANGELOG:
114   09/17/00 Lots of little tweaks. Build modelist in reverse order so largest contexts
115            list first. Compared various methods with ROM methods and fixed rez switch
116            crashing bug in GL Tron. (Woohoo!)
117*/
118
119#define DSP_TRY_CC_AND_AA
120
121/* #define DSP_NO_SYNC_VBL */
122
123#define DSP_NO_SYNC_OPENGL
124
125
126#if defined(__APPLE__) && defined(__MACH__)
127#include <Carbon/Carbon.h>
128#include <DrawSprocket/DrawSprocket.h>
129#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
130#include <Carbon.h>
131#include <DrawSprocket.h>
132#else
133#include <LowMem.h>
134#include <Gestalt.h>
135#include <Devices.h>
136#include <DiskInit.h>
137#include <QDOffscreen.h>
138#include <DrawSprocket.h>
139#endif
140
141#include "SDL_video.h"
142#include "SDL_syswm.h"
143#include "../SDL_sysvideo.h"
144#include "../SDL_blit.h"
145#include "../SDL_pixels_c.h"
146#include "SDL_dspvideo.h"
147#include "../maccommon/SDL_macgl_c.h"
148#include "../maccommon/SDL_macwm_c.h"
149#include "../maccommon/SDL_macmouse_c.h"
150#include "../maccommon/SDL_macevents_c.h"
151
152/* Initialization/Query functions */
153static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat);
154static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
155static SDL_Surface *DSp_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
156static int DSp_SetColors(_THIS, int firstcolor, int ncolors,
157			 SDL_Color *colors);
158static int DSp_CreatePalette(_THIS);
159static int DSp_DestroyPalette(_THIS);
160static void DSp_VideoQuit(_THIS);
161
162static int DSp_GetMainDevice (_THIS, GDHandle *device);
163static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat);
164static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
165static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects);
166
167/* Hardware surface functions */
168static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha);
169static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key);
170static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height);
171static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface);
172static int DSp_LockHWSurface(_THIS, SDL_Surface *surface);
173static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface);
174static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface);
175static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface);
176static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest);
177static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
178                           SDL_Surface *dst, SDL_Rect *dstrect);
179static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
180
181#if SDL_VIDEO_OPENGL
182   static void DSp_GL_SwapBuffers (_THIS);
183#endif
184
185#if ! TARGET_API_MAC_CARBON
186
187    #define GetPortPixRowBytes(x)  ( (*(x->portPixMap))->rowBytes )
188   #define GetGDevPixMap(x) ((**(x)).gdPMap)
189   #define GetPortPixMap(x) ((*(x)).portPixMap)
190
191   #define GetPixDepth(y)    ((**(y)).pixelSize)
192   //#define GetPixRowBytes(y) ((**(y)).rowBytes)
193   //#define GetPixBaseAddr(y) ((**(y)).baseAddr)
194   #define GetPixCTab(y)     ((**(y)).pmTable)
195    #define GetPortBitMapForCopyBits(x) (&(((GrafPtr)(x))->portBits))
196
197#else
198    #define GetPortPixRowBytes(x) (GetPixRowBytes(GetPortPixMap(x)) )
199    #define GetGDevPixMap(x) ((**(x)).gdPMap)
200
201#endif
202
203typedef struct private_hwdata {
204
205  GWorldPtr offscreen;    // offscreen gworld in VRAM or AGP
206
207  #ifdef DSP_TRY_CC_AND_AA
208    GWorldPtr mask;         // transparent mask
209    RGBColor  alpha;        // alpha color
210    RGBColor  trans;        // transparent color
211  #endif
212
213} private_hwdata;
214
215typedef private_hwdata private_swdata ; /* have same fields */
216
217/* Macintosh toolbox driver bootstrap functions */
218
219static int DSp_Available(void)
220{
221	/* Check for DrawSprocket */
222#if ! TARGET_API_MAC_OSX
223	/* This check is only meaningful if you weak-link DrawSprocketLib */
224	return ((Ptr)DSpStartup != (Ptr)kUnresolvedCFragSymbolAddress);
225#else
226	return 1; // DrawSprocket.framework doesn't have it all, but it's there
227#endif
228}
229
230static void DSp_DeleteDevice(SDL_VideoDevice *device)
231{
232	/* -dw- taking no chances with null pointers */
233	if (device) {
234
235   	if (device->hidden) {
236
237   	   if (device->hidden->dspinfo)
238	         SDL_free(device->hidden->dspinfo);
239
240   	   SDL_free(device->hidden);
241   	}
242	   SDL_free(device);
243	}
244}
245
246static SDL_VideoDevice *DSp_CreateDevice(int devindex)
247{
248	SDL_VideoDevice *device;
249
250	/* Initialize all variables that we clean on shutdown */
251	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
252	if ( device ) {
253		SDL_memset(device, 0, sizeof (*device));
254		device->hidden = (struct SDL_PrivateVideoData *)
255				SDL_malloc((sizeof *device->hidden));
256	    if (device->hidden)
257	        SDL_memset(device->hidden, 0, sizeof ( *(device->hidden) ) );
258	}
259	if ( (device == NULL) || (device->hidden == NULL) ) {
260		SDL_OutOfMemory();
261
262		if ( device ) {
263
264			if (device->hidden)
265				SDL_free(device->hidden);
266
267			SDL_free(device);
268		}
269
270		return(NULL);
271	}
272
273	/* Allocate DrawSprocket information */
274	device->hidden->dspinfo = (struct DSpInfo *)SDL_malloc(
275					(sizeof *device->hidden->dspinfo));
276	if ( device->hidden->dspinfo == NULL ) {
277		SDL_OutOfMemory();
278		SDL_free(device->hidden);
279		SDL_free(device);
280		return(0);
281	}
282	SDL_memset(device->hidden->dspinfo, 0, (sizeof *device->hidden->dspinfo));
283
284	/* Set the function pointers */
285	device->VideoInit       = DSp_VideoInit;
286	device->ListModes       = DSp_ListModes;
287	device->SetVideoMode    = DSp_SetVideoMode;
288	device->SetColors       = DSp_SetColors;
289	device->UpdateRects     = NULL;
290	device->VideoQuit       = DSp_VideoQuit;
291	device->AllocHWSurface  = DSp_AllocHWSurface;
292	device->CheckHWBlit     = NULL;
293	device->FillHWRect      = NULL;
294	device->SetHWColorKey   = NULL;
295	device->SetHWAlpha      = NULL;
296	device->LockHWSurface   = DSp_LockHWSurface;
297	device->UnlockHWSurface = DSp_UnlockHWSurface;
298	device->FlipHWSurface   = DSp_FlipHWSurface;
299	device->FreeHWSurface   = DSp_FreeHWSurface;
300#if SDL_MACCLASSIC_GAMMA_SUPPORT
301	device->SetGammaRamp    = Mac_SetGammaRamp;
302	device->GetGammaRamp    = Mac_GetGammaRamp;
303#endif
304#if SDL_VIDEO_OPENGL
305	device->GL_MakeCurrent  = Mac_GL_MakeCurrent;
306	device->GL_SwapBuffers  = DSp_GL_SwapBuffers;
307	device->GL_LoadLibrary = Mac_GL_LoadLibrary;
308	device->GL_GetProcAddress = Mac_GL_GetProcAddress;
309#endif
310	device->SetCaption = NULL;
311	device->SetIcon = NULL;
312	device->IconifyWindow = NULL;
313	device->GrabInput = NULL;
314	device->GetWMInfo = NULL;
315	device->FreeWMCursor    = Mac_FreeWMCursor;
316	device->CreateWMCursor  = Mac_CreateWMCursor;
317	device->ShowWMCursor    = Mac_ShowWMCursor;
318	device->WarpWMCursor    = Mac_WarpWMCursor;
319	device->InitOSKeymap    = Mac_InitOSKeymap;
320	device->PumpEvents      = Mac_PumpEvents;
321
322	device->GrabInput      = NULL;
323	device->CheckMouseMode = NULL;
324
325	device->free = DSp_DeleteDevice;
326
327	return device;
328}
329
330VideoBootStrap DSp_bootstrap = {
331	"DSp", "MacOS DrawSprocket",
332	DSp_Available, DSp_CreateDevice
333};
334
335/* Use DSp/Display Manager to build mode list for given screen */
336static SDL_Rect**  DSp_BuildModeList (const GDHandle gDevice, int *displayWidth, int *displayHeight)
337{
338	DSpContextAttributes  attributes;
339	DSpContextReference   context;
340	DisplayIDType         displayID;
341	SDL_Rect temp_list [16];
342	SDL_Rect **mode_list;
343	int width, height, i, j;
344
345        #if TARGET_API_MAC_OSX
346
347        displayID = 0;
348
349        #else
350        /* Ask Display Manager for integer id of screen device */
351	if ( DMGetDisplayIDByGDevice (gDevice, &displayID, SDL_TRUE) != noErr ) {
352		return NULL;
353	}
354	#endif
355	/* Get the first possible DSp context on this device */
356	if ( DSpGetFirstContext (displayID, &context) != noErr ) {
357		return NULL;
358	}
359
360	if ( DSpContext_GetAttributes (context, &attributes) != noErr )
361		return NULL;
362
363	*displayWidth = attributes.displayWidth;
364	*displayHeight = attributes.displayHeight;
365
366	for ( i = 0; i < SDL_arraysize(temp_list); i++ ) {
367		width  = attributes.displayWidth;
368		height = attributes.displayHeight;
369
370		temp_list [i].x = 0 | attributes.displayBestDepth;
371		temp_list [i].y = 0;
372		temp_list [i].w = width;
373		temp_list [i].h = height;
374
375		/* DSp will report many different contexts with the same width and height. */
376		/* They will differ in bit depth and refresh rate. */
377		/* We will ignore them until we reach one with a different width/height */
378		/* When there are no more contexts to look at, we will quit building the list*/
379		while ( width == attributes.displayWidth && height == attributes.displayHeight ) {
380
381			OSStatus err = DSpGetNextContext (context, &context);
382			if (err != noErr)
383				if (err == kDSpContextNotFoundErr)
384					goto done;
385				else
386					return NULL;
387
388			if ( DSpContext_GetAttributes (context, &attributes) != noErr )
389				return NULL;
390
391			temp_list [i].x |= attributes.displayBestDepth;
392		}
393	}
394done:
395	i++;          /* i was not incremented before kicking out of the loop */
396
397	mode_list = (SDL_Rect**) SDL_malloc (sizeof (SDL_Rect*) * (i+1));
398	if (mode_list) {
399
400	   /* -dw- new stuff: build in reverse order so largest sizes list first */
401		for (j = i-1; j >= 0; j--) {
402			mode_list [j] = (SDL_Rect*) SDL_malloc (sizeof (SDL_Rect));
403			if (mode_list [j])
404				SDL_memcpy (mode_list [j], &(temp_list [j]), sizeof (SDL_Rect));
405			else {
406				SDL_OutOfMemory ();
407				return NULL;
408			}
409		}
410		mode_list [i] = NULL;		/* append null to the end */
411	}
412	else {
413		SDL_OutOfMemory ();
414		return NULL;
415	}
416
417	return mode_list;
418}
419
420static void DSp_IsHWAvailable (_THIS, SDL_PixelFormat *vformat)
421{
422  /*
423     VRAM GWorlds are only available on OS 9 or later.
424     Even with OS 9, some display drivers won't support it,
425     so we create a test GWorld and check for errors.
426  */
427
428  long versionSystem;
429
430  dsp_vram_available = SDL_FALSE;
431  dsp_agp_available  = SDL_FALSE;
432
433  Gestalt ('sysv', &versionSystem);
434  if (0x00000860 < (versionSystem & 0x0000FFFF)) {
435
436    GWorldPtr offscreen;
437    OSStatus  err;
438    Rect      bounds;
439
440    SetRect (&bounds, 0, 0, 320, 240);
441
442#if useDistantHdwrMem && useLocalHdwrMem
443    err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useDistantHdwrMem | noNewDevice);
444    if (err == noErr) {
445      dsp_vram_available = SDL_TRUE;
446      DisposeGWorld (offscreen);
447    }
448
449    err = NewGWorld (&offscreen, vformat->BitsPerPixel, &bounds, NULL, SDL_Display, useLocalHdwrMem | noNewDevice);
450    if (err == noErr) {
451      DisposeGWorld (offscreen);
452      dsp_agp_available = SDL_TRUE;
453    }
454#endif
455  }
456}
457
458static int DSp_GetMainDevice (_THIS, GDHandle *device)
459{
460
461#if TARGET_API_MAC_OSX
462        /* DSpUserSelectContext not available on OS X */
463        *device = GetMainDevice();
464        return 0;
465#else
466
467	DSpContextAttributes attrib;
468	DSpContextReference  context;
469	DisplayIDType        display_id;
470	GDHandle             main_device;
471	GDHandle             device_list;
472
473	device_list = GetDeviceList ();
474	main_device = GetMainDevice ();
475
476	/* Quick check to avoid slower method when only one display exists */
477	if ( (**device_list).gdNextGD == NULL ) {
478	  *device = main_device;
479	  return 0;
480	}
481
482	SDL_memset (&attrib, 0, sizeof (DSpContextAttributes));
483
484	/* These attributes are hopefully supported on all devices...*/
485	attrib.displayWidth         = 640;
486	attrib.displayHeight        = 480;
487	attrib.displayBestDepth     = 8;
488	attrib.backBufferBestDepth  = 8;
489	attrib.displayDepthMask     = kDSpDepthMask_All;
490	attrib.backBufferDepthMask  = kDSpDepthMask_All;
491	attrib.colorNeeds           = kDSpColorNeeds_Require;
492	attrib.pageCount            = 1;
493
494	if (noErr != DMGetDisplayIDByGDevice (main_device, &display_id, SDL_FALSE)) {
495		SDL_SetError ("Display Manager couldn't associate GDevice with a Display ID");
496		return (-1);
497	}
498
499	/* Put up dialog on main display to select which display to use */
500	if (noErr != DSpUserSelectContext (&attrib, display_id, NULL, &context)) {
501		SDL_SetError ("DrawSprocket couldn't create a context");
502		return (-1);
503	}
504
505	if (noErr != DSpContext_GetDisplayID (context, &display_id)) {
506		SDL_SetError ("DrawSprocket couldn't get display ID");
507		return (-1);
508	}
509
510	if (noErr != DMGetGDeviceByDisplayID  (display_id, &main_device, SDL_FALSE)) {
511		SDL_SetError ("Display Manager couldn't associate Display ID with GDevice");
512		return (-1);
513	}
514
515	*device = main_device;
516	return (0);
517#endif
518}
519
520static int DSp_VideoInit(_THIS, SDL_PixelFormat *vformat)
521{
522	NumVersion dsp_version = { 0x01, 0x00, 0x00, 0x00 };
523
524#if UNIVERSAL_INTERFACES_VERSION > 0x0320
525	dsp_version = DSpGetVersion ();
526#endif
527
528	if (  (dsp_version.majorRev == 1 && dsp_version.minorAndBugRev < 0x73) ||
529	      (dsp_version.majorRev < 1)  ) {
530
531	   /* StandardAlert (kAlertStopAlert, "\pError!",
532	                "\pI need DrawSprocket 1.7.3 or later!\n"
533	                  "You can find a newer version at http://www.apple.com/swupdates.",
534	                   NULL, NULL);
535	    */
536	    SDL_SetError ("DrawSprocket version is too old. Need 1.7.3 or later.");
537	    return (-1);
538	}
539
540	if ( DSpStartup () != noErr ) {
541		SDL_SetError ("DrawSprocket couldn't startup");
542		return(-1);
543	}
544
545	/* Start DSpintosh events */
546	Mac_InitEvents(this);
547
548	/* Get a handle to the main monitor, or choose one on multiple monitor setups */
549	if ( DSp_GetMainDevice(this, &SDL_Display) <  0)
550		return (-1);
551
552	/* Determine pixel format */
553    vformat->BitsPerPixel = GetPixDepth ( (**SDL_Display).gdPMap );
554	dsp_old_depth = vformat->BitsPerPixel;
555
556	switch (vformat->BitsPerPixel) {
557		case 16:
558			vformat->Rmask = 0x00007c00;
559			vformat->Gmask = 0x000003e0;
560			vformat->Bmask = 0x0000001f;
561			break;
562		default:
563			break;
564	}
565
566	if ( DSp_CreatePalette (this) < 0 ) {
567		SDL_SetError ("Could not create palette");
568		return (-1);
569	}
570
571	/* Get a list of available fullscreen modes */
572	SDL_modelist = DSp_BuildModeList (SDL_Display,
573	                                  &this->info.current_w, &this->info.current_h);
574	if (SDL_modelist == NULL) {
575		SDL_SetError ("DrawSprocket could not build a mode list");
576		return (-1);
577	}
578
579	/* Check for VRAM and AGP GWorlds for HW Blitting */
580	DSp_IsHWAvailable (this, vformat);
581
582	this->info.wm_available = 0;
583
584	if (dsp_vram_available || dsp_agp_available) {
585
586	  this->info.hw_available = SDL_TRUE;
587
588	  this->CheckHWBlit  = DSp_CheckHWBlit;
589	  this->info.blit_hw = SDL_TRUE;
590
591	  this->FillHWRect     = DSp_FillHWRect;
592	  this->info.blit_fill = SDL_TRUE;
593
594	#ifdef DSP_TRY_CC_AND_AA
595	  this->SetHWColorKey   = DSp_SetHWColorKey;
596	  this->info.blit_hw_CC = SDL_TRUE;
597
598	  this->SetHWAlpha      = DSp_SetHWAlpha;
599	  this->info.blit_hw_A  = SDL_TRUE;
600	#endif
601
602	}
603
604	return(0);
605}
606
607static SDL_Rect **DSp_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
608{
609	static SDL_Rect *dsp_modes[16];
610	int i = 0, j = 0;
611
612	if ( format->BitsPerPixel == 0 )
613	   return ( (SDL_Rect**) NULL );
614
615	while (SDL_modelist[i] != NULL) {
616
617	   if (SDL_modelist[i]->x & format->BitsPerPixel) {
618	      dsp_modes[j] = SDL_modelist[i];
619	      j++;
620	   }
621	   i++;
622	}
623
624	dsp_modes[j] = NULL;
625
626	return dsp_modes;
627}
628
629/* Various screen update functions available */
630static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
631
632#if ! TARGET_API_MAC_OSX
633
634static volatile unsigned int retrace_count = 0; /* -dw- need volatile because it updates asychronously */
635
636Boolean DSp_VBLProc ( DSpContextReference context, void *ref_con )
637{
638	retrace_count++;
639
640	return 1; /* Darrell, is this right? */
641}
642
643static void DSp_SetHWError (OSStatus err, int is_agp)
644{
645	char message[1024];
646	const char *fmt, *mem;
647
648	if ( is_agp ) {
649		mem = "AGP Memory";
650	} else {
651		mem = "VRAM";
652	}
653	switch(err) {
654	    case memFullErr:
655		fmt = "Hardware surface possible but not enough %s available";
656		break;
657	    case cDepthErr:
658		fmt = "Hardware surface possible but invalid color depth";
659		break;
660	    default:
661		fmt = "Hardware surface could not be allocated in %s - unknown error";
662		break;
663	}
664	SDL_snprintf(message, SDL_arraysize(message), fmt, mem);
665	SDL_SetError(message);
666}
667#endif // TARGET_API_MAC_OSX
668
669/* put up a dialog to verify display change */
670static int DSp_ConfirmSwitch () {
671
672  /* resource id's for dialog */
673  const int rDialog = 1002;
674  const int bCancel = 1;
675  const int bOK     = 2;
676
677  DialogPtr dialog;
678  OSStatus  err;
679  SInt32    response;
680  DialogItemIndex       item = 0;
681  GrafPtr   savePort;
682
683  GetPort (&savePort);
684
685  dialog = GetNewDialog (rDialog, NULL, (WindowPtr) -1);
686  if (dialog == NULL)
687	 return (0);
688
689#if TARGET_API_MAC_CARBON
690  SetPort (GetDialogPort(dialog));
691#else
692  SetPort ((WindowPtr) dialog);
693#endif
694
695  SetDialogDefaultItem (dialog, bCancel);
696  SetDialogCancelItem  (dialog, bCancel);
697
698  SetEventMask (everyEvent);
699  FlushEvents (everyEvent, 0);
700
701   /* On MacOS 8.5 or later, we can make the dialog go away after 15 seconds */
702   /* This is good since it's possible user can't even see the dialog! */
703   /* Requires linking to DialogsLib */
704   err = Gestalt(gestaltSystemVersion,&response);
705   if (err == noErr && response >= 0x00000850) {
706   	SetDialogTimeout(dialog, bCancel, 15);
707   }
708
709   do {
710
711    ModalDialog ( NULL, &item );
712
713   } while ( item != bCancel && item != bOK && err != noErr);
714
715
716  DisposeDialog (dialog);
717  SetPort (savePort);
718
719  SetEventMask(everyEvent - autoKeyMask);
720  FlushEvents(everyEvent, 0);
721
722  return (item - 1);
723}
724
725static void DSp_UnsetVideoMode(_THIS, SDL_Surface *current)
726{
727
728
729	 if ( current->flags & SDL_OPENGL )  {
730	   Mac_GL_Quit (this);
731	}
732
733	if (dsp_context != NULL) {
734
735		GWorldPtr front;
736		DSpContext_GetFrontBuffer (dsp_context, &front);
737
738		if (front != dsp_back_buffer)
739		   DisposeGWorld (dsp_back_buffer);
740
741		if (current->hwdata)
742		   SDL_free(current->hwdata);
743
744		DSpContext_SetState (dsp_context, kDSpContextState_Inactive );
745		DSpContext_Release  (dsp_context);
746
747		dsp_context = NULL;
748	}
749
750    if (SDL_Window != NULL) {
751        DisposeWindow (SDL_Window);
752        SDL_Window = NULL;
753    }
754
755    current->pixels = NULL;
756    current->flags  = 0;
757}
758
759static SDL_Surface *DSp_SetVideoMode(_THIS,
760	SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
761{
762
763#if !TARGET_API_MAC_OSX
764    DisplayIDType        display_id;
765	Fixed freq;
766#endif
767	DSpContextAttributes attrib;
768	OSStatus err;
769	UInt32 rmask = 0, gmask = 0, bmask = 0;
770
771	int   page_count;
772	int   double_buf;
773	int   hw_surface;
774	int   use_dsp_back_buffer;
775
776	DSp_UnsetVideoMode (this, current);
777
778    if (bpp != dsp_old_depth)
779        DSp_DestroyPalette (this);
780
781	double_buf = (flags & SDL_DOUBLEBUF) != 0;
782	hw_surface = (flags & SDL_HWSURFACE) != 0;
783	use_dsp_back_buffer = !dsp_vram_available || !hw_surface ;
784
785	current->flags |= SDL_FULLSCREEN;
786
787rebuild:
788
789	if ( double_buf && use_dsp_back_buffer ) {
790		page_count = 2;
791	} else {
792		page_count = 1;
793	}
794
795	SDL_memset (&attrib, 0, sizeof (DSpContextAttributes));
796	attrib.displayWidth         = width;
797	attrib.displayHeight        = height;
798	attrib.displayBestDepth     = bpp;
799	attrib.backBufferBestDepth  = bpp;
800	attrib.displayDepthMask     = kDSpDepthMask_All;
801	attrib.backBufferDepthMask  = kDSpDepthMask_All;
802	attrib.colorNeeds           = kDSpColorNeeds_Require;
803	attrib.colorTable           = 0;
804	attrib.pageCount            = page_count;
805        #if TARGET_API_MAC_OSX || UNIVERSAL_INTERFACES_VERSION == 0x0320
806
807        if ( DSpFindBestContext (&attrib, &dsp_context) != noErr ) {
808            SDL_SetError ("DrawSprocket couldn't find a context");
809            return NULL;
810        }
811
812        #else
813	if ( noErr != DMGetDisplayIDByGDevice (SDL_Display, &display_id, SDL_FALSE) ) {
814		SDL_SetError ("Display Manager couldn't associate GDevice with display_id");
815		return NULL;
816	}
817	if ( DSpFindBestContextOnDisplayID(&attrib, &dsp_context, display_id) != noErr ) {
818		SDL_SetError ("DrawSprocket couldn't find a suitable context on given display");
819		return NULL;
820	}
821
822        #endif
823	if ( DSpContext_Reserve (dsp_context, &attrib) != noErr ) {
824		SDL_SetError ("DrawSprocket couldn't get the needed resources to build the display");
825		return NULL;
826	}
827
828	if ( (err = DSpContext_SetState (dsp_context, kDSpContextState_Active)) != noErr ) {
829
830		if (err == kDSpConfirmSwitchWarning) {
831
832		   if ( ! DSp_ConfirmSwitch () ) {
833
834		      DSpContext_Release (dsp_context);
835		      dsp_context = NULL;
836		      SDL_SetError ("User cancelled display switch");
837		      return NULL;
838		   }
839		   else
840		     /* Have to reactivate context. Why? */
841		     DSpContext_SetState (dsp_context, kDSpContextState_Active);
842
843	   }
844	   else {
845	      SDL_SetError ("DrawSprocket couldn't activate the context");
846		  return NULL;
847	   }
848	}
849
850
851	if (bpp != dsp_old_depth) {
852
853   	    DSp_CreatePalette  (this);
854
855       	/* update format if display depth changed */
856       	if (bpp == 16) {
857
858       	   rmask = 0x00007c00;
859       	   gmask = 0x000003e0;
860       	   bmask = 0x0000001f;
861       	}
862       	if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, 0 ) ) {
863
864       	   SDL_SetError ("Could not reallocate video format.");
865       	   return(NULL);
866       	}
867	}
868
869	if (!double_buf) {
870
871		/* single-buffer context */
872		DSpContext_GetFrontBuffer (dsp_context, &dsp_back_buffer);
873
874		current->hwdata   = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
875		if (current ->hwdata == NULL) {
876			SDL_OutOfMemory ();
877	  		return NULL;
878		}
879		current->hwdata->offscreen = dsp_back_buffer;
880	    current->flags   |= SDL_HWSURFACE;
881	    this->UpdateRects = DSp_DirectUpdate;
882	}
883	else if ( use_dsp_back_buffer ) {
884
885		DSpContext_GetBackBuffer  (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
886
887		current->flags   |= SDL_DOUBLEBUF | SDL_SWSURFACE; /* only front buffer is in VRAM */
888	    this->UpdateRects = DSp_DSpUpdate;
889	}
890	else if ( DSp_NewHWSurface(this, &dsp_back_buffer, bpp, width-1, height-1) == 0 ) {
891
892      current->hwdata = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
893      if (current ->hwdata == NULL) {
894      	SDL_OutOfMemory ();
895      	return NULL;
896      }
897
898      SDL_memset (current->hwdata, 0, sizeof (private_hwdata));
899      current->hwdata->offscreen = dsp_back_buffer;
900      current->flags |= SDL_DOUBLEBUF | SDL_HWSURFACE;
901      this->UpdateRects = DSp_DirectUpdate; /* hardware doesn't do update rects, must be page-flipped */
902   }
903   else {
904
905	   DSpContext_Release (dsp_context);
906	   use_dsp_back_buffer = SDL_TRUE;
907	   goto  rebuild;
908    }
909
910    current->pitch  = GetPortPixRowBytes(dsp_back_buffer) & 0x3FFF;
911	current->pixels = GetPixBaseAddr(GetPortPixMap(dsp_back_buffer));
912
913	current->w = width;
914	current->h = height;
915
916    #if ! TARGET_API_MAC_OSX
917
918	if (use_dsp_back_buffer) {
919
920	   DSpContext_GetMonitorFrequency (dsp_context, &freq);
921	   DSpContext_SetMaxFrameRate     (dsp_context, freq >> 16);
922	}
923
924
925	if ( (current->flags & SDL_HWSURFACE) || (current->flags & SDL_OPENGL) )
926		DSpContext_SetVBLProc (dsp_context, DSp_VBLProc, NULL);
927    #endif
928
929	if (bpp == 8)
930	   current->flags |= SDL_HWPALETTE;
931
932	if (flags & SDL_OPENGL) {
933
934	   Rect rect;
935	   RGBColor rgb = { 0.0, 0.0, 0.0 };
936	   GrafPtr save_port;
937
938	   SetRect (&rect, 0, 0, width, height);
939	   SDL_Window = NewCWindow(nil, &( (**SDL_Display).gdRect), "\p", SDL_TRUE, plainDBox, (WindowPtr)-1, SDL_FALSE, 0);
940
941	   if (SDL_Window == NULL) {
942
943		   SDL_SetError ("DSp_SetVideoMode : OpenGL window could not be created.");
944		   return NULL;
945	   }
946
947	   /* Set window color to black to avoid white flash*/
948	   GetPort (&save_port);
949#if TARGET_API_MAC_CARBON
950		SetPort (GetWindowPort(SDL_Window));
951#else
952	   SetPort (SDL_Window);
953#endif
954	      RGBForeColor (&rgb);
955	      PaintRect    (&rect);
956	   SetPort (save_port);
957
958	   SetPortWindowPort (SDL_Window);
959	   SelectWindow  (SDL_Window);
960
961	   if ( Mac_GL_Init (this) < 0 ) {
962
963	      SDL_SetError ("DSp_SetVideoMode : could not create OpenGL context.");
964	      return NULL;
965	   }
966
967	   current->flags |= SDL_OPENGL;
968	}
969
970	return current;
971}
972
973#ifdef DSP_TRY_CC_AND_AA
974
975static int DSp_MakeHWMask (_THIS, SDL_Surface *surface)
976{
977    GDHandle save_device;
978    CGrafPtr save_port;
979    GWorldPtr temp;
980    RGBColor black = { 0, 0, 0 };
981    RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
982    Rect     rect;
983
984    Uint32 depth = GetPixDepth ( GetGDevPixMap (SDL_Display) );
985
986    SetRect (&rect, 0, 0, surface->w, surface->h);
987
988    if ( noErr != NewGWorld (&(surface->hwdata->mask), depth, &rect, 0, SDL_Display, 0 ) < 0 ) {
989
990        SDL_OutOfMemory ();
991        return (-1);
992    }
993
994    if ( noErr != NewGWorld (&temp, depth, &rect, 0 , SDL_Display, 0 ) ) {
995
996        SDL_OutOfMemory ();
997        return (-1);
998    }
999
1000
1001    GetGWorld (&save_port, &save_device);
1002    SetGWorld (surface->hwdata->mask, SDL_Display);
1003
1004    RGBForeColor (&white);
1005    PaintRect    (&rect);
1006
1007    RGBBackColor (&(surface->hwdata->trans));
1008
1009    CopyBits ( GetPortBitMapForCopyBits(surface->hwdata->offscreen),
1010                 GetPortBitMapForCopyBits(surface->hwdata->mask),
1011    	       &rect, &rect, transparent, NULL );
1012
1013    SetGWorld (surface->hwdata->mask, SDL_Display);
1014    SetGWorld (save_port, save_device);
1015    return (0);
1016}
1017
1018static int DSp_SetHWAlpha(_THIS, SDL_Surface *surface, UInt8 alpha)
1019{
1020    surface->hwdata->alpha.red   = (alpha / 255.0) * 65535;
1021    surface->hwdata->alpha.blue  = (alpha / 255.0) * 65535;
1022    surface->hwdata->alpha.green = (alpha / 255.0) * 65535;
1023
1024    surface->flags |= SDL_SRCALPHA;
1025
1026    if (surface->flags & SDL_SRCCOLORKEY) {
1027        return(DSp_MakeHWMask (this, surface));
1028    }
1029    return(0);
1030}
1031
1032static int DSp_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
1033{
1034    CGrafPtr save_port;
1035    GDHandle save_device;
1036
1037    GetGWorld (&save_port, &save_device);
1038    SetGWorld (surface->hwdata->offscreen, NULL);
1039
1040    Index2Color (key, &(surface->hwdata->trans));
1041    surface->flags |= SDL_SRCCOLORKEY;
1042
1043    SetGWorld (save_port, save_device);
1044
1045    if ( surface->flags & SDL_SRCALPHA ) {
1046        return(DSp_MakeHWMask (this, surface));
1047    }
1048    return(0);
1049}
1050
1051#endif /* DSP_TRY_CC_AND_AA */
1052
1053static int DSp_NewHWSurface(_THIS, CGrafPtr *port, int depth, int width, int height) {
1054
1055   OSStatus err;
1056   Rect     bounds;
1057
1058	SetRect (&bounds, 0, 0, width, height);
1059
1060 #if useDistantHdwrMem && useLocalHdwrMem
1061    if (dsp_vram_available) {
1062	   /* try VRAM */
1063   	  err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useDistantHdwrMem | noNewDevice );
1064      if (err != noErr)
1065         DSp_SetHWError (err, SDL_FALSE);
1066      else
1067         return (0);
1068    }
1069
1070    if (dsp_agp_available) {
1071      /* try AGP */
1072      err = NewGWorld (port, depth, &bounds, 0 , SDL_Display, useLocalHdwrMem | noNewDevice );
1073
1074      if (err != noErr)
1075         DSp_SetHWError (err, SDL_TRUE);
1076      else
1077         return (0);
1078     }
1079#endif
1080
1081   return (-1);
1082}
1083
1084static int DSp_AllocHWSurface(_THIS, SDL_Surface *surface)
1085{
1086	GWorldPtr temp;
1087
1088	if ( DSp_NewHWSurface (this, &temp, surface->format->BitsPerPixel, surface->w, surface->h) < 0 )
1089	   return (-1);
1090
1091	surface->hwdata = (private_hwdata*) SDL_malloc (sizeof (private_hwdata));
1092	if (surface->hwdata == NULL) {
1093		SDL_OutOfMemory ();
1094		return -1;
1095	}
1096
1097	SDL_memset (surface->hwdata, 0, sizeof(private_hwdata));
1098	surface->hwdata->offscreen = temp;
1099	surface->pitch	 = GetPixRowBytes (GetPortPixMap (temp)) & 0x3FFF;
1100	surface->pixels  = GetPixBaseAddr (GetPortPixMap (temp));
1101	surface->flags	|= SDL_HWSURFACE;
1102#ifdef DSP_TRY_CC_AND_AA
1103	surface->flags  |= SDL_HWACCEL;
1104#endif
1105	return 0;
1106}
1107
1108static void DSp_FreeHWSurface(_THIS, SDL_Surface *surface)
1109{
1110	if (surface->hwdata->offscreen != NULL)
1111		DisposeGWorld (surface->hwdata->offscreen);
1112	SDL_free(surface->hwdata);
1113
1114    surface->pixels = NULL;
1115}
1116
1117static int DSp_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dest)
1118{
1119	int accelerated;
1120
1121	/* Set initial acceleration on */
1122	src->flags |= SDL_HWACCEL;
1123
1124	/* Set the surface attributes */
1125	if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
1126		if ( ! this->info.blit_hw_A ) {
1127			src->flags &= ~SDL_HWACCEL;
1128		}
1129	}
1130	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
1131		if ( ! this->info.blit_hw_CC ) {
1132			src->flags &= ~SDL_HWACCEL;
1133		}
1134	}
1135
1136	/* Check to see if final surface blit is accelerated */
1137	accelerated = !!(src->flags & SDL_HWACCEL);
1138	if ( accelerated ) {
1139		src->map->hw_blit = DSp_HWAccelBlit;
1140	}
1141	return(accelerated);
1142}
1143
1144static int DSp_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
1145                           SDL_Surface *dst, SDL_Rect *dstrect)
1146{
1147	CGrafPtr save_port;
1148	GDHandle save_device;
1149	Rect src_rect, dst_rect;
1150    RGBColor black = { 0, 0, 0 };
1151    RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
1152
1153#ifdef DSP_TRY_CC_AND_AA
1154	UInt32 mode;
1155#endif
1156
1157	SetRect (&src_rect, srcrect->x, srcrect->y, srcrect->x + srcrect->w, srcrect->y + srcrect->h);
1158	SetRect (&dst_rect, dstrect->x, dstrect->y, dstrect->x + dstrect->w, dstrect->y + dstrect->h);
1159
1160	GetGWorld (&save_port, &save_device);
1161	SetGWorld (dst->hwdata->offscreen, NULL);
1162
1163	RGBForeColor (&black);
1164	RGBBackColor (&white);
1165
1166#ifdef DSP_TRY_CC_AND_AA
1167
1168	if ( (src->flags & SDL_SRCCOLORKEY) &&
1169	     (src->flags & SDL_SRCALPHA)  ) {
1170
1171	     OpColor (&(src->hwdata->alpha));
1172
1173         CopyDeepMask ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
1174                        GetPortBitMapForCopyBits(src->hwdata->mask),
1175                        GetPortBitMapForCopyBits(dst->hwdata->offscreen),
1176	                    &src_rect, &src_rect, &dst_rect,
1177	                    blend,
1178	                    NULL );
1179	}
1180	else {
1181
1182    	if ( src->flags & SDL_SRCCOLORKEY) {
1183    	    RGBBackColor (&(src->hwdata->trans) );
1184    	    mode = transparent;
1185    	}
1186    	else if (src->flags & SDL_SRCALPHA) {
1187
1188    	    OpColor (&(src->hwdata->alpha));
1189    	    mode = blend;
1190    	}
1191    	else {
1192
1193    	    mode = srcCopy;
1194    	}
1195
1196        CopyBits ( GetPortBitMapForCopyBits(src->hwdata->offscreen),
1197                   GetPortBitMapForCopyBits(dst->hwdata->offscreen),
1198    	           &src_rect, &dst_rect, mode, NULL );
1199    }
1200#else
1201
1202    CopyBits ( &(((GrafPtr)(src->hwdata->offscreen))->portBits),
1203    	           &(((GrafPtr)(dst->hwdata->offscreen))->portBits),
1204    	           &src_rect, &dst_rect, srcCopy, NULL );
1205
1206#endif /* DSP_TRY_CC_AND_AA */
1207
1208	SetGWorld (save_port, save_device);
1209
1210	return(0);
1211}
1212
1213static int DSp_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
1214{
1215	CGrafPtr save_port;
1216	GDHandle save_device;
1217	Rect     fill_rect;
1218	RGBColor rgb;
1219
1220	SetRect (&fill_rect, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
1221
1222	GetGWorld (&save_port, &save_device);
1223	SetGWorld (dst->hwdata->offscreen, NULL);
1224
1225    Index2Color (color, &rgb);
1226
1227	RGBForeColor (&rgb);
1228	PaintRect (&fill_rect);
1229
1230	SetGWorld (save_port, save_device);
1231
1232	return(0);
1233}
1234
1235static int DSp_FlipHWSurface(_THIS, SDL_Surface *surface)
1236{
1237	  if ( (surface->flags & SDL_HWSURFACE) ) {
1238		CGrafPtr dsp_front_buffer, save_port;
1239		Rect rect;
1240
1241    #if ! TARGET_API_MAC_OSX
1242		unsigned int old_count;
1243	#endif
1244
1245		/* pseudo page flipping for VRAM back buffer*/
1246		DSpContext_GetFrontBuffer (dsp_context, &dsp_front_buffer);
1247		SetRect (&rect, 0, 0, surface->w-1, surface->h-1);
1248
1249  		GetPort ((GrafPtr *)&save_port);
1250  		SetPort ((GrafPtr)dsp_front_buffer);
1251
1252  		/* wait for retrace */
1253  		/* I have tried doing the swap in interrupt routine (VBL Proc) to do */
1254  		/* it asynchronously, but apparently CopyBits isn't interrupt safe  */
1255
1256            #if ! TARGET_API_MAC_OSX
1257		#ifndef DSP_NO_SYNC_VBL
1258    		old_count = retrace_count;
1259    		while (old_count == retrace_count)
1260    			  ;
1261		#endif
1262            #endif
1263
1264          CopyBits ( GetPortBitMapForCopyBits(dsp_back_buffer),
1265                      GetPortBitMapForCopyBits(dsp_front_buffer),
1266  			   &rect, &rect, srcCopy, NULL );
1267
1268  		SetPort ((GrafPtr)save_port);
1269
1270	} else {
1271		/* not really page flipping at all: DSp just blits the dirty rectangles from DSp_UpdateRects */
1272		Boolean busy_flag;
1273		DSpContext_SwapBuffers (dsp_context, NULL, &busy_flag); /* this  waits for VBL */
1274		DSpContext_GetBackBuffer (dsp_context, kDSpBufferKind_Normal, &dsp_back_buffer);
1275        surface->pixels =  GetPixBaseAddr( GetPortPixMap(dsp_back_buffer) );
1276	}
1277	return(0);
1278}
1279
1280static int DSp_LockHWSurface(_THIS, SDL_Surface *surface)
1281{
1282	if ( LockPixels (GetGWorldPixMap (surface->hwdata->offscreen)) )
1283		return 0;
1284	else
1285		return -1;
1286}
1287
1288static void DSp_UnlockHWSurface(_THIS, SDL_Surface *surface)
1289{
1290	UnlockPixels (GetGWorldPixMap (surface->hwdata->offscreen));
1291}
1292
1293static void DSp_DirectUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
1294{
1295	return;
1296}
1297
1298static void DSp_DSpUpdate(_THIS, int numrects, SDL_Rect *sdl_rects)
1299{
1300#if ! TARGET_API_MAC_OSX /* Unsupported DSp in here */
1301	int i;
1302	Rect rect;
1303
1304	for (i = 0; i < numrects; i++) {
1305
1306		rect.top    = sdl_rects[i].y;
1307		rect.left   = sdl_rects[i].x;
1308		rect.bottom = sdl_rects[i].h + sdl_rects[i].y;
1309		rect.right  = sdl_rects[i].w + sdl_rects[i].x;
1310
1311		DSpContext_InvalBackBufferRect (dsp_context, &rect);
1312	}
1313#endif
1314}
1315
1316static int DSp_CreatePalette(_THIS) {
1317
1318
1319	/* Create our palette */
1320	SDL_CTab = (CTabHandle)NewHandle(sizeof(ColorSpec)*256 + 8);
1321	if ( SDL_CTab == nil ) {
1322		SDL_OutOfMemory();
1323		return(-1);
1324	}
1325	(**SDL_CTab).ctSeed = GetCTSeed();
1326	(**SDL_CTab).ctFlags = 0;
1327	(**SDL_CTab).ctSize = 255;
1328	CTabChanged(SDL_CTab);
1329	SDL_CPal = NewPalette(256, SDL_CTab, pmExplicit+pmTolerant, 0);
1330
1331	return 0;
1332}
1333
1334static int DSp_DestroyPalette(_THIS) {
1335
1336	/* Free palette and restore original one */
1337	if ( SDL_CTab != nil ) {
1338		DisposeHandle((Handle)SDL_CTab);
1339		SDL_CTab = nil;
1340	}
1341	if ( SDL_CPal != nil ) {
1342		DisposePalette(SDL_CPal);
1343		SDL_CPal = nil;
1344	}
1345	RestoreDeviceClut(SDL_Display);
1346
1347   return (0);
1348}
1349
1350static int DSp_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1351{
1352	CTabHandle   cTab;
1353
1354	int i;
1355
1356	cTab = SDL_CTab;
1357
1358	/* Verify the range of colors */
1359	if ( (firstcolor+ncolors) > ((**cTab).ctSize+1) ) {
1360		return(0);
1361	}
1362
1363	/* Set the screen palette and update the display */
1364	for(i = 0; i < ncolors; i++) {
1365	        int j = firstcolor + i;
1366	        (**cTab).ctTable[j].value = j;
1367		(**cTab).ctTable[j].rgb.red = colors[i].r << 8 | colors[i].r;
1368		(**cTab).ctTable[j].rgb.green = colors[i].g << 8 | colors[i].g;
1369		(**cTab).ctTable[j].rgb.blue = colors[i].b << 8 | colors[i].b;
1370	}
1371
1372	SetGDevice(SDL_Display);
1373	SetEntries(0, (**cTab).ctSize, (ColorSpec *)&(**cTab).ctTable);
1374
1375	return(1);
1376}
1377
1378void DSp_VideoQuit(_THIS)
1379{
1380	int i;
1381
1382	/* Free current video mode */
1383	DSp_UnsetVideoMode(this, this->screen);
1384
1385	/* Free Palette and restore original */
1386	DSp_DestroyPalette (this);
1387
1388#if SDL_MACCLASSIC_GAMMA_SUPPORT
1389	Mac_QuitGamma(this);
1390#endif
1391
1392	/* Free list of video modes */
1393	if ( SDL_modelist != NULL ) {
1394		for ( i=0; SDL_modelist[i]; i++ ) {
1395			SDL_free(SDL_modelist[i]);
1396		}
1397		SDL_free(SDL_modelist);
1398		SDL_modelist = NULL;
1399	}
1400
1401	/* Unload DrawSprocket */
1402	DSpShutdown ();
1403}
1404
1405#if SDL_VIDEO_OPENGL
1406
1407/* swap buffers with v-sync */
1408static void DSp_GL_SwapBuffers (_THIS) {
1409
1410   #ifndef DSP_NO_SYNC_OPENGL
1411
1412       unsigned int old_count;
1413
1414       old_count = retrace_count;
1415       while (old_count == retrace_count)
1416          ;
1417   #endif
1418
1419   aglSwapBuffers (glContext);
1420}
1421
1422#endif
1423