Mercurial > sdl-ios-xcode
diff src/video/quartz/SDL_QuartzVideo.m @ 390:19e73568a75c
Date: Sat, 1 Jun 2002 17:56:45 -0500
From: Darrell Walisser <dwaliss1@purdue.edu>
Subject: mac patch
In this patch:
- yuv code
- links to QuickTime
- tabs -> 4 spaces
- mouse events fix
- SDLMain path parsing fix
- BUGS updates
- some miscellaneous docs/comments/code cleanup
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 01 Jun 2002 23:05:05 +0000 |
parents | f0e5198a1522 |
children | 140798e1e7a6 |
line wrap: on
line diff
--- a/src/video/quartz/SDL_QuartzVideo.m Sat Jun 01 19:54:15 2002 +0000 +++ b/src/video/quartz/SDL_QuartzVideo.m Sat Jun 01 23:05:05 2002 +0000 @@ -32,7 +32,6 @@ #include "SDL_QuartzEvents.m" #include "SDL_QuartzWindow.m" - /* Bootstrap binding, enables entry point into the driver */ VideoBootStrap QZ_bootstrap = { "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice @@ -100,7 +99,9 @@ /*device->GetWMInfo = QZ_GetWMInfo;*/ device->GrabInput = QZ_GrabInput; - device->free = QZ_DeleteDevice; + device->CreateYUVOverlay = QZ_CreateYUVOverlay; + + device->free = QZ_DeleteDevice; return device; } @@ -135,106 +136,106 @@ } static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { - + CFIndex num_modes; CFIndex i; static SDL_Rect **list = NULL; int list_size = 0; - + /* Any windowed mode is acceptable */ if ( (flags & SDL_FULLSCREEN) == 0 ) return (SDL_Rect**)-1; - + /* Free memory from previous call, if any */ if ( list != NULL ) { - int i; + int i; - for (i = 0; list[i] != NULL; i++) - free (list[i]); + for (i = 0; list[i] != NULL; i++) + free (list[i]); - free (list); - list = NULL; + free (list); + list = NULL; } - + num_modes = CFArrayGetCount (mode_list); /* Build list of modes with the requested bpp */ for (i = 0; i < num_modes; i++) { - + CFDictionaryRef onemode; CFNumberRef number; - int bpp; - - onemode = CFArrayGetValueAtIndex (mode_list, i); - number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel); - CFNumberGetValue (number, kCFNumberSInt32Type, &bpp); + int bpp; + + onemode = CFArrayGetValueAtIndex (mode_list, i); + number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel); + CFNumberGetValue (number, kCFNumberSInt32Type, &bpp); + + if (bpp == format->BitsPerPixel) { + + int intvalue; + int hasMode; + int width, height; - if (bpp == format->BitsPerPixel) { - - int intvalue; - int hasMode; - int width, height; - - number = CFDictionaryGetValue (onemode, kCGDisplayWidth); - CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); - width = (Uint16) intvalue; - - number = CFDictionaryGetValue (onemode, kCGDisplayHeight); - CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); - height = (Uint16) intvalue; - - /* Check if mode is already in the list */ - { - int i; - hasMode = SDL_FALSE; - for (i = 0; i < list_size; i++) { - if (list[i]->w == width && list[i]->h == height) { - hasMode = SDL_TRUE; - break; + number = CFDictionaryGetValue (onemode, kCGDisplayWidth); + CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); + width = (Uint16) intvalue; + + number = CFDictionaryGetValue (onemode, kCGDisplayHeight); + CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue); + height = (Uint16) intvalue; + + /* Check if mode is already in the list */ + { + int i; + hasMode = SDL_FALSE; + for (i = 0; i < list_size; i++) { + if (list[i]->w == width && list[i]->h == height) { + hasMode = SDL_TRUE; + break; + } } } - } - - /* Grow the list and add mode to the list */ - if ( ! hasMode ) { - - SDL_Rect *rect; - - list_size++; + + /* Grow the list and add mode to the list */ + if ( ! hasMode ) { + + SDL_Rect *rect; + + list_size++; + + if (list == NULL) + list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) ); + else + list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1)); + + rect = (SDL_Rect*) malloc (sizeof(**list)); - if (list == NULL) - list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) ); - else - list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1)); - - rect = (SDL_Rect*) malloc (sizeof(**list)); - - if (list == NULL || rect == NULL) { - SDL_OutOfMemory (); - return NULL; + if (list == NULL || rect == NULL) { + SDL_OutOfMemory (); + return NULL; + } + + rect->w = width; + rect->h = height; + + list[list_size-1] = rect; + list[list_size] = NULL; } - - rect->w = width; - rect->h = height; - - list[list_size-1] = rect; - list[list_size] = NULL; } - } } - + /* Sort list largest to smallest (by area) */ { int i, j; for (i = 0; i < list_size; i++) { for (j = 0; j < list_size-1; j++) { - + int area1, area2; area1 = list[j]->w * list[j]->h; area2 = list[j+1]->w * list[j+1]->h; - + if (area1 < area2) { SDL_Rect *tmp = list[j]; list[j] = list[j+1]; @@ -299,8 +300,8 @@ static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) { CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], - greenTable[QZ_GAMMA_TABLE_SIZE], - blueTable[QZ_GAMMA_TABLE_SIZE]; + greenTable[QZ_GAMMA_TABLE_SIZE], + blueTable[QZ_GAMMA_TABLE_SIZE]; float percent; int j; @@ -308,7 +309,7 @@ memset (redTable, 0, sizeof(redTable)); memset (greenTable, 0, sizeof(greenTable)); memset (blueTable, 0, sizeof(greenTable)); - + for (percent = 0.0; percent <= 1.0; percent += 0.01) { for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { @@ -338,7 +339,7 @@ this->info.blit_fill = 0; this->FillHWRect = NULL; this->UpdateRects = NULL; - + /* Release fullscreen resources */ if ( mode_flags & SDL_FULLSCREEN ) { @@ -351,7 +352,7 @@ /* Do this first to avoid trash on the display before fade */ if ( mode_flags & SDL_OPENGL ) QZ_TearDownOpenGL (this); - + if (mode_flags & SDL_OPENGL) CGLSetFullScreen(NULL); @@ -359,12 +360,12 @@ CGDisplaySwitchToMode (display_id, save_mode); CGDisplayRelease (display_id); ShowMenuBar (); - + if (! gamma_error) QZ_FadeGammaIn (this, &gamma_table); } /* Release window mode resources */ - else { + else { if ( (mode_flags & SDL_OPENGL) == 0 ) { UnlockPortBits ( [ window_view qdPort ] ); [ window_view release ]; @@ -373,7 +374,7 @@ [ qz_window setDelegate:nil ]; [ qz_window close ]; [ qz_window release ]; - qz_window = nil; + qz_window = nil; /* Release the OpenGL context */ if ( mode_flags & SDL_OPENGL ) @@ -382,15 +383,15 @@ /* Restore gamma settings */ CGDisplayRestoreColorSyncSettings (); - + /* Set pixels to null (so other code doesn't try to free it) */ if (this->screen != NULL) this->screen->pixels = NULL; - + /* Ensure the cursor will be visible and working when we quit */ CGDisplayShowCursor (display_id); CGAssociateMouseAndMouseCursorPosition (1); - + /* Signal successful teardown */ video_set = SDL_FALSE; } @@ -400,11 +401,11 @@ int exact_match; int gamma_error; SDL_QuartzGammaTable gamma_table; - + /* See if requested mode exists */ - mode = CGDisplayBestModeForParameters (display_id, bpp, width, - height, &exact_match); - + mode = CGDisplayBestModeForParameters (display_id, bpp, width, + height, &exact_match); + /* Require an exact match to the requested mode */ if ( ! exact_match ) { sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp); @@ -421,7 +422,7 @@ goto ERR_NO_CAPTURE; } - + /* Do the physical switch */ if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { SDL_SetError ("Failed switching display resolution"); @@ -434,45 +435,45 @@ current->flags = 0; current->w = width; current->h = height; - current->flags |= SDL_FULLSCREEN; + current->flags |= SDL_FULLSCREEN; current->flags |= SDL_HWSURFACE; - + this->UpdateRects = QZ_DirectUpdate; - + /* Setup some mode-dependant info */ if ( CGSDisplayCanHWFill (display_id) ) { - this->info.blit_fill = 1; - this->FillHWRect = QZ_FillHWRect; + this->info.blit_fill = 1; + this->FillHWRect = QZ_FillHWRect; } - + if ( CGDisplayCanSetPalette (display_id) ) current->flags |= SDL_HWPALETTE; - + /* Setup OpenGL for a fullscreen context */ if (flags & SDL_OPENGL) { CGLError err; CGLContextObj ctx; - + if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { goto ERR_NO_GL; } - + ctx = [ gl_context cglContext ]; err = CGLSetFullScreen (ctx); - + if (err) { sprintf (QZ_Error, "Error setting OpenGL fullscreen: %s", CGLErrorString(err)); SDL_SetError (QZ_Error); goto ERR_NO_GL; } - + [ gl_context makeCurrentContext]; glClear (GL_COLOR_BUFFER_BIT); [ gl_context flushBuffer ]; - + current->flags |= SDL_OPENGL; } @@ -482,23 +483,23 @@ /* Fade the display to original gamma */ if (! gamma_error ) QZ_FadeGammaIn (this, &gamma_table); - + /* Save the flags to ensure correct tear-down */ mode_flags = current->flags; - + return current; - /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ - ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); - ERR_NO_SWITCH: CGDisplayRelease (display_id); - ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); } - ERR_NO_MATCH: return NULL; + /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ +ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); +ERR_NO_SWITCH: CGDisplayRelease (display_id); +ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); } +ERR_NO_MATCH: return NULL; } static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, - int height, int bpp, Uint32 flags) { + int height, int bpp, Uint32 flags) { unsigned int style; - NSRect rect; + NSRect rect; rect = NSMakeRect (0, 0, width, height); #if 1 // FIXME - the resize button doesn't show? Also need resize events... @@ -515,17 +516,17 @@ } /* Manually create a window, avoids having a nib file resource */ - qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect - styleMask:style backing:NSBackingStoreBuffered defer:NO ]; + qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect + styleMask:style backing:NSBackingStoreBuffered defer:NO ]; if (qz_window == nil) { SDL_SetError ("Could not create the Cocoa window"); return NULL; } - + current->flags = 0; current->w = width; current->h = height; - + [ qz_window setReleasedWhenClosed:YES ]; QZ_SetCaption(this, this->wm_title, this->wm_icon); [ qz_window setAcceptsMouseMovedEvents:YES ]; @@ -533,14 +534,14 @@ [ qz_window center ]; [ qz_window setDelegate: [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; - + /* For OpenGL, we set the content view to a NSOpenGLView */ if ( flags & SDL_OPENGL ) { - + if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { return NULL; } - + [ gl_context setView: [ qz_window contentView ] ]; [ gl_context makeCurrentContext]; [ qz_window makeKeyAndOrderFront:nil ]; @@ -548,45 +549,45 @@ } /* For 2D, we set the content view to a NSQuickDrawView */ else { - + window_view = [ [ SDL_QuartzWindowView alloc ] init ]; [ qz_window setContentView:window_view ]; - [ qz_window makeKeyAndOrderFront:nil ]; - + [ qz_window makeKeyAndOrderFront:nil ]; + LockPortBits ( [ window_view qdPort ] ); current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) ); current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) ); - + current->flags |= SDL_SWSURFACE; current->flags |= SDL_PREALLOC; - - if ( flags & SDL_NOFRAME ) - current->flags |= SDL_NOFRAME; - if ( flags & SDL_RESIZABLE ) - current->flags |= SDL_RESIZABLE; + + if ( flags & SDL_NOFRAME ) + current->flags |= SDL_NOFRAME; + if ( flags & SDL_RESIZABLE ) + current->flags |= SDL_RESIZABLE; /* Offset 22 pixels down to fill the full content region */ - if ( ! (current->flags & SDL_NOFRAME) ) { - current->pixels += 22 * current->pitch; - } + if ( ! (current->flags & SDL_NOFRAME) ) { + current->pixels += 22 * current->pitch; + } this->UpdateRects = QZ_UpdateRects; } - + /* Save flags to ensure correct teardown */ mode_flags = current->flags; - + return current; } -static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, - int height, int bpp, Uint32 flags) { +static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, + int height, int bpp, Uint32 flags) { if (video_set == SDL_TRUE) QZ_UnsetVideoMode (this); - + current->flags = 0; - + /* Setup full screen video */ if ( flags & SDL_FULLSCREEN ) { current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags ); @@ -601,17 +602,17 @@ if (current == NULL) return NULL; } - + /* Setup the new pixel format */ { - int amask = 0, - rmask = 0, - gmask = 0, - bmask = 0; - + int amask = 0, + rmask = 0, + gmask = 0, + bmask = 0; + switch (bpp) { case 16: /* (1)-5-5-5 RGB */ - amask = 0; + amask = 0; rmask = 0x7C00; gmask = 0x03E0; bmask = 0x001F; @@ -626,212 +627,212 @@ bmask = 0x000000FF; break; } - + if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, amask ) ) { - SDL_SetError ("Couldn't reallocate pixel format"); - return NULL; - } + SDL_SetError ("Couldn't reallocate pixel format"); + return NULL; + } } - + /* Signal successful completion (used internally) */ video_set = SDL_TRUE; - + return current; } -static int QZ_ToggleFullScreen (_THIS, int on) { +static int QZ_ToggleFullScreen (_THIS, int on) { return -1; } -static int QZ_SetColors (_THIS, int first_color, int num_colors, - SDL_Color *colors) { +static int QZ_SetColors (_THIS, int first_color, int num_colors, + SDL_Color *colors) { CGTableCount index; CGDeviceColor color; - + for (index = first_color; index < first_color+num_colors; index++) { - + /* Clamp colors between 0.0 and 1.0 */ color.red = colors->r / 255.0; color.blue = colors->b / 255.0; color.green = colors->g / 255.0; - + colors++; - + CGPaletteSetColorAtIndex (palette, color, index); } - + if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) ) return 0; - + return 1; } static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { - #pragma unused(this,num_rects,rects) +#pragma unused(this,num_rects,rects) } -/** +/** * The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com, * who supplied sample code for Carbon. **/ static int QZ_IsWindowObscured (NSWindow *window) { -//#define TEST_OBSCURED 1 + //#define TEST_OBSCURED 1 #if TEST_OBSCURED - + /* In order to determine if a direct copy to the screen is possible, - we must figure out if there are any windows covering ours (including shadows). - This can be done by querying the window server about the on screen - windows for their screen rectangle and window level. - The procedure used below is puts accuracy before speed; however, it aims to call - the window server the fewest number of times possible to keep things reasonable. - In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW + we must figure out if there are any windows covering ours (including shadows). + This can be done by querying the window server about the on screen + windows for their screen rectangle and window level. + The procedure used below is puts accuracy before speed; however, it aims to call + the window server the fewest number of times possible to keep things reasonable. + In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW - Notes: - -Calls into the Window Server involve IPC which is slow. - -Getting a rectangle seems slower than getting the window level - -The window list we get back is in sorted order, top to bottom - -On average, I suspect, most windows above ours are dock icon windows (hence optimization) - -Some windows above ours are always there, and cannot move or obscure us (menu bar) - - Bugs: - -no way (yet) to deactivate direct drawing when a window is dragged, - or suddenly obscured, so drawing continues and can produce garbage - We need some kind of locking mechanism on window movement to prevent this - - -deactivated normal windows use activated normal - window shadows (slight inaccuraccy) + Notes: + -Calls into the Window Server involve IPC which is slow. + -Getting a rectangle seems slower than getting the window level + -The window list we get back is in sorted order, top to bottom + -On average, I suspect, most windows above ours are dock icon windows (hence optimization) + -Some windows above ours are always there, and cannot move or obscure us (menu bar) + + Bugs: + -no way (yet) to deactivate direct drawing when a window is dragged, + or suddenly obscured, so drawing continues and can produce garbage + We need some kind of locking mechanism on window movement to prevent this + + -deactivated normal windows use activated normal + window shadows (slight inaccuraccy) */ - + /* Cache the connection to the window server */ - static CGSConnectionID cgsConnection = (CGSConnectionID) -1; - + static CGSConnectionID cgsConnection = (CGSConnectionID) -1; + /* Cache the dock icon windows */ static CGSWindowID dockIcons[kMaxWindows]; static int numCachedDockIcons = 0; - - CGSWindowID windows[kMaxWindows]; - CGSWindowCount i, count; - CGSWindowLevel winLevel; - CGSRect winRect; + + CGSWindowID windows[kMaxWindows]; + CGSWindowCount i, count; + CGSWindowLevel winLevel; + CGSRect winRect; CGSRect contentRect; int windowNumber; //int isMainWindow; - int firstDockIcon; + int firstDockIcon; int dockIconCacheMiss; int windowContentOffset; - + int obscured = SDL_TRUE; - + if ( [ window isVisible ] ) { - - /* walk the window list looking for windows over top of - (or casting a shadow on) ours */ - + + /* walk the window list looking for windows over top of + (or casting a shadow on) ours */ + /* Get a connection to the window server */ /* Should probably be moved out into SetVideoMode() or InitVideo() */ if (cgsConnection == (CGSConnectionID) -1) { cgsConnection = (CGSConnectionID) 0; cgsConnection = _CGSDefaultConnection (); } - - if (cgsConnection) { - + + if (cgsConnection) { + if ( ! [ window styleMask ] & NSBorderlessWindowMask ) windowContentOffset = 22; else windowContentOffset = 0; - + windowNumber = [ window windowNumber ]; //isMainWindow = [ window isMainWindow ]; - + /* The window list is sorted according to order on the screen */ count = 0; CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count); CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect); - + /* adjust rect for window title bar (if present) */ contentRect.origin.y += windowContentOffset; contentRect.size.height -= windowContentOffset; - + firstDockIcon = -1; dockIconCacheMiss = SDL_FALSE; - - /* The first window is always an empty window with level kCGSWindowLevelTop - so start at index 1 */ + + /* The first window is always an empty window with level kCGSWindowLevelTop + so start at index 1 */ for (i = 1; i < count; i++) { - + /* If we reach our window in the list, it cannot be obscured */ if (windows[i] == windowNumber) { - + obscured = SDL_FALSE; break; } else { - + float shadowSide; float shadowTop; float shadowBottom; CGSGetWindowLevel (cgsConnection, windows[i], &winLevel); - + if (winLevel == kCGSWindowLevelDockIcon) { - + int j; - + if (firstDockIcon < 0) { - + firstDockIcon = i; - + if (numCachedDockIcons > 0) { - + for (j = 0; j < numCachedDockIcons; j++) { - + if (windows[i] == dockIcons[j]) i++; else break; } - + if (j != 0) { - + i--; - + if (j < numCachedDockIcons) { - + dockIconCacheMiss = SDL_TRUE; } } } } - + continue; } else if (winLevel == kCGSWindowLevelMenuIgnore /* winLevel == kCGSWindowLevelTop */) { - + continue; /* cannot obscure window */ } else if (winLevel == kCGSWindowLevelDockMenu || winLevel == kCGSWindowLevelMenu) { - + shadowSide = 18; shadowTop = 4; - shadowBottom = 22; + shadowBottom = 22; } else if (winLevel == kCGSWindowLevelUtility) { - + shadowSide = 8; shadowTop = 4; shadowBottom = 12; } else if (winLevel == kCGSWindowLevelNormal) { - + /* These numbers are for foreground windows, they are too big (but will work) for background windows */ shadowSide = 20; @@ -839,52 +840,52 @@ shadowBottom = 24; } else if (winLevel == kCGSWindowLevelDock) { - + /* Create dock icon cache */ if (numCachedDockIcons != (i-firstDockIcon) || dockIconCacheMiss) { - + numCachedDockIcons = i - firstDockIcon; - memcpy (dockIcons, &(windows[firstDockIcon]), + memcpy (dockIcons, &(windows[firstDockIcon]), numCachedDockIcons * sizeof(*windows)); } - + /* no shadow */ shadowSide = 0; shadowTop = 0; shadowBottom = 0; } else { - + /* kCGSWindowLevelDockLabel, - kCGSWindowLevelDock, - kOther??? */ - + kCGSWindowLevelDock, + kOther??? */ + /* no shadow */ shadowSide = 0; shadowTop = 0; shadowBottom = 0; } - + CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect); - + winRect.origin.x -= shadowSide; winRect.origin.y -= shadowTop; winRect.size.width += shadowSide; winRect.size.height += shadowBottom; - + if (NSIntersectsRect (contentRect, winRect)) { - + obscured = SDL_TRUE; break; } - - } /* window was not our window */ - + + } /* window was not our window */ + } /* iterate over windows */ - + } /* get cgsConnection */ - + } /* window is visible */ return obscured; @@ -893,86 +894,86 @@ #endif } -static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { +static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { QZ_GL_SwapBuffers (this); } - else if ( [ qz_window isMiniaturized ] && + else if ( [ qz_window isMiniaturized ] && ! (SDL_VideoSurface->flags & SDL_OPENGL)) { - - /** + + /** * Set port alpha opaque so deminiaturize looks right - * This isn't so nice, but there is no + * This isn't so nice, but there is no * initial deminatureize notification (before demini starts) **/ QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort], - [ qz_window styleMask ] & NSBorderlessWindowMask); + [ qz_window styleMask ] & NSBorderlessWindowMask); } else if ( ! QZ_IsWindowObscured (qz_window) ) { - + /* Use direct copy to flush contents to the display */ CGrafPtr savePort; CGrafPtr dstPort, srcPort; const BitMap *dstBits, *srcBits; - Rect dstRect, srcRect; + Rect dstRect, srcRect; Point offset; int i; - + GetPort (&savePort); - + dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id); srcPort = [ window_view qdPort ]; - + offset.h = 0; offset.v = 0; SetPort (srcPort); LocalToGlobal (&offset); - + SetPort (dstPort); - + LockPortBits (dstPort); LockPortBits (srcPort); - + dstBits = GetPortBitMapForCopyBits (dstPort); srcBits = GetPortBitMapForCopyBits (srcPort); - + for (i = 0; i < numRects; i++) { - + SetRect (&srcRect, rects[i].x, rects[i].y, rects[i].x + rects[i].w, rects[i].y + rects[i].h); - + SetRect (&dstRect, - rects[i].x + offset.h, + rects[i].x + offset.h, rects[i].y + offset.v, rects[i].x + rects[i].w + offset.h, rects[i].y + rects[i].h + offset.v); - + CopyBits (srcBits, dstBits, &srcRect, &dstRect, srcCopy, NULL); - + } - + SetPort (savePort); } else { - + /* Use QDFlushPortBuffer() to flush content to display */ int i; RgnHandle dirty = NewRgn (); RgnHandle temp = NewRgn (); - + SetEmptyRgn (dirty); - + /* Build the region of dirty rectangles */ for (i = 0; i < numRects; i++) { - - MacSetRectRgn (temp, rects[i].x, rects[i].y, - rects[i].x + rects[i].w, rects[i].y + rects[i].h); + + MacSetRectRgn (temp, rects[i].x, rects[i].y, + rects[i].x + rects[i].w, rects[i].y + rects[i].h); MacUnionRgn (dirty, temp, dirty); } - + /* Flush the dirty region */ QDFlushPortBuffer ( [ window_view qdPort ], dirty ); DisposeRgn (dirty); @@ -993,7 +994,7 @@ return 0; } -static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { +static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { return 1; } @@ -1006,10 +1007,10 @@ } /* -int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) { - return 0; -} -*/ + int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) { + return 0; + } + */ /* Gamma functions */ static int QZ_SetGamma (_THIS, float red, float green, float blue) { @@ -1030,14 +1031,14 @@ blue = FLT_MAX; else blue = 1.0 / blue; - - if ( CGDisplayNoErr == CGSetDisplayTransferByFormula - (display_id, min, max, red, min, max, green, min, max, blue) ) { - + + if ( CGDisplayNoErr == CGSetDisplayTransferByFormula + (display_id, min, max, red, min, max, green, min, max, blue) ) { + return 0; } else { - + return -1; } } @@ -1046,66 +1047,66 @@ CGGammaValue dummy; if ( CGDisplayNoErr == CGGetDisplayTransferByFormula - (display_id, &dummy, &dummy, red, - &dummy, &dummy, green, &dummy, &dummy, blue) ) - + (display_id, &dummy, &dummy, red, + &dummy, &dummy, green, &dummy, &dummy, blue) ) + return 0; else return -1; } static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) { - - const CGTableCount tableSize = 255; - CGGammaValue redTable[tableSize]; - CGGammaValue greenTable[tableSize]; - CGGammaValue blueTable[tableSize]; - - int i; - - /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */ - for (i = 0; i < 256; i++) - redTable[i % 256] = ramp[i] / 65535.0; - - for (i=256; i < 512; i++) - greenTable[i % 256] = ramp[i] / 65535.0; - - for (i=512; i < 768; i++) - blueTable[i % 256] = ramp[i] / 65535.0; - - if ( CGDisplayNoErr == CGSetDisplayTransferByTable - (display_id, tableSize, redTable, greenTable, blueTable) ) + + const CGTableCount tableSize = 255; + CGGammaValue redTable[tableSize]; + CGGammaValue greenTable[tableSize]; + CGGammaValue blueTable[tableSize]; + + int i; + + /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */ + for (i = 0; i < 256; i++) + redTable[i % 256] = ramp[i] / 65535.0; + + for (i=256; i < 512; i++) + greenTable[i % 256] = ramp[i] / 65535.0; + + for (i=512; i < 768; i++) + blueTable[i % 256] = ramp[i] / 65535.0; + + if ( CGDisplayNoErr == CGSetDisplayTransferByTable + (display_id, tableSize, redTable, greenTable, blueTable) ) return 0; else return -1; } static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) { - + const CGTableCount tableSize = 255; CGGammaValue redTable[tableSize]; CGGammaValue greenTable[tableSize]; CGGammaValue blueTable[tableSize]; CGTableCount actual; int i; - - if ( CGDisplayNoErr != CGGetDisplayTransferByTable - (display_id, tableSize, redTable, greenTable, blueTable, &actual) || - actual != tableSize) - + + if ( CGDisplayNoErr != CGGetDisplayTransferByTable + (display_id, tableSize, redTable, greenTable, blueTable, &actual) || + actual != tableSize) + return -1; - + /* Pack tables into one array, with values from 0 to 65535 */ for (i = 0; i < 256; i++) ramp[i] = redTable[i % 256] * 65535.0; - + for (i=256; i < 512; i++) ramp[i] = greenTable[i % 256] * 65535.0; - + for (i=512; i < 768; i++) ramp[i] = blueTable[i % 256] * 65535.0; - - return 0; + + return 0; } /* OpenGL helper functions (used internally) */ @@ -1118,53 +1119,53 @@ int colorBits = bpp; if ( flags & SDL_FULLSCREEN ) { - + attr[i++] = NSOpenGLPFAFullScreen; } /* In windowed mode, the OpenGL pixel depth must match device pixel depth */ - else if ( colorBits != device_bpp ) { + else if ( colorBits != device_bpp ) { colorBits = device_bpp; } - + attr[i++] = NSOpenGLPFAColorSize; attr[i++] = colorBits; - + attr[i++] = NSOpenGLPFADepthSize; attr[i++] = this->gl_config.depth_size; if ( this->gl_config.double_buffer ) { attr[i++] = NSOpenGLPFADoubleBuffer; } - + if ( this->gl_config.stencil_size != 0 ) { attr[i++] = NSOpenGLPFAStencilSize; attr[i++] = this->gl_config.stencil_size; } - + attr[i++] = NSOpenGLPFAScreenMask; attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id); attr[i] = 0; - + fmt = [ [ NSOpenGLPixelFormat alloc ] initWithAttributes:attr ]; if (fmt == nil) { SDL_SetError ("Failed creating OpenGL pixel format"); return 0; } - - gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt - shareContext:nil]; - + + gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt + shareContext:nil]; + if (gl_context == nil) { SDL_SetError ("Failed creating OpenGL context"); return 0; - } - + } + /* Convince SDL that the GL "driver" is loaded */ this->gl_config.driver_loaded = 1; - + [ fmt release ]; - + return 1; } @@ -1187,23 +1188,23 @@ /* We may want to cache the bundleRef at some point */ CFBundleRef bundle; - CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, - CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); - - CFStringRef functionName = CFStringCreateWithCString + CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, + CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); + + CFStringRef functionName = CFStringCreateWithCString (kCFAllocatorDefault, proc, kCFStringEncodingASCII); - + void *function; - + bundle = CFBundleCreate (kCFAllocatorDefault, bundleURL); assert (bundle != NULL); - + function = CFBundleGetFunctionPointerForName (bundle, functionName); CFRelease ( bundleURL ); CFRelease ( functionName ); CFRelease ( bundle ); - + return function; } @@ -1214,18 +1215,18 @@ QZ_GL_MakeCurrent (this); switch (attrib) { - case SDL_GL_RED_SIZE: attr = GL_RED_BITS; break; - case SDL_GL_BLUE_SIZE: attr = GL_BLUE_BITS; break; - case SDL_GL_GREEN_SIZE: attr = GL_GREEN_BITS; break; - case SDL_GL_ALPHA_SIZE: attr = GL_ALPHA_BITS; break; - case SDL_GL_DOUBLEBUFFER: attr = GL_DOUBLEBUFFER; break; - case SDL_GL_DEPTH_SIZE: attr = GL_DEPTH_BITS; break; - case SDL_GL_STENCIL_SIZE: attr = GL_STENCIL_BITS; break; - case SDL_GL_ACCUM_RED_SIZE: attr = GL_ACCUM_RED_BITS; break; - case SDL_GL_ACCUM_GREEN_SIZE: attr = GL_ACCUM_GREEN_BITS; break; - case SDL_GL_ACCUM_BLUE_SIZE: attr = GL_ACCUM_BLUE_BITS; break; - case SDL_GL_ACCUM_ALPHA_SIZE: attr = GL_ACCUM_ALPHA_BITS; break; - case SDL_GL_BUFFER_SIZE: + case SDL_GL_RED_SIZE: attr = GL_RED_BITS; break; + case SDL_GL_BLUE_SIZE: attr = GL_BLUE_BITS; break; + case SDL_GL_GREEN_SIZE: attr = GL_GREEN_BITS; break; + case SDL_GL_ALPHA_SIZE: attr = GL_ALPHA_BITS; break; + case SDL_GL_DOUBLEBUFFER: attr = GL_DOUBLEBUFFER; break; + case SDL_GL_DEPTH_SIZE: attr = GL_DEPTH_BITS; break; + case SDL_GL_STENCIL_SIZE: attr = GL_STENCIL_BITS; break; + case SDL_GL_ACCUM_RED_SIZE: attr = GL_ACCUM_RED_BITS; break; + case SDL_GL_ACCUM_GREEN_SIZE: attr = GL_ACCUM_GREEN_BITS; break; + case SDL_GL_ACCUM_BLUE_SIZE: attr = GL_ACCUM_BLUE_BITS; break; + case SDL_GL_ACCUM_ALPHA_SIZE: attr = GL_ACCUM_ALPHA_BITS; break; + case SDL_GL_BUFFER_SIZE: { GLint bits = 0; GLint component; @@ -1254,4 +1255,298 @@ [ gl_context flushBuffer ]; } +static int QZ_LockYUV (_THIS, SDL_Overlay *overlay) { + return 0; +} + +static void QZ_UnlockYUV (_THIS, SDL_Overlay *overlay) { + + ; +} + +static int QZ_DisplayYUV (_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect) { + + OSErr err; + CodecFlags flags; + + if (dstrect->x != 0 || dstrect->y != 0) { + + SDL_SetError ("Need a dstrect at (0,0)"); + return -1; + } + + if (dstrect->w != yuv_width || dstrect->h != yuv_height) { + + Fixed scale_x, scale_y; + + scale_x = FixDiv ( Long2Fix (dstrect->w), Long2Fix (overlay->w) ); + scale_y = FixDiv ( Long2Fix (dstrect->h), Long2Fix (overlay->h) ); + + SetIdentityMatrix (yuv_matrix); + ScaleMatrix (yuv_matrix, scale_x, scale_y, Long2Fix (0), Long2Fix (0)); + + SetDSequenceMatrix (yuv_seq, yuv_matrix); + + yuv_width = dstrect->w; + yuv_height = dstrect->h; + } + + if( ( err = DecompressSequenceFrameS( + yuv_seq, + (void*)yuv_pixmap, + sizeof (PlanarPixmapInfoYUV420), + codecFlagUseImageBuffer, &flags, nil ) != noErr ) ) + { + SDL_SetError ("DecompressSequenceFrameS failed"); + } + + return err == noErr; +} + +static void QZ_FreeHWYUV (_THIS, SDL_Overlay *overlay) { + + CDSequenceEnd (yuv_seq); + ExitMovies(); + + free (overlay->hwfuncs); + free (overlay->pitches); + free (overlay->pixels); + + if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { + [ qz_window close ]; + qz_window = nil; + } + + free (yuv_matrix); + DisposeHandle ((Handle)yuv_idh); +} + +#include "SDL_yuvfuncs.h" + +/** + * check for 16 byte alignment, bail otherwise + **/ +#define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0) + +/** + * align a byte offset, return how much to add to make it + * a multiple of 16 + **/ +#define ALIGN(x) ((16 - (x & 15)) & 15) + +static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, + Uint32 format, SDL_Surface *display) { + + Uint32 codec; + OSStatus err; + CGrafPtr port; + SDL_Overlay *overlay; + + if (format == SDL_YV12_OVERLAY || + format == SDL_IYUV_OVERLAY) { + + codec = kYUV420CodecType; + } + else { + SDL_SetError ("Hardware: unsupported video format"); + return NULL; + } + + yuv_idh = (ImageDescriptionHandle) NewHandleClear (sizeof(ImageDescription)); + if (yuv_idh == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + yuv_matrix = (MatrixRecordPtr) malloc (sizeof(MatrixRecord)); + if (yuv_matrix == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + if ( EnterMovies() != noErr ) { + SDL_SetError ("Could not init QuickTime for YUV playback"); + return NULL; + } + + err = FindCodec (codec, bestSpeedCodec, nil, &yuv_codec); + if (err != noErr) { + SDL_SetError ("Could not find QuickTime codec for format"); + return NULL; + } + + if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { + + /** + * Good acceleration requires a window to be present. + * A CGrafPtr that points to the screen isn't good enough + **/ + NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); + + qz_window = [ [ SDL_QuartzWindow alloc ] + initWithContentRect:content + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered defer:NO ]; + + if (qz_window == nil) { + SDL_SetError ("Could not create the Cocoa window"); + return NULL; + } + + [ qz_window setContentView:[ [ SDL_QuartzWindowView alloc ] init ] ]; + [ qz_window setReleasedWhenClosed:YES ]; + [ qz_window center ]; + [ qz_window setAcceptsMouseMovedEvents:YES ]; + [ qz_window setLevel:CGShieldingWindowLevel() ]; + [ qz_window makeKeyAndOrderFront:nil ]; + + port = [ [ qz_window contentView ] qdPort ]; + SetPort (port); + // BUG: would like to remove white flash when window kicks in + //{ + // Rect r; + // SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); + // PaintRect (&r); + // QDFlushPortBuffer (port, nil); + //} + + } + else { + port = [ [ qz_window contentView ] qdPort ]; + SetPort (port); + } + + SetIdentityMatrix (yuv_matrix); + + HLock ((Handle)yuv_idh); + + (**yuv_idh).idSize = sizeof(ImageDescription); + (**yuv_idh).cType = codec; + (**yuv_idh).version = 1; + (**yuv_idh).revisionLevel = 0; + (**yuv_idh).width = width; + (**yuv_idh).height = height; + (**yuv_idh).hRes = Long2Fix(72); + (**yuv_idh).vRes = Long2Fix(72); + (**yuv_idh).spatialQuality = codecLosslessQuality; + (**yuv_idh).frameCount = 1; + (**yuv_idh).clutID = -1; + (**yuv_idh).dataSize = 0; + (**yuv_idh).depth = 12; + + HUnlock ((Handle)yuv_idh); + + err = DecompressSequenceBeginS ( + &yuv_seq, + yuv_idh, + NULL, + 0, + port, + NULL, + NULL, + yuv_matrix, + 0, + NULL, + codecFlagUseImageBuffer, + codecLosslessQuality, + yuv_codec); + + if (err != noErr) { + SDL_SetError ("Error trying to start YUV codec."); + return NULL; + } + + overlay = (SDL_Overlay*) malloc (sizeof(*overlay)); + if (overlay == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + overlay->format = format; + overlay->w = width; + overlay->h = height; + overlay->planes = 3; + overlay->hw_overlay = 1; + { + int offset; + Uint8 **pixels; + Uint16 *pitches; + int plane2, plane3; + + if (format == SDL_IYUV_OVERLAY) { + + plane2 = 1; /* Native codec format */ + plane3 = 2; + } + else if (format == SDL_YV12_OVERLAY) { + + /* switch the U and V planes */ + plane2 = 2; /* U plane maps to plane 3 */ + plane3 = 1; /* V plane maps to plane 2 */ + } + else { + SDL_SetError("Unsupported YUV format"); + return NULL; + } + + pixels = (Uint8**) malloc (sizeof(*pixels) * 3); + pitches = (Uint16*) malloc (sizeof(*pitches) * 3); + if (pixels == NULL || pitches == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + yuv_pixmap = (PlanarPixmapInfoYUV420*) + malloc (sizeof(PlanarPixmapInfoYUV420) + + (width * height * 2)); + if (yuv_pixmap == NULL) { + SDL_OutOfMemory (); + return NULL; + } + + //CHECK_ALIGN(yuv_pixmap); + offset = sizeof(PlanarPixmapInfoYUV420); + //offset += ALIGN(offset); + //CHECK_ALIGN(offset); + + pixels[0] = (Uint8*)yuv_pixmap + offset; + //CHECK_ALIGN(pixels[0]); + + pitches[0] = width; + yuv_pixmap->componentInfoY.offset = offset; + yuv_pixmap->componentInfoY.rowBytes = width; + + offset += width * height; + pixels[plane2] = (Uint8*)yuv_pixmap + offset; + pitches[plane2] = width / 2; + yuv_pixmap->componentInfoCb.offset = offset; + yuv_pixmap->componentInfoCb.rowBytes = width / 2; + + offset += (width * height / 4); + pixels[plane3] = (Uint8*)yuv_pixmap + offset; + pitches[plane3] = width / 2; + yuv_pixmap->componentInfoCr.offset = offset; + yuv_pixmap->componentInfoCr.rowBytes = width / 2; + + overlay->pixels = pixels; + overlay->pitches = pitches; + } + + overlay->hwfuncs = malloc (sizeof(*overlay->hwfuncs)); + if (overlay->hwfuncs == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + overlay->hwfuncs->Lock = QZ_LockYUV; + overlay->hwfuncs->Unlock = QZ_UnlockYUV; + overlay->hwfuncs->Display = QZ_DisplayYUV; + overlay->hwfuncs->FreeHW = QZ_FreeHWYUV; + + yuv_width = overlay->w; + yuv_height = overlay->h; + + return overlay; +} +