Mercurial > sdl-ios-xcode
comparison src/video/quartz/SDL_QuartzVideo.m @ 47:45b1c4303f87
Added initial support for Quartz video (thanks Darrell!)
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 07 Jun 2001 14:28:11 +0000 |
parents | |
children | ce9cd2cf0d0d |
comparison
equal
deleted
inserted
replaced
46:3dcf26fa9d15 | 47:45b1c4303f87 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 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 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@devolution.com | |
21 */ | |
22 | |
23 #include "SDL_QuartzVideo.h" | |
24 | |
25 /* Some variables to share among files, put in device structure eventually */ | |
26 static SDL_GrabMode currentGrabMode = SDL_GRAB_OFF; | |
27 static BOOL inForeground = YES; | |
28 static SDLKey keymap[256]; | |
29 static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */ | |
30 | |
31 /* Include files into one compile unit...break apart eventually */ | |
32 #include "SDL_QuartzWM.m" | |
33 #include "SDL_QuartzEvents.m" | |
34 #include "SDL_QuartzWindow.m" | |
35 | |
36 char QZ_Error[255]; /* Global error buffer to temporarily store more informative error messages */ | |
37 | |
38 /* Bootstrap binding, enables entry point into the driver */ | |
39 VideoBootStrap QZ_bootstrap = { | |
40 "Quartz", "MacOS X CoreGraphics", QZ_Available, QZ_CreateDevice | |
41 }; | |
42 | |
43 /* Bootstrap functions */ | |
44 static int QZ_Available () { | |
45 return 1; | |
46 } | |
47 | |
48 static SDL_VideoDevice* QZ_CreateDevice (int device_index) { | |
49 | |
50 #pragma unused (device_index) | |
51 | |
52 SDL_VideoDevice *device; | |
53 SDL_PrivateVideoData *hidden; | |
54 | |
55 device = (SDL_VideoDevice*) malloc (sizeof (*device) ); | |
56 hidden = (SDL_PrivateVideoData*) malloc (sizeof (*hidden) ); | |
57 | |
58 if (device == NULL || hidden == NULL) | |
59 SDL_OutOfMemory (); | |
60 | |
61 memset (device, 0, sizeof (*device) ); | |
62 memset (hidden, 0, sizeof (*hidden) ); | |
63 | |
64 device->hidden = hidden; | |
65 | |
66 device->VideoInit = QZ_VideoInit; | |
67 device->ListModes = QZ_ListModes; | |
68 device->SetVideoMode = QZ_SetVideoMode; | |
69 device->ToggleFullScreen = QZ_ToggleFullScreen; | |
70 device->SetColors = QZ_SetColors; | |
71 /* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */ | |
72 device->VideoQuit = QZ_VideoQuit; | |
73 | |
74 device->LockHWSurface = QZ_LockHWSurface; | |
75 device->UnlockHWSurface = QZ_UnlockHWSurface; | |
76 device->FreeHWSurface = QZ_FreeHWSurface; | |
77 /* device->FlipHWSurface = QZ_FlipHWSurface */; | |
78 | |
79 device->SetGamma = QZ_SetGamma; | |
80 device->GetGamma = QZ_GetGamma; | |
81 device->SetGammaRamp = QZ_SetGammaRamp; | |
82 device->GetGammaRamp = QZ_GetGammaRamp; | |
83 | |
84 device->GL_GetProcAddress = QZ_GL_GetProcAddress; | |
85 device->GL_GetAttribute = QZ_GL_GetAttribute; | |
86 device->GL_MakeCurrent = QZ_GL_MakeCurrent; | |
87 device->GL_SwapBuffers = QZ_GL_SwapBuffers; | |
88 device->GL_LoadLibrary = QZ_GL_LoadLibrary; | |
89 | |
90 device->FreeWMCursor = QZ_FreeWMCursor; | |
91 device->CreateWMCursor = QZ_CreateWMCursor; | |
92 device->ShowWMCursor = QZ_ShowWMCursor; | |
93 device->WarpWMCursor = QZ_WarpWMCursor; | |
94 device->MoveWMCursor = QZ_MoveWMCursor; | |
95 device->CheckMouseMode = QZ_CheckMouseMode; | |
96 device->InitOSKeymap = QZ_InitOSKeymap; | |
97 device->PumpEvents = QZ_PumpEvents; | |
98 | |
99 device->SetCaption = QZ_SetCaption; | |
100 device->SetIcon = QZ_SetIcon; | |
101 device->IconifyWindow = QZ_IconifyWindow; | |
102 /*device->GetWMInfo = QZ_GetWMInfo;*/ | |
103 device->GrabInput = QZ_GrabInput; | |
104 | |
105 device->free = QZ_DeleteDevice; | |
106 | |
107 return device; | |
108 } | |
109 | |
110 static void QZ_DeleteDevice (SDL_VideoDevice *device) { | |
111 | |
112 free (device->hidden); | |
113 free (device); | |
114 } | |
115 | |
116 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) { | |
117 | |
118 /* Initialize the video settings; this data persists between mode switches */ | |
119 display_id = kCGDirectMainDisplay; | |
120 save_mode = CGDisplayCurrentMode (display_id); | |
121 mode_list = CGDisplayAvailableModes (display_id); | |
122 palette = CGPaletteCreateDefaultColorPalette (); | |
123 | |
124 /* Gather some information that is useful to know about the display */ | |
125 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel), | |
126 kCFNumberSInt32Type, &device_bpp); | |
127 | |
128 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth), | |
129 kCFNumberSInt32Type, &device_width); | |
130 | |
131 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight), | |
132 kCFNumberSInt32Type, &device_height); | |
133 | |
134 video_format->BitsPerPixel = device_bpp; | |
135 windowTitle = @""; | |
136 | |
137 return 0; | |
138 } | |
139 | |
140 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { | |
141 | |
142 CFIndex num_modes = CFArrayGetCount (mode_list); | |
143 CFIndex i; | |
144 | |
145 static SDL_Rect **list = NULL; | |
146 int list_size = 0; | |
147 | |
148 /* Any windowed mode is acceptable */ | |
149 if ( (flags & SDL_FULLSCREEN) == 0 ) | |
150 return (SDL_Rect**)-1; | |
151 | |
152 /* Free memory from previous call, if any */ | |
153 if ( list != NULL ) { | |
154 | |
155 int i = 0; | |
156 | |
157 for (i = 0; list[i] != NULL; i++) | |
158 free (list[i]); | |
159 | |
160 free (list); | |
161 list = NULL; | |
162 } | |
163 | |
164 /* Build list of modes with the requested bpp */ | |
165 for (i = num_modes-1; i >= 0; i--) { | |
166 | |
167 CFDictionaryRef onemode = CFArrayGetValueAtIndex (mode_list, i); | |
168 CFNumberRef number; | |
169 int bpp; | |
170 | |
171 number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel); | |
172 CFNumberGetValue (number, kCFNumberSInt32Type, &bpp); | |
173 | |
174 if (bpp == format->BitsPerPixel) { | |
175 | |
176 int intvalue; | |
177 SDL_Rect *rect; | |
178 int lastwidth = 0, lastheight = 0, width, height; | |
179 | |
180 number = CFDictionaryGetValue (onemode, kCGDisplayWidth); | |
181 CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); | |
182 width = (Uint16) intvalue; | |
183 | |
184 number = CFDictionaryGetValue (onemode, kCGDisplayHeight); | |
185 CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); | |
186 height = (Uint16) intvalue; | |
187 | |
188 /* We'll get a lot of modes with the same size, so ignore them */ | |
189 if ( width != lastwidth && height != lastheight ) { | |
190 | |
191 lastwidth = width; | |
192 lastheight = height; | |
193 | |
194 list_size++; | |
195 | |
196 if ( list == NULL) | |
197 list = (SDL_Rect**) malloc (sizeof(*list) * list_size+1); | |
198 else | |
199 list = (SDL_Rect**) realloc (list, sizeof(*list) * list_size+1); | |
200 | |
201 rect = (SDL_Rect*) malloc (sizeof(**list)); | |
202 | |
203 if (list == NULL || rect == NULL) | |
204 SDL_OutOfMemory (); | |
205 | |
206 rect->w = width; | |
207 rect->h = height; | |
208 | |
209 list[list_size-1] = rect; | |
210 list[list_size] = NULL; | |
211 } | |
212 } | |
213 } | |
214 | |
215 return list; | |
216 } | |
217 | |
218 static void QZ_UnsetVideoMode (_THIS) { | |
219 | |
220 if ( mode_flags & SDL_OPENGL ) | |
221 QZ_TearDownOpenGL (this); | |
222 | |
223 /* Reset values that may change between switches */ | |
224 this->info.blit_fill = 0; | |
225 this->FillHWRect = NULL; | |
226 this->UpdateRects = NULL; | |
227 | |
228 /* Restore gamma settings */ | |
229 CGDisplayRestoreColorSyncSettings (); | |
230 | |
231 /* Restore original screen resolution */ | |
232 if ( mode_flags & SDL_FULLSCREEN ) { | |
233 CGDisplaySwitchToMode (display_id, save_mode); | |
234 CGDisplayRelease (display_id); | |
235 } | |
236 /* Release window mode data structures */ | |
237 else { | |
238 if ( (mode_flags & SDL_OPENGL) == 0 ) { | |
239 UnlockPortBits ( [ windowView qdPort ] ); | |
240 [ windowView release ]; | |
241 } | |
242 [ window setContentView:nil ]; | |
243 [ window close ]; | |
244 [ window release ]; | |
245 } | |
246 | |
247 /* Ensure the cursor will be visible and working when we quit */ | |
248 CGDisplayShowCursor (display_id); | |
249 CGAssociateMouseAndMouseCursorPosition (1); | |
250 } | |
251 | |
252 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width, | |
253 int height, int bpp, Uint32 flags) { | |
254 int exact_match; | |
255 | |
256 /* See if requested mode exists */ | |
257 mode = CGDisplayBestModeForParameters (display_id, bpp, width, | |
258 height, &exact_match); | |
259 | |
260 /* Require an exact match to the requested mode */ | |
261 if ( ! exact_match ) { | |
262 sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp); | |
263 SDL_SetError (QZ_Error); | |
264 goto ERR_NO_MATCH; | |
265 } | |
266 | |
267 /* Put up the blanking window (a window above all other windows) */ | |
268 if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) { | |
269 SDL_SetError ("Failed capturing display"); | |
270 goto ERR_NO_CAPTURE; | |
271 } | |
272 | |
273 /* Do the physical switch */ | |
274 if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { | |
275 SDL_SetError ("Failed switching display resolution"); | |
276 goto ERR_NO_SWITCH; | |
277 } | |
278 | |
279 /* None of these methods seem to fix the fullscreen artifacts bug(s) */ | |
280 #if USE_GDHANDLE | |
281 SetGDevice(GetMainDevice()); | |
282 current->pitch = (**(** GetMainDevice() ).gdPMap).rowBytes & 0x3FFF; | |
283 current->pixels = (**(** GetMainDevice() ).gdPMap).baseAddr; | |
284 #elif USE_CREATEPORT | |
285 device_port = CreateNewPortForCGDisplayID((Uint32*)display_id); | |
286 SetPort (device_port); | |
287 LockPortBits ( device_port ); | |
288 current->pixels = GetPixBaseAddr ( GetPortPixMap ( device_port ) ); | |
289 current->pitch = GetPixRowBytes ( GetPortPixMap ( device_port ) ); | |
290 UnlockPortBits ( device_port ); | |
291 #else | |
292 current->pixels = (Uint32*) CGDisplayBaseAddress (display_id); | |
293 current->pitch = CGDisplayBytesPerRow (display_id); | |
294 #endif | |
295 | |
296 current->w = width; | |
297 current->h = height; | |
298 current->flags |= SDL_FULLSCREEN; | |
299 current->flags |= SDL_HWSURFACE; | |
300 | |
301 this->UpdateRects = QZ_DirectUpdate; | |
302 | |
303 /* Setup some mode-dependant info */ | |
304 if ( CGSDisplayCanHWFill (display_id) ) { | |
305 this->info.blit_fill = 1; | |
306 this->FillHWRect = QZ_FillHWRect; | |
307 } | |
308 | |
309 if ( CGDisplayCanSetPalette (display_id) ) | |
310 current->flags |= SDL_HWPALETTE; | |
311 | |
312 /* Setup OpenGL for a fullscreen context */ | |
313 if (flags & SDL_OPENGL) { | |
314 | |
315 CGLError err; | |
316 CGLContextObj ctx; | |
317 | |
318 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { | |
319 return NULL; | |
320 } | |
321 | |
322 ctx = [ gl_context cglContext ]; | |
323 err = CGLSetFullScreen (ctx); | |
324 | |
325 if (err) { | |
326 sprintf (QZ_Error, "Error setting OpenGL fullscreen: %s", CGLErrorString(err)); | |
327 SDL_SetError (QZ_Error); | |
328 goto ERR_NO_GL; | |
329 } | |
330 | |
331 [ gl_context makeCurrentContext]; | |
332 | |
333 current->flags |= SDL_OPENGL; | |
334 } | |
335 | |
336 /* If we don't hide menu bar, it will get events and interrupt the program */ | |
337 HideMenuBar (); | |
338 | |
339 /* Save the flags to ensure correct tear-down */ | |
340 mode_flags = current->flags; | |
341 | |
342 return current; | |
343 | |
344 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crutial */ | |
345 ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); | |
346 ERR_NO_SWITCH: CGDisplayRelease (display_id); | |
347 ERR_NO_CAPTURE: | |
348 ERR_NO_MATCH: return NULL; | |
349 } | |
350 | |
351 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, | |
352 int height, int bpp, Uint32 flags) { | |
353 NSRect rect; | |
354 rect = NSMakeRect (0, 0, width, height); | |
355 | |
356 /* Manually create a window, avoids having a nib file resource */ | |
357 window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect | |
358 styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask) | |
359 backing: //NSBackingStoreBuffered | |
360 NSBackingStoreRetained | |
361 defer:NO ]; | |
362 | |
363 if (window == nil) { | |
364 SDL_SetError ("Could not create the Cocoa window"); | |
365 return NULL; | |
366 } | |
367 | |
368 current->w = width; | |
369 current->h = height; | |
370 | |
371 [ window setTitle:windowTitle ]; | |
372 [ window setAcceptsMouseMovedEvents:YES ]; | |
373 [ window center ]; | |
374 | |
375 /* For OpenGL, we set the content view to a NSOpenGLView */ | |
376 if ( flags & SDL_OPENGL ) { | |
377 | |
378 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { | |
379 return NULL; | |
380 } | |
381 | |
382 [ gl_context setView: [ window contentView ] ]; | |
383 [ gl_context makeCurrentContext]; | |
384 [ window orderFront:nil ]; | |
385 current->flags |= SDL_OPENGL; | |
386 } | |
387 /* For 2D, we set the content view to a NSQuickDrawView */ | |
388 else { | |
389 | |
390 windowView = [ [ NSQuickDrawView alloc ] init ]; | |
391 [ window setContentView:windowView ]; | |
392 [ window orderFront:nil ]; | |
393 | |
394 LockPortBits ( [ windowView qdPort ] ); | |
395 current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) ); | |
396 current->pitch = GetPixRowBytes ( GetPortPixMap ( [ windowView qdPort ] ) ); | |
397 | |
398 /* Offset 22 pixels down to fill the full content region */ | |
399 current->pixels += 22 * current->pitch; | |
400 | |
401 current->flags |= SDL_SWSURFACE; | |
402 current->flags |= SDL_PREALLOC; | |
403 | |
404 this->UpdateRects = QZ_UpdateRects; | |
405 } | |
406 return current; | |
407 } | |
408 | |
409 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, | |
410 int height, int bpp, Uint32 flags) { | |
411 | |
412 if (SDL_VideoSurface != NULL) | |
413 QZ_UnsetVideoMode (this); | |
414 | |
415 current->flags = 0; | |
416 | |
417 /* Setup full screen video */ | |
418 if ( flags & SDL_FULLSCREEN ) { | |
419 current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags ); | |
420 if (current == NULL) | |
421 return NULL; | |
422 } | |
423 /* Setup windowed video */ | |
424 else { | |
425 /* Force bpp to the device's bpp */ | |
426 bpp = current->format->BitsPerPixel; | |
427 current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags); | |
428 if (current == NULL) | |
429 return NULL; | |
430 } | |
431 | |
432 /* Setup the new pixel format */ | |
433 { | |
434 int amask = 0, | |
435 rmask = 0, | |
436 gmask = 0, | |
437 bmask = 0; | |
438 | |
439 switch (bpp) { | |
440 case 16: /* (1)-5-5-5 RGB */ | |
441 amask = 0; | |
442 rmask = 0x7c00; | |
443 gmask = 0x3e0; | |
444 bmask = 0x1f; | |
445 break; | |
446 case 24: | |
447 SDL_SetError ("24bpp is not available"); | |
448 return NULL; | |
449 case 32: /* (8)-8-8-8 ARGB */ | |
450 amask = 0xFF000000; | |
451 rmask = 0x00FF0000; | |
452 gmask = 0x0000FF00; | |
453 bmask = 0x000000FF; | |
454 break; | |
455 } | |
456 | |
457 if ( ! SDL_ReallocFormat (current, bpp, | |
458 rmask, gmask, bmask, amask ) ) { | |
459 SDL_SetError ("Couldn't reallocate pixel format"); | |
460 return NULL; | |
461 } | |
462 } | |
463 | |
464 /* Warp mouse to origin in order to get passive mouse motion events started correctly */ | |
465 QZ_PrivateWarpCursor (this, current->flags & SDL_FULLSCREEN, height, 0, 0); | |
466 | |
467 return current; | |
468 } | |
469 | |
470 static int QZ_ToggleFullScreen (_THIS, int on) { | |
471 return -1; | |
472 } | |
473 | |
474 static int QZ_SetColors (_THIS, int first_color, int num_colors, | |
475 SDL_Color *colors) { | |
476 | |
477 CGTableCount index; | |
478 CGDeviceColor color; | |
479 | |
480 for (index = first_color; index < first_color+num_colors; index++) { | |
481 | |
482 /* Clamp colors between 0.0 and 1.0 */ | |
483 color.red = colors->r / 255.0; | |
484 color.blue = colors->b / 255.0; | |
485 color.green = colors->g / 255.0; | |
486 | |
487 colors++; | |
488 | |
489 CGPaletteSetColorAtIndex (palette, color, index); | |
490 } | |
491 | |
492 if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) ) | |
493 return 0; | |
494 | |
495 return 1; | |
496 } | |
497 | |
498 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { | |
499 #pragma unused(this,num_rects,rects) | |
500 } | |
501 | |
502 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { | |
503 | |
504 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { | |
505 QZ_GL_SwapBuffers (this); | |
506 } | |
507 else { | |
508 int i; | |
509 RgnHandle dirty = NewRgn (); | |
510 RgnHandle temp = NewRgn (); | |
511 | |
512 SetEmptyRgn (dirty); | |
513 | |
514 /* Build the region of dirty rectangles */ | |
515 for (i = 0; i < numRects; i++) { | |
516 | |
517 MacSetRectRgn (temp, rects[i].x, rects[i].y, | |
518 rects[i].x + rects[i].w, rects[i].y + rects[i].h); | |
519 MacUnionRgn (dirty, temp, dirty); | |
520 } | |
521 | |
522 /* Flush the dirty region */ | |
523 QDFlushPortBuffer ( [ windowView qdPort ], dirty ); | |
524 DisposeRgn (dirty); | |
525 DisposeRgn (temp); | |
526 } | |
527 } | |
528 | |
529 static void QZ_VideoQuit (_THIS) { | |
530 | |
531 QZ_UnsetVideoMode (this); | |
532 CGPaletteRelease (palette); | |
533 } | |
534 | |
535 static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) { | |
536 | |
537 CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color); | |
538 return 0; | |
539 } | |
540 | |
541 static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { | |
542 | |
543 return 1; | |
544 } | |
545 | |
546 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) { | |
547 } | |
548 | |
549 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) { | |
550 } | |
551 | |
552 /* | |
553 int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) { | |
554 return 0; | |
555 } | |
556 */ | |
557 | |
558 /* Gamma functions */ | |
559 static int QZ_SetGamma (_THIS, float red, float green, float blue) { | |
560 | |
561 const CGGammaValue min = 0.0, max = 1.0; | |
562 | |
563 if ( CGDisplayNoErr != CGSetDisplayTransferByFormula | |
564 (display_id, min, max, red, min, max, green, min, max, blue) ) | |
565 return -1; | |
566 | |
567 return 0; | |
568 } | |
569 | |
570 static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) { | |
571 | |
572 CGGammaValue dummy; | |
573 if ( CGDisplayNoErr != CGGetDisplayTransferByFormula | |
574 (display_id, &dummy, &dummy, red, | |
575 &dummy, &dummy, green, &dummy, &dummy, blue) ) | |
576 | |
577 return -1; | |
578 | |
579 return 0; | |
580 } | |
581 | |
582 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) { | |
583 | |
584 const CGTableCount tableSize = 255; | |
585 CGGammaValue redTable[tableSize]; | |
586 CGGammaValue greenTable[tableSize]; | |
587 CGGammaValue blueTable[tableSize]; | |
588 | |
589 int i; | |
590 | |
591 /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */ | |
592 for (i = 0; i < 256; i++) | |
593 redTable[i % 256] = ramp[i] / 65535.0; | |
594 | |
595 for (i=256; i < 512; i++) | |
596 greenTable[i % 256] = ramp[i] / 65535.0; | |
597 | |
598 for (i=512; i < 768; i++) | |
599 blueTable[i % 256] = ramp[i] / 65535.0; | |
600 | |
601 if ( CGDisplayNoErr != CGSetDisplayTransferByTable | |
602 (display_id, tableSize, redTable, greenTable, blueTable) ) | |
603 return -1; | |
604 | |
605 return 0; | |
606 } | |
607 | |
608 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) { | |
609 | |
610 const CGTableCount tableSize = 255; | |
611 CGGammaValue redTable[tableSize]; | |
612 CGGammaValue greenTable[tableSize]; | |
613 CGGammaValue blueTable[tableSize]; | |
614 CGTableCount actual; | |
615 int i; | |
616 | |
617 if ( CGDisplayNoErr != CGGetDisplayTransferByTable | |
618 (display_id, tableSize, redTable, greenTable, blueTable, &actual) || | |
619 actual != tableSize) | |
620 | |
621 return -1; | |
622 | |
623 /* Pack tables into one array, with values from 0 to 65535 */ | |
624 for (i = 0; i < 256; i++) | |
625 ramp[i] = redTable[i % 256] * 65535.0; | |
626 | |
627 for (i=256; i < 512; i++) | |
628 ramp[i] = greenTable[i % 256] * 65535.0; | |
629 | |
630 for (i=512; i < 768; i++) | |
631 ramp[i] = blueTable[i % 256] * 65535.0; | |
632 | |
633 return 0; | |
634 } | |
635 | |
636 /* OpenGL helper functions */ | |
637 static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { | |
638 | |
639 NSOpenGLPixelFormatAttribute attr[32]; | |
640 NSOpenGLPixelFormat *fmt; | |
641 int i = 0; | |
642 int colorBits = bpp; | |
643 | |
644 if ( flags & SDL_FULLSCREEN ) { | |
645 | |
646 attr[i++] = NSOpenGLPFAFullScreen; | |
647 } | |
648 /* In windowed mode, the OpenGL pixel depth must match device pixel depth */ | |
649 else if ( colorBits != device_bpp ) { | |
650 | |
651 colorBits = device_bpp; | |
652 } | |
653 | |
654 attr[i++] = NSOpenGLPFAColorSize; | |
655 attr[i++] = colorBits; | |
656 | |
657 attr[i++] = NSOpenGLPFADepthSize; | |
658 attr[i++] = this->gl_config.depth_size; | |
659 | |
660 if ( this->gl_config.double_buffer ) { | |
661 attr[i++] = NSOpenGLPFADoubleBuffer; | |
662 } | |
663 | |
664 if ( this->gl_config.stencil_size != 0 ) { | |
665 attr[i++] = NSOpenGLPFAStencilSize; | |
666 attr[i++] = this->gl_config.stencil_size; | |
667 } | |
668 | |
669 attr[i++] = NSOpenGLPFAScreenMask; | |
670 attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id); | |
671 attr[i] = 0; | |
672 | |
673 fmt = [ [ NSOpenGLPixelFormat alloc ] initWithAttributes:attr ]; | |
674 if (fmt == nil) { | |
675 SDL_SetError ("Failed creating OpenGL pixel format"); | |
676 return 0; | |
677 } | |
678 | |
679 gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt | |
680 shareContext:nil]; | |
681 | |
682 if (gl_context == nil) { | |
683 SDL_SetError ("Failed creating OpenGL context"); | |
684 return 0; | |
685 } | |
686 | |
687 /* Convince SDL that the GL "driver" is loaded */ | |
688 this->gl_config.driver_loaded = 1; | |
689 | |
690 [ fmt release ]; | |
691 | |
692 return 1; | |
693 } | |
694 | |
695 static void QZ_TearDownOpenGL (_THIS) { | |
696 | |
697 [ NSOpenGLContext clearCurrentContext ]; | |
698 [ gl_context clearDrawable ]; | |
699 [ gl_context release ]; | |
700 } | |
701 | |
702 /* SDL OpenGL functions */ | |
703 | |
704 static int QZ_GL_LoadLibrary (_THIS, const char *location) { | |
705 return 1; | |
706 } | |
707 | |
708 static void* QZ_GL_GetProcAddress (_THIS, const char *proc) { | |
709 | |
710 /* We may want to cache the bundleRef at some point */ | |
711 CFBundleRef bundle; | |
712 CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, | |
713 CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); | |
714 | |
715 CFStringRef functionName = CFStringCreateWithCString | |
716 (kCFAllocatorDefault, proc, kCFStringEncodingASCII); | |
717 | |
718 void *function; | |
719 | |
720 bundle = CFBundleCreate (kCFAllocatorDefault, bundleURL); | |
721 assert (bundle != NULL); | |
722 | |
723 function = CFBundleGetFunctionPointerForName (bundle, functionName); | |
724 | |
725 CFRelease ( bundleURL ); | |
726 CFRelease ( functionName ); | |
727 CFRelease ( bundle ); | |
728 | |
729 return function; | |
730 } | |
731 | |
732 static int QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int* value) { | |
733 | |
734 /* | |
735 CGLContextRef ctx = [ gl_context cglContext ]; | |
736 CGLContextParameter param; | |
737 | |
738 switch (attrib) { | |
739 case SDL_GL_RED_SIZE: param = CGLContextParameter break; | |
740 | |
741 } | |
742 | |
743 CGLGetParameter (ctx, param, (long*)value); | |
744 */ | |
745 *value = -1; | |
746 return -1; | |
747 } | |
748 | |
749 static int QZ_GL_MakeCurrent (_THIS) { | |
750 [ gl_context makeCurrentContext ]; | |
751 return 0; | |
752 } | |
753 | |
754 static void QZ_GL_SwapBuffers (_THIS) { | |
755 [ gl_context flushBuffer ]; | |
756 } |