📄 sdl_quartzvideo.m
字号:
} this->UpdateRects = QZ_UpdateRects; this->LockHWSurface = QZ_LockWindow; this->UnlockHWSurface = QZ_UnlockWindow; } /* Save flags to ensure correct teardown */ mode_flags = current->flags; /* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */ if (fade_token != kCGDisplayFadeReservationInvalidToken) { CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); CGReleaseDisplayFadeReservation (fade_token); } return current;}static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags) { current->flags = 0; current->pixels = NULL; /* Setup full screen video */ if ( flags & SDL_FULLSCREEN ) { current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags ); if (current == NULL) return NULL; } /* Setup windowed video */ else { /* Force bpp to the device's bpp */ bpp = device_bpp; current = QZ_SetVideoWindowed (this, current, width, height, &bpp, flags); if (current == NULL) return NULL; } /* Setup the new pixel format */ { int amask = 0, rmask = 0, gmask = 0, bmask = 0; switch (bpp) { case 16: /* (1)-5-5-5 RGB */ amask = 0; rmask = 0x7C00; gmask = 0x03E0; bmask = 0x001F; break; case 24: SDL_SetError ("24bpp is not available"); return NULL; case 32: /* (8)-8-8-8 ARGB */ amask = 0x00000000; rmask = 0x00FF0000; gmask = 0x0000FF00; bmask = 0x000000FF; break; } if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, amask ) ) { 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) { return 0;}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 int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface) { return 1;}static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface) {} /* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */ static AbsoluteTime QZ_SecondsToAbsolute ( double seconds ) { union { UInt64 i; Nanoseconds ns; } temp; temp.i = seconds * 1000000000.0; return NanosecondsToAbsolute ( temp.ns );}static int QZ_ThreadFlip (_THIS) { Uint8 *src, *dst; int skip, len, h; /* Give this thread the highest scheduling priority possible, in the hopes that it will immediately run after the VBL delay */ { pthread_t current_thread; int policy; struct sched_param param; current_thread = pthread_self (); pthread_getschedparam (current_thread, &policy, ¶m); policy = SCHED_RR; param.sched_priority = sched_get_priority_max (policy); pthread_setschedparam (current_thread, policy, ¶m); } while (1) { SDL_SemWait (sem1); if (quit_thread) return 0; /* * We have to add SDL_VideoSurface->offset here, since we might be a * smaller surface in the center of the framebuffer (you asked for * a fullscreen resolution smaller than the hardware could supply * so SDL is centering it in a bigger resolution)... */ dst = (Uint8 *)CGDisplayBaseAddress (display_id) + SDL_VideoSurface->offset; src = current_buffer + SDL_VideoSurface->offset; len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel; h = SDL_VideoSurface->h; skip = SDL_VideoSurface->pitch; /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */ { /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */ double refreshRate; double linesPerSecond; double target; double position; double adjustment; AbsoluteTime nextTime; CFNumberRef refreshRateCFNumber; refreshRateCFNumber = CFDictionaryGetValue (mode, kCGDisplayRefreshRate); if ( NULL == refreshRateCFNumber ) { SDL_SetError ("Mode has no refresh rate"); goto ERROR; } if ( 0 == CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) ) { SDL_SetError ("Error getting refresh rate"); goto ERROR; } if ( 0 == refreshRate ) { SDL_SetError ("Display has no refresh rate, using 60hz"); /* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */ refreshRate = 60.0; } linesPerSecond = refreshRate * h; target = h; /* Figure out the first delay so we start off about right */ position = CGDisplayBeamPosition (display_id); if (position > target) position = 0; adjustment = (target - position) / linesPerSecond; nextTime = AddAbsoluteToAbsolute (UpTime (), QZ_SecondsToAbsolute (adjustment)); MPDelayUntil (&nextTime); } /* On error, skip VBL delay */ ERROR: while ( h-- ) { SDL_memcpy (dst, src, len); src += skip; dst += skip; } /* signal flip completion */ SDL_SemPost (sem2); } return 0;} static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface) { /* wait for previous flip to complete */ SDL_SemWait (sem2); current_buffer = surface->pixels; if (surface->pixels == sw_buffers[0]) surface->pixels = sw_buffers[1]; else surface->pixels = sw_buffers[0]; /* signal worker thread to do the flip */ SDL_SemPost (sem1); return 0;}static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects) { /* perform a flip if someone calls updaterects on a doublebuferred surface */ this->FlipHWSurface (this, SDL_VideoSurface);}static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *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.*//*#define TEST_OBSCURED 1*/#if TEST_OBSCURED#include "CGS.h"#endifstatic int QZ_IsWindowObscured (NSWindow *window) {#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 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; /* Cache the dock icon windows */ static CGSWindowID dockIcons[kMaxWindows]; static int numCachedDockIcons = 0; CGSWindowID windows[kMaxWindows]; CGSWindowCount i, count; CGSWindowLevel winLevel; CGSRect winRect; CGSRect contentRect; int windowNumber; 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 */ /* 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 ( ! [ window styleMask ] & NSBorderlessWindowMask ) windowContentOffset = 22; else windowContentOffset = 0; windowNumber = [ window windowNumber ]; /* 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 */ 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -