55#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
56#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
58HRESULT WINAPI DwmSetWindowAttribute (HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
60#define USE_UNDOCUMENTED_DARKMODE_API 1
62#if USE_UNDOCUMENTED_DARKMODE_API
63#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
64#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
66typedef DWORD(WINAPI* pfnSetPreferredAppMode)(DWORD appMode);
78@interface MyOpenGLView (OOPrivate)
81- (void) setWindowBorderless:(BOOL)borderless;
82- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event keyID:(Uint16)key_id;
87- (SDL_DisplayID) getDisplayId
89 SDL_DisplayID displayId = 0;
92 displayId = SDL_GetDisplayForWindow(window);
97 SDL_DisplayID *displayIds = SDL_GetDisplays(&displayCount);
100 displayId = displayIds[0];
104 OOLog(
@"sdl.display_id",
@"Could not get list of displays. Error was: %s", SDL_GetError());
106 SDL_free(displayIds);
111- (NSMutableDictionary *) getNativeSize
113 NSMutableDictionary *
mode=[[NSMutableDictionary alloc] init];
114 int nativeDisplayWidth = 1024;
115 int nativeDisplayHeight = 768;
118 SDL_DisplayID displayId = [
self getDisplayId];
120 if (displayId && SDL_GetDisplayUsableBounds(displayId, &boundsRect))
122 nativeDisplayWidth = boundsRect.w;
123 nativeDisplayHeight = boundsRect.h;
124 OOLog(
@"display.mode.list.native",
@"Native display resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight);
128 OOLog(
@"display.mode.list.native.failed",
@"%@",
@"SDL_GetWMInfo failed, defaulting to 1024x768 for native size");
132 nativeDisplayWidth = GetSystemMetrics(SM_CXSCREEN);
133 nativeDisplayHeight = GetSystemMetrics(SM_CYSCREEN);
134 OOLog(
@"display.mode.list.native",
@"Windows native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight);
136 OOLog(
@"display.mode.list.native.unknown",
@"Unknown architecture, defaulting to 1024x768");
138 [mode
setValue: [NSNumber numberWithInt: nativeDisplayWidth]
forKey:kOODisplayWidth];
139 [mode
setValue: [NSNumber numberWithInt: nativeDisplayHeight]
forKey: kOODisplayHeight];
140 [mode
setValue: [NSNumber numberWithInt: 0]
forKey: kOODisplayRefreshRate];
145- (NSString*) getWindowCaption
148 NSString *caption = [NSString stringWithFormat:@"Oolite v%@ - %s", @OO_VERSION_FULL, BUILD_DATE];
150 NSString *caption = [NSString stringWithFormat:@"Oolite v%@ - %s", @OO_VERSION_FULL, __DATE__];
152 return [[caption retain] autorelease];
155- (void) createWindowWithSize: (NSSize) size
158 SDL_Surface *icon=NULL;
161 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
163 OOLog(
@"display.initGL",
@"Trying %d-bpcc, 24-bit depth buffer", bitsPerColorComponent);
164 if (bitsPerColorComponent > 8)
166 SDL_GL_SetAttribute(SDL_GL_FLOATBUFFERS, 1);
171 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, bitsPerColorComponent);
172 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, bitsPerColorComponent);
173 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, bitsPerColorComponent);
174 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, bitsPerColorComponent);
177 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
178 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
188 if ([prefs oo_boolForKey:
@"anti-aliasing" defaultValue:NO])
190 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
191 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
194 NSString *windowCaption = [
self getWindowCaption];
195 Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY;
198 SDL_PropertiesID props = SDL_CreateProperties();
199 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, [windowCaption UTF8String]);
200 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER,
size.width);
201 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER,
size.height);
202 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, windowFlags);
205 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
206 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
208 window = SDL_CreateWindowWithProperties(props);
211 OOLog(
@"display.initGL",
@"%@",
@"Trying 8-bpcc, 24-bit depth buffer");
212 SDL_GL_SetAttribute(SDL_GL_FLOATBUFFERS, 0);
213 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
214 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
215 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
216 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
217 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
218 window = SDL_CreateWindowWithProperties(props);
224 OOLog(
@"display.initGL",
@"%@",
@"Trying 5-bpcc, 16-bit depth buffer");
225 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
226 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
227 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
228 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
230 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
231 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
232 window = SDL_CreateWindowWithProperties(props);
236 SDL_DestroyProperties(props);
240 const char * errStr = SDL_GetError();
241 OOLogERR(
@"display.mode.error",
@"Could not create window: %s", errStr);
244 glContext = SDL_GL_CreateContext(window);
247 OOLog(
@"sdl.create_context",
@"%@",
@"Could not create OpenGL context");
250 SDL_Surface *surface = SDL_GetWindowSurface(window);
251 if (!SDL_SetSurfaceColorspace(surface, SDL_COLORSPACE_SRGB_LINEAR))
253 OOLogWARN(
@"sdl.use_edr_surface",
@"%@ %s",
@"Failed to set SDR linear surface - falling back to SDR. Error was:", SDL_GetError());
254 SDL_SetSurfaceColorspace(surface, SDL_COLORSPACE_SRGB);
259 SDL_PropertiesID windowPropertiesId = SDL_GetWindowProperties(window);
260 windowHandle = SDL_GetPointerProperty(windowPropertiesId, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
263 OOLog(
@"sdl.window_handle",
@"%@",
@"Failed to retrieve window handle");
268 if (![
self getCurrentMonitorInfo:&monitorInfo])
270 OOLogWARN(
@"display.initGL.monitorInfoWarning",
@"Could not get current monitor information.");
273 atDesktopResolution = YES;
275#if USE_UNDOCUMENTED_DARKMODE_API
277 HMODULE hUxTheme = LoadLibraryExW(L
"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
281 pfnSetPreferredAppMode SetPreferredAppMode = (pfnSetPreferredAppMode)GetProcAddress(hUxTheme, MAKEINTRESOURCEA(135));
282 if (SetPreferredAppMode) SetPreferredAppMode(AllowDark);
283 FreeLibrary(hUxTheme);
285 [
self refreshDarKOrLightMode];
289 imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"];
290 icon = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:
@"WMicon.bmp"] UTF8String]);
294 const SDL_PixelFormatDetails *pixelFormat = SDL_GetPixelFormatDetails(icon->format);
295 const SDL_Palette *palette = SDL_GetSurfacePalette(icon);
296 colorkey = SDL_MapRGB(pixelFormat, palette, 128, 0, 128);
297 SDL_SetSurfaceColorKey(icon, YES, colorkey);
298 SDL_SetWindowIcon(window, icon);
300 SDL_DestroySurface(icon);
302 _colorSaturation = 1.0f;
305 _hdrMaxBrightness = [prefs oo_floatForKey:@"hdr-max-brightness" defaultValue:1000.0f];
306 _hdrPaperWhiteBrightness = [prefs oo_floatForKey:@"hdr-paperwhite-brightness" defaultValue:200.0f];
307 _hdrToneMapper =
OOHDRToneMapperFromString([prefs oo_stringForKey:
@"hdr-tone-mapper" defaultValue:
@"OOHDR_TONEMAPPER_ACES_APPROX"]);
310 _sdrToneMapper =
OOSDRToneMapperFromString([prefs oo_stringForKey:
@"sdr-tone-mapper" defaultValue:
@"OOSDR_TONEMAPPER_ACES"]);
312 SDL_SetWindowSurfaceVSync(window, vSyncPreference);
313 OOLog(
@"display.initGL",
@"V-Sync %@requested.", vSyncPreference ?
@"" :
@"not ");
316 OOLog(
@"display.initGL",
@"%@",
@"Achieved color / depth buffer sizes (bits):");
317 SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &testAttrib);
318 OOLog(
@"display.initGL",
@"Red: %d", testAttrib);
319 SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &testAttrib);
320 OOLog(
@"display.initGL",
@"Green: %d", testAttrib);
321 SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &testAttrib);
322 OOLog(
@"display.initGL",
@"Blue: %d", testAttrib);
323 SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &testAttrib);
324 OOLog(
@"display.initGL",
@"Alpha: %d", testAttrib);
325 SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &testAttrib);
326 OOLog(
@"display.initGL",
@"Depth Buffer: %d", testAttrib);
328 SDL_GL_GetAttribute(SDL_GL_FLOATBUFFERS, &testAttrib);
329 OOLog(
@"display.initGL",
@"Pixel type is float : %d", testAttrib);
332 OOLog(
@"display.initGL",
@"Pixel format index: %d", GetPixelFormat(GetDC(windowHandle)));
338 if (vSyncPreference && (!SDL_GetWindowSurfaceVSync(window, &hasVsync) || !hasVsync))
340 OOLogWARN(
@"display.initGL",
@"Could not enable V-Sync. Please check that your graphics driver supports the %@_swap_control extension.",
345 OOLog(
@"display.initGL",
@"%@",
@"V-Sync set");
349 SDL_GetWindowSizeInPixels(window, &width, &height);
350 bounds.size.width = width;
351 bounds.size.height = height;
360 NSString *cmdLineArgsStr =
@"Startup command: ";
364 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
365 showSplashScreen = [prefs oo_boolForKey:@"splash-screen" defaultValue:YES];
366 vSyncPreference = [prefs oo_boolForKey:@"v-sync" defaultValue:YES];
367 bitsPerColorComponent = [prefs oo_boolForKey:@"hdr" defaultValue:NO] ? 16 : 8;
369 NSArray *arguments =
nil;
370 NSEnumerator *argEnum =
nil;
372 BOOL noSplashArgFound = NO;
374 [
self initKeyMappingData];
379 arguments = [[NSProcessInfo processInfo] arguments];
383 for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); )
385 if ([arg isEqual:
@"-nosplash"] || [arg isEqual:
@"--nosplash"])
387 showSplashScreen = NO;
388 noSplashArgFound = YES;
390 else if (([arg isEqual:
@"-splash"] || [arg isEqual:
@"--splash"]) && !noSplashArgFound)
392 showSplashScreen = YES;
396 if ([arg isEqual:
@"-novsync"] || [arg isEqual:
@"--novsync"]) vSyncPreference = NO;
398 if ([arg isEqual:
@"-hdr"]) bitsPerColorComponent = 16;
401 cmdLineArgsStr = [cmdLineArgsStr stringByAppendingFormat:@"%@ ", arg];
404 OOLog(
@"process.args",
@"%@", cmdLineArgsStr);
410 OOLog(
@"sdl.init",
@"%@",
@"initialising SDL");
411 if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD))
413 OOLog(
@"sdl.init.failed",
@"Unable to init SDL: %s\n", SDL_GetError());
418 [
self populateFullScreenModelist];
423 [
self loadWindowSize];
424 [
self loadFullscreenSettings];
427 firstScreen = (fullScreen) ? [
self modeAsSize: currentSize] : currentWindowSize;
428 viewSize = firstScreen;
434 if (![
OOSound isSoundOK])
OOLog(
@"sound.init",
@"%@",
@"Sound system disabled.");
436 grabMouseStatus = NO;
438 OOLog(
@"display.mode.list",
@"%@",
@"CREATING MODE LIST");
443 ShowWindow(windowHandle,SW_SHOWMINIMIZED);
444 updateContext = !showSplashScreen;
446 if (!showSplashScreen)
449 [
self initialiseGLWithSize: firstScreen];
453 [
self autoShowMouse];
455 virtualJoystickPosition = NSMakePoint(0.0,0.0);
458 _mouseVirtualStickSensitivityFactor = OOClamp_0_1_f([prefs oo_floatForKey:
@"mouse-flight-sensitivity" defaultValue:0.95f]);
460 if (_mouseVirtualStickSensitivityFactor < 0.005f) _mouseVirtualStickSensitivityFactor = 0.005f;
462 typedString = [[NSMutableString alloc] initWithString:@""];
464 isAlphabetKeyDown = NO;
466 timeIntervalAtLastClick = timeSinceLastMouseWheel = [NSDate timeIntervalSinceReferenceDate];
468 _mouseWheelDelta = 0.0f;
470 m_glContextInitialized = NO;
475- (void) endSplashScreen
480 if ([
self hdrOutput] && ![
self isOutputDisplayHDREnabled])
482 if (MessageBox(NULL,
"No primary display in HDR mode was detected.\n\n"
483 "If you continue, graphics will not be rendered as intended.\n"
484 "Click OK to launch anyway, or Cancel to exit.",
"oolite.exe - HDR requested",
485 MB_OKCANCEL | MB_ICONWARNING) == IDCANCEL)
487 [gameController exitAppWithContext:@"Cancel selected on no-HDR confirmation dialog"];
491 wasFullScreen = !fullScreen;
493 ShowWindow(windowHandle,SW_RESTORE);
494 [
self initialiseGLWithSize: firstScreen];
497 if (!showSplashScreen)
return;
499 SDL_HideWindow(window);
500 SDL_SetWindowSize(window, firstScreen.width, firstScreen.height);
501 SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
502 SDL_SetWindowFullscreen(window, fullScreen);
503 SDL_ShowWindow(window);
512 SDL_Event dummyEvent;
513 while (SDL_PollEvent(&dummyEvent))
524 [
self autoShowMouse];
528- (void) initKeyMappingData
530 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
538 NSString *kbd = [prefs oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
539 NSDictionary *subset = [kmap objectForKey:kbd];
541 [keyMappings_normal release];
542 keyMappings_normal = [[subset objectForKey:@"mapping_normal"] copy];
543 [keyMappings_shifted release];
544 keyMappings_shifted = [[subset objectForKey:@"mapping_shifted"] copy];
551 [typedString release];
554 [screenSizes release];
558 SDL_DestroyWindow(window);
563 SDL_GL_DestroyContext(glContext);
566 if (keyMappings_normal)
567 [keyMappings_normal release];
569 if (keyMappings_shifted)
570 [keyMappings_shifted release];
576 [matrixManager release];
582- (void) autoShowMouse
587 if (SDL_CursorVisible())
592 if (!SDL_CursorVisible())
599 allowingStringInput = value;
603- (void) allowStringInput: (BOOL) value
613 return allowingStringInput;
617- (NSString *) typedString
623- (void) resetTypedString
625 [typedString setString:@""];
629- (void) setTypedString:(NSString*) value
631 [typedString setString:value];
647- (NSSize) backingViewSize
673 return gameController;
679 gameController = controller;
685 [
self autoShowMouse];
686 [
self setMouseInDeltaMode:OOMouseInteractionModeIsFlightMode(newMode)];
690- (BOOL) inFullScreenMode
695#ifdef GNUSTEP_BASE_LIBRARY
696- (void) setFullScreenMode:(BOOL)fsm
701 [[NSUserDefaults standardUserDefaults]
702 setBool: fullScreen forKey:@"fullscreen"];
703 [[NSUserDefaults standardUserDefaults] synchronize];
707- (void) toggleScreenMode
709 [
self setFullScreenMode: !fullScreen];
711 [
self getCurrentMonitorInfo:&monitorInfo];
716 if(![
self isRunningOnPrimaryDisplayDevice])
718 [
self initialiseGLWithSize:NSMakeSize(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
719 monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top)];
721 else [
self initialiseGLWithSize:[
self modeAsSize: currentSize]];
723 [
self initialiseGLWithSize:[
self modeAsSize: currentSize]];
728 [
self initialiseGLWithSize: currentWindowSize];
730 SDL_SetWindowMouseGrab(window, NO);
741- (void) setDisplayMode:(
int)mode fullScreen:(BOOL)fsm
743 [
self setFullScreenMode: fsm];
746 [
self initialiseGLWithSize: [
self modeAsSize: mode]];
750- (
int) indexOfCurrentSize
756- (void) setScreenSize: (
int)sizeIndex
758 currentSize=sizeIndex;
760 [
self initialiseGLWithSize: [
self modeAsSize: currentSize]];
764- (NSMutableArray *)getScreenSizeArray
770- (NSSize) modeAsSize:(
int)sizeIndex
772 NSDictionary *
mode=[screenSizes objectAtIndex: sizeIndex];
786 [
self drawRect: NSMakeRect(0, 0, viewSize.width, viewSize.height)];
789- (void) drawRect:(NSRect)rect
791 SDL_SetWindowSize(window, (
int)NSWidth(rect), (
int)NSHeight(rect));
792 [
self updateScreenWithVideoMode:YES];
795- (void) updateScreenWithVideoMode:(BOOL) v_mode
797 SDL_Surface* surface = SDL_GetWindowSurface(window);
798 int windowWidth, windowHeight;
799 SDL_GetWindowSize(window, &windowWidth, &windowHeight);
800 if ((viewSize.width != windowWidth)||(viewSize.height != windowHeight))
803 m_glContextInitialized = NO;
805 viewSize.width = windowWidth;
806 viewSize.height = windowHeight;
809 if (m_glContextInitialized == NO)
811 [
self initialiseGLWithSize:viewSize useVideoMode:v_mode];
821 [UNIVERSE drawUniverse];
826 glClearColor( 0.0, 0.0, 0.0, 0.0);
827 glClear( GL_COLOR_BUFFER_BIT);
830 SDL_GL_SwapWindow(window);
833- (void) initSplashScreen
835 if (!showSplashScreen)
return;
838 SDL_Surface *image=NULL;
841 NSString *imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"];
843 image = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:
@"splash.bmp"] UTF8String]);
847 SDL_DestroySurface(image);
848 OOLogWARN(
@"sdl.gameStart",
@"%@",
@"image 'splash.bmp' not found!");
849 [
self endSplashScreen];
858 [
self createWindowWithSize: NSMakeSize(image->w, image->h)];
861 dest.x = (GetSystemMetrics(SM_CXSCREEN)- dest.w)/2;
862 dest.y = (GetSystemMetrics(SM_CYSCREEN)-dest.h)/2;
863 SetWindowLong(windowHandle,GWL_STYLE,GetWindowLong(windowHandle,GWL_STYLE) & ~WS_CAPTION & ~WS_THICKFRAME);
864 ShowWindow(windowHandle,SW_RESTORE);
865 MoveWindow(windowHandle,dest.x,dest.y,dest.w,dest.h,TRUE);
869 float pixelDensity = SDL_GetWindowPixelDensity(window);
870 if (pixelDensity == 0.0f)
875 glViewport( 0, 0, dest.w * pixelDensity, dest.h * pixelDensity);
877 glEnable( GL_TEXTURE_2D );
878 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
879 glClear( GL_COLOR_BUFFER_BIT );
881 [matrixManager resetProjection];
882 [matrixManager orthoLeft: 0.0f right: 1.0f bottom: 1.0f top: 0.0f near: -1.0f far: 1.0f];
883 [matrixManager syncProjection];
885 [matrixManager resetModelView];
886 [matrixManager syncModelView];
889 GLenum texture_format;
893 const SDL_PixelFormatDetails *pixelFormat = SDL_GetPixelFormatDetails(image->format);
894 nOfColors = pixelFormat->bytes_per_pixel;
897 if (pixelFormat->Rmask == 0x000000ff)
898 texture_format = GL_RGBA;
900 texture_format = GL_BGRA;
902 else if (nOfColors == 3)
904 if (pixelFormat->Rmask == 0x000000ff)
905 texture_format = GL_RGB;
907 texture_format = GL_BGR;
909 SDL_DestroySurface(image);
910 OOLog(
@"Sdl.GameStart",
@"%@",
@"----- Encoding error within image 'splash.bmp'");
911 [
self endSplashScreen];
915 glGenTextures( 1, &texture );
916 glBindTexture( GL_TEXTURE_2D, texture );
919 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
920 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
923 glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, image->w, image->h, 0,
924 texture_format, GL_UNSIGNED_BYTE, image->pixels );
926 glBindTexture( GL_TEXTURE_2D, texture );
929 glTexCoord2i( 0, 0 );
931 glTexCoord2i( 1, 0 );
933 glTexCoord2i( 1, 1 );
935 glTexCoord2i( 0, 1 );
941 SDL_GL_SwapWindow(window);
942 [matrixManager resetModelView];
943 [matrixManager syncModelView];
946 SDL_DestroySurface( image );
948 glDeleteTextures(1, &texture);
950 glDisable( GL_TEXTURE_2D );
953 SDL_DestroySurface(image);
959- (MONITORINFOEX) currentMonitorInfo
965- (BOOL) getCurrentMonitorInfo:(MONITORINFOEX *)mInfo
967 HMONITOR hMon = MonitorFromWindow(windowHandle, MONITOR_DEFAULTTOPRIMARY);
968 ZeroMemory(mInfo,
sizeof(MONITORINFOEX));
969 mInfo->cbSize =
sizeof(MONITORINFOEX);
970 if (GetMonitorInfo (hMon, (LPMONITORINFO)mInfo))
978- (BOOL) isRunningOnPrimaryDisplayDevice
981 [
self getCurrentMonitorInfo:&monitorInfo];
982 if (!(monitorInfo.dwFlags & MONITORINFOF_PRIMARY))
990- (void) grabMouseInsideGameWindow:(BOOL) value
995 GetWindowRect(windowHandle, &gameWindowRect);
996 ClipCursor(&gameWindowRect);
1002 grabMouseStatus = !!value;
1006- (void) stringToClipboard:(NSString *)stringToCopy
1010 const char *clipboardText = [stringToCopy cStringUsingEncoding:NSUTF8StringEncoding];
1011 const size_t clipboardTextLength = strlen(clipboardText) + 1;
1012 HGLOBAL clipboardMem = GlobalAlloc(GMEM_MOVEABLE, clipboardTextLength);
1015 memcpy(GlobalLock(clipboardMem), clipboardText, clipboardTextLength);
1016 GlobalUnlock(clipboardMem);
1019 if (!SetClipboardData(CF_TEXT, clipboardMem))
1021 OOLog(
@"stringToClipboard.failed",
@"Failed to copy string %@ to clipboard", stringToCopy);
1026 GlobalFree(clipboardMem);
1094- (void) setWindowBorderless:(BOOL)borderless
1096 LONG currentWindowStyle = GetWindowLong(windowHandle, GWL_STYLE);
1099 if ((!borderless && (currentWindowStyle & WS_CAPTION)) ||
1100 (borderless && !(currentWindowStyle & WS_CAPTION)))
return;
1104 SetWindowLong(windowHandle, GWL_STYLE, currentWindowStyle & ~WS_CAPTION & ~WS_THICKFRAME);
1108 SetWindowLong(windowHandle, GWL_STYLE, currentWindowStyle |
1109 WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX );
1110 [
self refreshDarKOrLightMode];
1112 SetWindowPos(windowHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
1116- (void) refreshDarKOrLightMode
1118 int shouldSetDarkMode = [
self isDarkModeOn];
1119 DwmSetWindowAttribute (windowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &shouldSetDarkMode,
sizeof(shouldSetDarkMode));
1123- (BOOL) isDarkModeOn
1126 DWORD bufferSize =
sizeof(buffer);
1129 HRESULT resultRegGetValue = RegGetValueW(HKEY_CURRENT_USER, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
1130 L
"AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, buffer, &bufferSize);
1131 if (resultRegGetValue != ERROR_SUCCESS)
1137 int i = (
int)(buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]);
1144- (BOOL) atDesktopResolution
1146 return atDesktopResolution;
1156- (BOOL) isOutputDisplayHDREnabled
1158 UINT32 pathCount, modeCount;
1159 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
1160 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
1161 UINT32 flags = QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE;
1162 LONG tempResult = ERROR_SUCCESS;
1163 BOOL isAdvColorInfo2DetectionSuccess = NO;
1169 tempResult = GetDisplayConfigBufferSizes(flags, &pathCount, &modeCount);
1171 if (tempResult != ERROR_SUCCESS)
1173 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: %ld", HRESULT_FROM_WIN32(tempResult));
1178 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pathCount *
sizeof(DISPLAYCONFIG_PATH_INFO));
1179 if (!pPathInfoArray)
1181 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: -1");
1185 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(modeCount *
sizeof(DISPLAYCONFIG_MODE_INFO));
1186 if (!pModeInfoArray)
1189 free(pPathInfoArray);
1190 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: -1");
1195 tempResult = QueryDisplayConfig(flags, &pathCount, pPathInfoArray, &modeCount, pModeInfoArray, NULL);
1197 if (tempResult != ERROR_SUCCESS)
1199 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: %ld", HRESULT_FROM_WIN32(tempResult));
1204 pPathInfoArray = realloc(pPathInfoArray, pathCount *
sizeof(DISPLAYCONFIG_PATH_INFO));
1205 if (!pPathInfoArray)
1207 OOLogERR(
@"gameView.isOutputDisplayHDREnabled",
@"Failed ro reallocate pPathInfoArray");
1210 pModeInfoArray = realloc(pModeInfoArray, modeCount *
sizeof(DISPLAYCONFIG_MODE_INFO));
1211 if (!pModeInfoArray)
1213 OOLogERR(
@"gameView.isOutputDisplayHDREnabled",
@"Failed to reallocate pModeInfoArray");
1219 }
while (tempResult == ERROR_INSUFFICIENT_BUFFER);
1221 if (tempResult != ERROR_SUCCESS)
1223 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: %ld", HRESULT_FROM_WIN32(tempResult));
1229 wchar_t wcsPrimaryDeviceID[256] = L
"OOUnknownDevice";
1234 for (i = 0; i < pathCount; i++)
1237 char saveDeviceName[64];
1239 ZeroMemory(&dd,
sizeof(dd));
1241 EnumDisplayDevices(NULL, i, &dd, 0);
1242 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
1245 strncpy(saveDeviceName, dd.DeviceName, 33);
1246 while (EnumDisplayDevices(saveDeviceName, j, &dd, 0x00000001))
1248 if (
EXPECT(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
1251 mbstowcs(wcsPrimaryDeviceID, dd.DeviceID, 129);
1257 OOLogWARN(
@"gameView.isOutputDisplayHDREnabled",
@"Primary monitor candidate %s (%s %s) not active.", dd.DeviceName, dd.DeviceString, dd.DeviceID);
1267 for (i = 0; i < pathCount; i++)
1269 DISPLAYCONFIG_PATH_INFO *path = &pPathInfoArray[i];
1271 DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
1272 targetName.header.adapterId = path->targetInfo.adapterId;
1273 targetName.header.id = path->targetInfo.id;
1274 targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
1275 targetName.header.size =
sizeof(targetName);
1276 tempResult = DisplayConfigGetDeviceInfo(&targetName.header);
1278 if (tempResult != ERROR_SUCCESS)
1280 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: %ld", HRESULT_FROM_WIN32(tempResult));
1285 DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 advColorInfo2 = {};
1286 advColorInfo2.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2;
1287 advColorInfo2.header.adapterId = path->targetInfo.adapterId;
1288 advColorInfo2.header.id = path->targetInfo.id;
1289 advColorInfo2.header.size =
sizeof(advColorInfo2);
1291 tempResult = DisplayConfigGetDeviceInfo(&advColorInfo2.header);
1293 if (tempResult == ERROR_SUCCESS) isAdvColorInfo2DetectionSuccess = YES;
1296 OOLogWARN(
@"gameView.isOutputDisplayHDREnabled",
@"Received 0x%08lX while attempting to detect HDR mode using Advanced Color Info 2 API. Retrying detection using legacy API.", HRESULT_FROM_WIN32(tempResult));
1301 DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = {};
1302 advColorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
1303 advColorInfo.header.adapterId = path->targetInfo.adapterId;
1304 advColorInfo.header.id = path->targetInfo.id;
1305 advColorInfo.header.size =
sizeof(advColorInfo);
1307 tempResult = DisplayConfigGetDeviceInfo(&advColorInfo.header);
1309 if (tempResult != ERROR_SUCCESS)
1311 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"Error! Code: %ld", HRESULT_FROM_WIN32(tempResult));
1315 BOOL isPrimaryDisplayDevice = !wcscmp(targetName.monitorDevicePath, wcsPrimaryDeviceID);
1318 if (isPrimaryDisplayDevice &&
1319 ((isAdvColorInfo2DetectionSuccess && advColorInfo2.highDynamicRangeSupported && advColorInfo2.activeColorMode == DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR) ||
1320 (!isAdvColorInfo2DetectionSuccess && advColorInfo.advancedColorSupported && advColorInfo.advancedColorEnabled && !advColorInfo.wideColorEnforced)))
1327 OOLog(
@"gameView.isOutputDisplayHDREnabled",
@"HDR display output requested - checking availability: %@", result ?
@"YES" :
@"NO");
1329 free (pModeInfoArray);
1330 free (pPathInfoArray);
1336- (float) hdrMaxBrightness
1338 return _hdrMaxBrightness;
1342- (void) setHDRMaxBrightness: (
float)newMaxBrightness
1346 _hdrMaxBrightness = newMaxBrightness;
1348 [[NSUserDefaults standardUserDefaults] setFloat:_hdrMaxBrightness forKey:@"hdr-max-brightness"];
1352- (float) hdrPaperWhiteBrightness
1354 return _hdrPaperWhiteBrightness;
1358- (void) setHDRPaperWhiteBrightness: (
float)newPaperWhiteBrightness
1362 _hdrPaperWhiteBrightness = newPaperWhiteBrightness;
1364 [[NSUserDefaults standardUserDefaults] setFloat:_hdrPaperWhiteBrightness forKey:@"hdr-paperwhite-brightness"];
1370 return _hdrToneMapper;
1378 _hdrToneMapper = newToneMapper;
1385- (BOOL) isRunningOnPrimaryDisplayDevice
1391- (void) grabMouseInsideGameWindow:(BOOL) value
1397- (void) stringToClipboard:(NSString *)stringToCopy
1409- (void) setWindowBorderless:(BOOL)borderless
1421- (BOOL) isOutputDisplayHDREnabled
1431 return _sdrToneMapper;
1439 _sdrToneMapper = newToneMapper;
1443- (void) initialiseGLWithSize:(NSSize) v_size
1445 [
self initialiseGLWithSize:v_size useVideoMode:YES];
1449- (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode
1453 [
self createWindowWithSize: v_size];
1456 OOLog(
@"display.initGL",
@"Requested a new surface of %d x %d, %@.", (
int)viewSize.width, (
int)viewSize.height,(fullScreen ?
@"fullscreen" :
@"windowed"));
1457 SDL_GL_SwapWindow(window);
1460 if (!updateContext)
return;
1463 settings.dmSize =
sizeof(DEVMODE);
1464 settings.dmDriverExtra = 0;
1465 EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &settings);
1467 WINDOWPLACEMENT windowPlacement;
1468 windowPlacement.length =
sizeof(WINDOWPLACEMENT);
1469 GetWindowPlacement(windowHandle, &windowPlacement);
1471 static BOOL lastWindowPlacementMaximized = NO;
1472 if (fullScreen && (windowPlacement.showCmd == SW_SHOWMAXIMIZED))
1476 lastWindowPlacementMaximized = YES;
1480 if (lastWindowPlacementMaximized)
1482 windowPlacement.showCmd = SW_SHOWMAXIMIZED;
1487 BOOL changingResolution = [
self isRunningOnPrimaryDisplayDevice] &&
1488 ((fullScreen && (settings.dmPelsWidth != viewSize.width || settings.dmPelsHeight != viewSize.height)) ||
1489 (wasFullScreen && (settings.dmPelsWidth != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayWidth] intValue]
1490 || settings.dmPelsHeight != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayHeight] intValue])));
1502 [
self getCurrentMonitorInfo: &monitorInfo];
1504 settings.dmPelsWidth = viewSize.width;
1505 settings.dmPelsHeight = viewSize.height;
1506 settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
1511 if(lastWindowPlacementMaximized)
1513 CopyRect(&lastGoodRect, &windowPlacement.rcNormalPosition);
1515 windowPlacement.showCmd = SW_SHOWNORMAL;
1516 SetWindowPlacement(windowHandle, &windowPlacement);
1518 else GetWindowRect(windowHandle, &lastGoodRect);
1521 SetForegroundWindow(windowHandle);
1522 if (changingResolution)
1524 if (ChangeDisplaySettingsEx(monitorInfo.szDevice, &settings, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
1526 m_glContextInitialized = YES;
1527 OOLogERR(
@"displayMode.change.error",
@"Could not switch to requested display mode.");
1530 atDesktopResolution = settings.dmPelsWidth == [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayWidth] intValue]
1531 && settings.dmPelsHeight == [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayHeight] intValue];
1534 MoveWindow(windowHandle, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (
int)viewSize.width, (
int)viewSize.height, TRUE);
1537 [
self setWindowBorderless:YES];
1541 else if ( wasFullScreen )
1543 if (changingResolution)
1546 if (ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL) == DISP_CHANGE_SUCCESSFUL)
1548 atDesktopResolution = YES;
1560 [
self getCurrentMonitorInfo: &monitorInfo];
1562 if (lastWindowPlacementMaximized) CopyRect(&windowPlacement.rcNormalPosition, &lastGoodRect);
1563 SetWindowPlacement(windowHandle, &windowPlacement);
1564 if (!lastWindowPlacementMaximized)
1566 MoveWindow(windowHandle, (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left - (
int)viewSize.width)/2 +
1567 monitorInfo.rcMonitor.left,
1568 (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top - (
int)viewSize.height)/2 +
1569 monitorInfo.rcMonitor.top,
1570 (
int)viewSize.width, (
int)viewSize.height, TRUE);
1573 [
self setWindowBorderless:NO];
1575 lastWindowPlacementMaximized = NO;
1576 ShowWindow(windowHandle,SW_SHOW);
1580 saveSize = !wasFullScreen;
1582 GetClientRect(windowHandle, &wDC);
1584 if (!fullScreen && (bounds.size.width != wDC.right - wDC.left
1585 || bounds.size.height != wDC.bottom - wDC.top))
1594 RECT desiredClientRect;
1595 GetWindowRect(windowHandle, &desiredClientRect);
1596 AdjustWindowRect(&desiredClientRect, WS_CAPTION | WS_THICKFRAME, FALSE);
1597 SetWindowPos(windowHandle, NULL, desiredClientRect.left, desiredClientRect.top,
1598 desiredClientRect.right - desiredClientRect.left,
1599 desiredClientRect.bottom - desiredClientRect.top, 0);
1601 GetClientRect(windowHandle, &wDC);
1602 viewSize.width = wDC.right - wDC.left;
1603 viewSize.height = wDC.bottom - wDC.top;
1607 bounds.size.width = viewSize.width = wDC.right - wDC.left;
1608 bounds.size.height = viewSize.height = wDC.bottom - wDC.top;
1612 bounds.origin.x = monitorInfo.rcMonitor.left;
1613 bounds.origin.y = monitorInfo.rcMonitor.top;
1615 wasFullScreen=fullScreen;
1619 SDL_SetWindowBordered(window, v_mode);
1620 SDL_SetWindowFullscreen(window, fullScreen);
1621 SDL_SetWindowSize(window, viewSize.width, viewSize.height);
1622 SDL_Surface *surface = SDL_GetWindowSurface(window);
1623 bounds.size.width = surface->w;
1624 bounds.size.height = surface->h;
1627 OOLog(
@"display.initGL",
@"Created a new surface of %d x %d, %@.", (
int)viewSize.width, (
int)viewSize.height,(fullScreen ?
@"fullscreen" :
@"windowed"));
1629 if (viewSize.width/viewSize.height > 4.0/3.0) {
1630 display_z = 480.0 * bounds.size.width/bounds.size.height;
1631 x_offset = 240.0 * bounds.size.width/bounds.size.height;
1636 y_offset = 320.0 * bounds.size.height/bounds.size.width;
1639 [
self autoShowMouse];
1641 int pixelWidth, pixelHeight;
1642 SDL_GetWindowSizeInPixels(window, &pixelWidth, &pixelHeight);
1643 NSSize pixelSize = NSMakeSize(pixelWidth, pixelHeight);
1644 [[
self gameController] setUpBasicOpenGLStateWithSize:pixelSize];
1645 SDL_GL_SwapWindow(window);
1648 m_glContextInitialized = YES;
1652- (float) colorSaturation
1654 return _colorSaturation;
1658- (void) adjustColorSaturation:(
float)colorSaturationAdjustment;
1660 _colorSaturation += colorSaturationAdjustment;