Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
MyOpenGLView.m
Go to the documentation of this file.
1/*
2
3MyOpenGLView.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "png.h"
26#import "MyOpenGLView.h"
27
28#import "GameController.h"
29#import "Universe.h"
31#import "SDL_syswm.h"
32#import "OOSound.h"
33#import "NSFileManagerOOExtensions.h" // to find savedir
34#import "PlayerEntity.h"
35#import "GuiDisplayGen.h"
36#import "PlanetEntity.h"
38#import "OOCollectionExtractors.h" // for splash screen settings
40#import "ResourceManager.h"
41
42#define STB_IMAGE_WRITE_IMPLEMENTATION
43#import "stb_image_write.h"
44
45#define kOOLogUnconvertedNSLog @"unclassified.MyOpenGLView"
46
47static NSString * kOOLogKeyUp = @"input.keyMapping.keyPress.keyUp";
48static NSString * kOOLogKeyDown = @"input.keyMapping.keyPress.keyDown";
49
50#include <ctype.h>
51
52#if OOLITE_WINDOWS
53#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
54HRESULT WINAPI DwmSetWindowAttribute (HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
55#endif
56
57@interface MyOpenGLView (OOPrivate)
58
60- (void) setWindowBorderless:(BOOL)borderless;
61- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event keyID:(Uint16)key_id; // DJS
62@end
63
64@implementation MyOpenGLView
65
66+ (NSMutableDictionary *) getNativeSize
67{
68 NSMutableDictionary *mode=[[NSMutableDictionary alloc] init];
69 int nativeDisplayWidth = 1024;
70 int nativeDisplayHeight = 768;
71
72#if OOLITE_LINUX
73 SDL_SysWMinfo dpyInfo;
74 SDL_VERSION(&dpyInfo.version);
75 if(SDL_GetWMInfo(&dpyInfo))
76 {
77 nativeDisplayWidth = DisplayWidth(dpyInfo.info.x11.display, 0);
78 nativeDisplayHeight = DisplayHeight(dpyInfo.info.x11.display, 0);
79 OOLog(@"display.mode.list.native", @"X11 native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight);
80 }
81 else
82 {
83 OOLog(@"display.mode.list.native.failed", @"%@", @"SDL_GetWMInfo failed, defaulting to 1024x768 for native size");
84 }
85#elif OOLITE_WINDOWS
86 nativeDisplayWidth = GetSystemMetrics(SM_CXSCREEN);
87 nativeDisplayHeight = GetSystemMetrics(SM_CYSCREEN);
88 OOLog(@"display.mode.list.native", @"Windows native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight);
89#else
90 OOLog(@"display.mode.list.native.unknown", @"Unknown architecture, defaulting to 1024x768");
91#endif
92 [mode setValue: [NSNumber numberWithInt: nativeDisplayWidth] forKey:kOODisplayWidth];
93 [mode setValue: [NSNumber numberWithInt: nativeDisplayHeight] forKey: kOODisplayHeight];
94 [mode setValue: [NSNumber numberWithInt: 0] forKey: kOODisplayRefreshRate];
95
96 return [mode autorelease];
97}
98
99
100- (void) createSurface
101{
102 // Changing these flags can trigger texture bugs.
103 const int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL | SDL_RESIZABLE;
104
105 if (showSplashScreen)
106 {
107#if OOLITE_WINDOWS
108 // Pre setVideoMode adjustments.
109 NSSize tmp = currentWindowSize;
110 ShowWindow(SDL_Window,SW_SHOWMINIMIZED);
111 updateContext = NO; //don't update the (splash screen) window yet!
112
113 // Initialise the SDL surface. (need custom SDL.dll)
114 surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags);
115
116 // Post setVideoMode adjustments.
117 currentWindowSize=tmp;
118#else
119 // Changing the flags can trigger texture bugs.
120 surface = SDL_SetVideoMode(8, 8, 32, videoModeFlags);
121#endif
122 if (!surface) {
123 return;
124 }
125 }
126 else
127 {
128#if OOLITE_WINDOWS
129 updateContext = YES;
130#endif
131 surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags);
132 if (!surface) {
133 return;
134 }
135 // blank the surface / go to fullscreen
136 [self initialiseGLWithSize: firstScreen];
137 }
138
139 _gamma = 1.0f;
140 if (SDL_SetGamma(_gamma, _gamma, _gamma) < 0 )
141 {
142 char * errStr = SDL_GetError();
143 OOLogWARN(@"gamma.set.failed", @"Could not set gamma: %s", errStr);
144 // CIM: this doesn't seem to necessarily be fatal. Gamma settings
145 // mostly work on mine despite this function failing.
146 // exit(1);
147 }
148 SDL_EnableUNICODE(1);
149}
150
151
152- (id) init
153{
154 self = [super init];
155
156 Uint32 colorkey;
157 SDL_Surface *icon=NULL;
158 NSString *imagesDir;
159 NSString *cmdLineArgsStr = @"Startup command: ";
160
161 // SDL splash screen settings
162
163 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
164 showSplashScreen = [prefs oo_boolForKey:@"splash-screen" defaultValue:YES];
165 BOOL vSyncPreference = [prefs oo_boolForKey:@"v-sync" defaultValue:YES];
166 int bitsPerColorComponent = [prefs oo_boolForKey:@"hdr" defaultValue:NO] ? 16 : 8;
167 int vSyncValue;
168
169 NSArray *arguments = nil;
170 NSEnumerator *argEnum = nil;
171 NSString *arg = nil;
172 BOOL noSplashArgFound = NO;
173
174 [self initKeyMappingData];
175
176 // preload the printscreen key into our translation array because SDLK_PRINTSCREEN isn't available
177 scancode2Unicode[55] = gvPrintScreenKey;
178
179 arguments = [[NSProcessInfo processInfo] arguments];
180
181 // scan for splash screen overrides: -nosplash || --nosplash , -splash || --splash
182 // scan for V-sync disabling overrides: -novsync || --novsync
183 for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); )
184 {
185 if ([arg isEqual:@"-nosplash"] || [arg isEqual:@"--nosplash"])
186 {
187 showSplashScreen = NO;
188 noSplashArgFound = YES; // -nosplash always trumps -splash
189 }
190 else if (([arg isEqual:@"-splash"] || [arg isEqual:@"--splash"]) && !noSplashArgFound)
191 {
192 showSplashScreen = YES;
193 }
194
195 // if V-sync is disabled at the command line, override the defaults file
196 if ([arg isEqual:@"-novsync"] || [arg isEqual:@"--novsync"]) vSyncPreference = NO;
197
198 if ([arg isEqual: @"-hdr"]) bitsPerColorComponent = 16;
199
200 // build the startup command string so that we can log it
201 cmdLineArgsStr = [cmdLineArgsStr stringByAppendingFormat:@"%@ ", arg];
202 }
203
204 OOLog(@"process.args", @"%@", cmdLineArgsStr);
205
206 matrixManager = [[OOOpenGLMatrixManager alloc] init];
207
208 // TODO: This code up to and including stickHandler really ought
209 // not to be in this class.
210 OOLog(@"sdl.init", @"%@", @"initialising SDL");
211 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
212 {
213 OOLog(@"sdl.init.failed", @"Unable to init SDL: %s\n", SDL_GetError());
214 [self dealloc];
215 return nil;
216 }
217
218 SDL_putenv ("SDL_VIDEO_WINDOW_POS=center");
219
221 // end TODO
222
223 [OOSound setUp];
224 if (![OOSound isSoundOK]) OOLog(@"sound.init", @"%@", @"Sound system disabled.");
225
226 // Generate the window caption, containing the version number and the date the executable was compiled.
227 static char windowCaption[128];
228 NSString *versionString = [NSString stringWithFormat:@"Oolite v%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]];
229
230 strcpy (windowCaption, [versionString UTF8String]);
231 strcat (windowCaption, " - "__DATE__);
232 SDL_WM_SetCaption (windowCaption, "Oolite"); // Set window title.
233
234#if OOLITE_WINDOWS
235 // needed for enabling system window manager events, which is needed for handling window movement messages
236 SDL_EventState (SDL_SYSWMEVENT, SDL_ENABLE);
237
238 //capture the window handle for later
239 static SDL_SysWMinfo wInfo;
240 SDL_VERSION(&wInfo.version);
241 SDL_GetWMInfo(&wInfo);
242 SDL_Window = wInfo.window;
243
244 // This must be inited after SDL_Window has been set - we need the main window handle in order to get monitor info
245 if (![self getCurrentMonitorInfo:&monitorInfo])
246 {
247 OOLogWARN(@"display.initGL.monitorInfoWarning", @"Could not get current monitor information.");
248 }
249
250 atDesktopResolution = YES;
251#endif
252
253 grabMouseStatus = NO;
254
255 imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"];
256 icon = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:@"WMicon.bmp"] UTF8String]);
257
258 if (icon != NULL)
259 {
260 colorkey = SDL_MapRGB(icon->format, 128, 0, 128);
261 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, colorkey);
262 SDL_WM_SetIcon(icon, NULL);
263 }
264 SDL_FreeSurface(icon);
265
266 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, bitsPerColorComponent);
267 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, bitsPerColorComponent);
268 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, bitsPerColorComponent);
269 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, bitsPerColorComponent);
270 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
271 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
272
273 _colorSaturation = 1.0f;
274
275 _hdrOutput = NO;
276#if OOLITE_WINDOWS
277 _hdrMaxBrightness = [prefs oo_floatForKey:@"hdr-max-brightness" defaultValue:1000.0f];
278 _hdrPaperWhiteBrightness = [prefs oo_floatForKey:@"hdr-paperwhite-brightness" defaultValue:200.0f];
279 if (bitsPerColorComponent == 16)
280 {
281 // SDL.dll built specifically for Oolite required
282 SDL_GL_SetAttribute(SDL_GL_PIXEL_TYPE_FLOAT, 1);
283 _hdrOutput = YES;
284 }
285#endif
286
287 // V-sync settings - we set here, but can only verify after SDL_SetVideoMode has been called.
288 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vSyncPreference); // V-sync on by default.
289 OOLog(@"display.initGL", @"V-Sync %@requested.", vSyncPreference ? @"" : @"not ");
290
291 /* Multisampling significantly improves graphics quality with
292 * basically no extra programming effort on our part, especially
293 * for curved surfaces like the planet, but is also expensive - in
294 * the worst case the entire scene must be rendered four
295 * times. For now it can be a hidden setting. If early testing
296 * doesn't give any problems (other than speed on low-end graphics
297 * cards) a game options entry might be useful. - CIM, 24 Aug 2013*/
298 if ([prefs oo_boolForKey:@"anti-aliasing" defaultValue:NO])
299 {
300 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
301 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
302 }
303
304 OOLog(@"display.mode.list", @"%@", @"CREATING MODE LIST");
305 [self populateFullScreenModelist];
306 currentSize = 0;
307
308 // Find what the full screen and windowed settings are.
309 fullScreen = NO;
310 [self loadFullscreenSettings];
311 [self loadWindowSize];
312
313 // Set up the drawing surface's dimensions.
314 firstScreen= (fullScreen) ? [self modeAsSize: currentSize] : currentWindowSize;
315 viewSize = firstScreen; // viewSize must be set prior to splash screen initialization
316
317 OOLog(@"display.initGL", @"Trying %d-bpcc, 24-bit depth buffer", bitsPerColorComponent);
318 [self createSurface];
319
320 if (surface == NULL)
321 {
322 // Retry with hardcoded 8 bits per color component
323 OOLog(@"display.initGL", @"%@", @"Trying 8-bpcc, 32-bit depth buffer");
324 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
325 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
326 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
327 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
328 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
329 [self createSurface];
330
331 if (surface == NULL)
332 {
333 // Still not working? One last go...
334 // Retry, allowing 16-bit contexts.
335 OOLog(@"display.initGL", @"%@", @"Trying 5-bpcc, 16-bit depth buffer");
336 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
337 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
338 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
339 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
340 // and if it's this bad, forget even trying to multisample!
341 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
342 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
343
344 [self createSurface];
345
346 if (surface == NULL)
347 {
348 char * errStr = SDL_GetError();
349 OOLogERR(@"display.mode.error", @"Could not create display surface: %s", errStr);
350#if OOLITE_WINDOWS
351 if (showSplashScreen)
352 {
353 [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"splash-screen"];
354 [[NSUserDefaults standardUserDefaults] synchronize];
355 OOLogWARN(@"display.mode.conflict",@"Possible incompatibility between the splash screen and video drivers detected.");
356 OOLogWARN(@"display.mode.conflict",@"Oolite will start without showing the splash screen from now on. Override with 'oolite.exe -splash'");
357 }
358#endif
359 exit(1);
360 }
361 }
362 }
363
364 int testAttrib = -1;
365 OOLog(@"display.initGL", @"%@", @"Achieved color / depth buffer sizes (bits):");
366 SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &testAttrib);
367 OOLog(@"display.initGL", @"Red: %d", testAttrib);
368 SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &testAttrib);
369 OOLog(@"display.initGL", @"Green: %d", testAttrib);
370 SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &testAttrib);
371 OOLog(@"display.initGL", @"Blue: %d", testAttrib);
372 SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &testAttrib);
373 OOLog(@"display.initGL", @"Alpha: %d", testAttrib);
374 SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &testAttrib);
375 OOLog(@"display.initGL", @"Depth Buffer: %d", testAttrib);
376#if OOLITE_WINDOWS
377 SDL_GL_GetAttribute(SDL_GL_PIXEL_TYPE_FLOAT, &testAttrib);
378 OOLog(@"display.initGL", @"Pixel type is float : %d", testAttrib);
379#endif
380
381 // Verify V-sync successfully set - report it if not
382 if (vSyncPreference && SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &vSyncValue) == -1)
383 {
384 OOLogWARN(@"display.initGL", @"Could not enable V-Sync. Please check that your graphics driver supports the %@_swap_control extension.",
385 OOLITE_WINDOWS ? @"WGL_EXT" : @"[GLX_SGI/GLX_MESA]");
386 }
387
388 bounds.size.width = surface->w;
389 bounds.size.height = surface->h;
390
391 [self autoShowMouse];
392
393 virtualJoystickPosition = NSMakePoint(0.0,0.0);
394 mouseWarped = NO;
395
396 typedString = [[NSMutableString alloc] initWithString:@""];
397 allowingStringInput = gvStringInputNo;
398 isAlphabetKeyDown = NO;
399
400 timeIntervalAtLastClick = timeSinceLastMouseWheel = [NSDate timeIntervalSinceReferenceDate];
401
402 _mouseWheelDelta = 0.0f;
403
404 m_glContextInitialized = NO;
405
406 return self;
407}
408
409- (void) endSplashScreen
410{
411#if OOLITE_WINDOWS
412 if ([self hdrOutput] && ![self isOutputDisplayHDREnabled])
413 {
414 if (MessageBox(NULL, "No primary display in HDR mode was detected.\n\n"
415 "If you continue, graphics will not be rendered as intended.\n"
416 "Click OK to launch anyway, or Cancel to exit.", "oolite.exe - HDR requested",
417 MB_OKCANCEL | MB_ICONWARNING) == IDCANCEL)
418 {
419 exit (1);
420 }
421 }
422#endif // OOLITE_WINDOWS
423
424 if (!showSplashScreen) return;
425
426#if OOLITE_WINDOWS
427
428 wasFullScreen = !fullScreen;
429 updateContext = YES;
430 ShowWindow(SDL_Window,SW_RESTORE);
431 [self initialiseGLWithSize: firstScreen];
432
433#else
434
435 int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL;
436
437 videoModeFlags |= (fullScreen) ? SDL_FULLSCREEN : SDL_RESIZABLE;
438 surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags);
439
440 if (!surface && fullScreen == YES)
441 {
442 [self setFullScreenMode: NO];
443 videoModeFlags &= ~SDL_FULLSCREEN;
444 videoModeFlags |= SDL_RESIZABLE;
445 surface = SDL_SetVideoMode(currentWindowSize.width, currentWindowSize.height, 32, videoModeFlags);
446 }
447
448 SDL_putenv ("SDL_VIDEO_WINDOW_POS=none"); //stop linux from auto centering on resize
449
450 /* MKW 2011.11.11
451 * Eat all SDL events to gobble up any resize events while the
452 * splash-screen was visible. They affected the main window after 1.74.
453 * TODO: should really process SDL events while showing the splash-screen
454
455 int numEvents = 0;
456 */
457 SDL_Event dummyEvent;
458 while (SDL_PollEvent(&dummyEvent))
459 {
460 /* Do nothing; the below is for development info
461 numEvents++;
462 OOLog(@"display.splash", @"Suppressed splash-screen event %d: %d ", numEvents, dummyEvent.type);
463 */
464 }
465
466
467#endif
468
469 [self updateScreen];
470 [self autoShowMouse];
471}
472
473
474- (void) initKeyMappingData
475{
476 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
477 // load in our keyboard scancode mappings
478#if OOLITE_WINDOWS
479 NSDictionary *kmap = [NSDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:@"keymappings_windows.plist" inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
480#else
481 NSDictionary *kmap = [NSDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:@"keymappings_linux.plist" inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
482#endif
483 // get the stored keyboard code from preferences
484 NSString *kbd = [prefs oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
485 NSDictionary *subset = [kmap objectForKey:kbd];
486
487 [keyMappings_normal release];
488 keyMappings_normal = [[subset objectForKey:@"mapping_normal"] copy];
489 [keyMappings_shifted release];
490 keyMappings_shifted = [[subset objectForKey:@"mapping_shifted"] copy];
491}
492
493
494- (void) dealloc
495{
496 if (typedString)
497 [typedString release];
498
499 if (screenSizes)
500 [screenSizes release];
501
502 if (surface != 0)
503 {
504 SDL_FreeSurface(surface);
505 surface = 0;
506 }
507
508 if (keyMappings_normal)
509 [keyMappings_normal release];
510
511 if (keyMappings_shifted)
512 [keyMappings_shifted release];
513
514 SDL_Quit();
515
516 if (matrixManager)
517 {
518 [matrixManager release];
519 }
520
521 [super dealloc];
522}
523
524- (void) autoShowMouse
525{
526 //don't touch the 'please wait...' cursor.
527 if (fullScreen)
528 {
529 if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)
530 SDL_ShowCursor(SDL_DISABLE);
531 }
532 else
533 {
534 if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE)
535 SDL_ShowCursor(SDL_ENABLE);
536 }
537}
538
539- (void) setStringInput: (enum StringInput) value
540{
541 allowingStringInput = value;
542}
543
544
545- (void) allowStringInput: (BOOL) value
546{
547 if (value)
548 allowingStringInput = gvStringInputAlpha;
549 else
550 allowingStringInput = gvStringInputNo;
551}
552
553-(enum StringInput) allowingStringInput
554{
555 return allowingStringInput;
556}
557
558
559- (NSString *) typedString
560{
561 return typedString;
562}
563
564
565- (void) resetTypedString
566{
567 [typedString setString:@""];
568}
569
570
571- (void) setTypedString:(NSString*) value
572{
573 [typedString setString:value];
574}
575
576
577- (NSRect) bounds
578{
579 return bounds;
580}
581
582
583- (NSSize) viewSize
584{
585 return viewSize;
586}
587
588
589- (NSSize) backingViewSize
590{
591 return viewSize;
592}
593
594
595- (GLfloat) display_z
596{
597 return display_z;
598}
599
600
601- (GLfloat) x_offset
602{
603 return x_offset;
604}
605
606
607- (GLfloat) y_offset
608{
609 return y_offset;
610}
611
612
613- (GameController *) gameController
614{
615 return gameController;
616}
617
618
619- (void) setGameController:(GameController *) controller
620{
621 gameController = controller;
622}
623
624
625- (void) noteMouseInteractionModeChangedFrom:(OOMouseInteractionMode)oldMode to:(OOMouseInteractionMode)newMode
626{
627 [self autoShowMouse];
628 [self setMouseInDeltaMode:OOMouseInteractionModeIsFlightMode(newMode)];
629}
630
631
632- (BOOL) inFullScreenMode
633{
634 return fullScreen;
635}
636
637#ifdef GNUSTEP
638- (void) setFullScreenMode:(BOOL)fsm
639{
640 fullScreen = fsm;
641
642 // Save the settings for later.
643 [[NSUserDefaults standardUserDefaults]
644 setBool: fullScreen forKey:@"fullscreen"];
645 [[NSUserDefaults standardUserDefaults] synchronize];
646}
647
648
649- (void) toggleScreenMode
650{
651 [self setFullScreenMode: !fullScreen];
652#if OOLITE_WINDOWS
653 [self getCurrentMonitorInfo:&monitorInfo];
654#endif
655 if(fullScreen)
656 {
657#if OOLITE_WINDOWS
658 if(![self isRunningOnPrimaryDisplayDevice])
659 {
660 [self initialiseGLWithSize:NSMakeSize(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
661 monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top)];
662 }
663 else [self initialiseGLWithSize:[self modeAsSize: currentSize]];
664#else
665 [self initialiseGLWithSize:[self modeAsSize: currentSize]];
666#endif
667 }
668 else
669 [self initialiseGLWithSize: currentWindowSize];
670
671
672 // do screen resizing updates
673 if ([PlayerEntity sharedPlayer])
674 {
676 }
677}
678
679
680- (void) setDisplayMode:(int)mode fullScreen:(BOOL)fsm
681{
682 [self setFullScreenMode: fsm];
683 currentSize=mode;
684 if(fullScreen)
685 [self initialiseGLWithSize: [self modeAsSize: mode]];
686}
687
688
689- (int) indexOfCurrentSize
690{
691 return currentSize;
692}
693
694
695- (void) setScreenSize: (int)sizeIndex
696{
697 currentSize=sizeIndex;
698 if(fullScreen)
699 [self initialiseGLWithSize: [self modeAsSize: currentSize]];
700}
701
702
703- (NSMutableArray *)getScreenSizeArray
704{
705 return screenSizes;
706}
707
708
709- (NSSize) modeAsSize:(int)sizeIndex
710{
711 NSDictionary *mode=[screenSizes objectAtIndex: sizeIndex];
712 return NSMakeSize([[mode objectForKey: kOODisplayWidth] intValue],
713 [[mode objectForKey: kOODisplayHeight] intValue]);
714}
715
716#endif
717
718- (void) display
719{
720 [self updateScreen];
721}
722
723- (void) updateScreen
724{
725 [self drawRect: NSMakeRect(0, 0, viewSize.width, viewSize.height)];
726}
727
728- (void) drawRect:(NSRect)rect
729{
730 [self updateScreenWithVideoMode:YES];
731}
732
733- (void) updateScreenWithVideoMode:(BOOL) v_mode
734{
735 if ((viewSize.width != surface->w)||(viewSize.height != surface->h)) // resized
736 {
737#if OOLITE_LINUX
738 m_glContextInitialized = NO; //probably not needed
739#endif
740 viewSize.width = surface->w;
741 viewSize.height = surface->h;
742 }
743
744 if (m_glContextInitialized == NO)
745 {
746 [self initialiseGLWithSize:viewSize useVideoMode:v_mode];
747 }
748
749 if (surface == 0)
750 return;
751
752 // do all the drawing!
753 //
754 if (UNIVERSE) [UNIVERSE drawUniverse];
755 else
756 {
757 // not set up yet, draw a black screen
758 glClearColor( 0.0, 0.0, 0.0, 0.0);
759 glClear( GL_COLOR_BUFFER_BIT);
760 }
761
762 SDL_GL_SwapBuffers();
763}
764
765- (void) initSplashScreen
766{
767 if (!showSplashScreen) return;
768
769 //too early for OOTexture!
770 SDL_Surface *image=NULL;
771 SDL_Rect dest;
772
773 NSString *imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"];
774
775 image = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:@"splash.bmp"] UTF8String]);
776
777 if (image == NULL)
778 {
779 SDL_FreeSurface(image);
780 OOLogWARN(@"sdl.gameStart", @"%@", @"image 'splash.bmp' not found!");
781 [self endSplashScreen];
782 return;
783 }
784
785 dest.x = 0;
786 dest.y = 0;
787 dest.w = image->w;
788 dest.h = image->h;
789
790 #if OOLITE_WINDOWS
791
792 dest.x = (GetSystemMetrics(SM_CXSCREEN)- dest.w)/2;
793 dest.y = (GetSystemMetrics(SM_CYSCREEN)-dest.h)/2;
794 SetWindowLong(SDL_Window,GWL_STYLE,GetWindowLong(SDL_Window,GWL_STYLE) & ~WS_CAPTION & ~WS_THICKFRAME);
795 ShowWindow(SDL_Window,SW_RESTORE);
796 MoveWindow(SDL_Window,dest.x,dest.y,dest.w,dest.h,TRUE);
797
798 #else
799
800 /* MKW 2011.11.11
801 * According to Marc using the NOFRAME flag causes trouble under Ubuntu 8.04.
802 *
803 * The current Ubuntu LTS is 10.04, which doesn't seem to have that problem.
804 * 12.04 LTS is going to be released soon, also without apparent problems.
805 * Changed to SDL_NOFRAME, throwing caution to the wind - Kaks 2012.03.23
806 * Took SDL_NOFRAME out, since it still causes strange problems here - cim 2012.04.09
807 */
808 surface = SDL_SetVideoMode(dest.w, dest.h, 32, SDL_HWSURFACE | SDL_OPENGL);
809
810 #endif
811
813
814 glViewport( 0, 0, dest.w, dest.h);
815
816 glEnable( GL_TEXTURE_2D );
817 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
818 glClear( GL_COLOR_BUFFER_BIT );
819
820 [matrixManager resetProjection];
821 [matrixManager orthoLeft: 0.0f right: dest.w bottom: dest.h top: 0.0 near: -1.0 far: 1.0];
822 [matrixManager syncProjection];
823
824 [matrixManager resetModelView];
825 [matrixManager syncModelView];
826
827 GLuint texture;
828 GLenum texture_format;
829 GLint nOfColors;
830
831 // get the number of channels in the SDL image
832 nOfColors = image->format->BytesPerPixel;
833 if (nOfColors == 4) // contains an alpha channel
834 {
835 if (image->format->Rmask == 0x000000ff)
836 texture_format = GL_RGBA;
837 else
838 texture_format = GL_BGRA;
839 }
840 else if (nOfColors == 3) // no alpha channel
841 {
842 if (image->format->Rmask == 0x000000ff)
843 texture_format = GL_RGB;
844 else
845 texture_format = GL_BGR;
846 } else {
847 SDL_FreeSurface(image);
848 OOLog(@"Sdl.GameStart", @"%@", @"----- Encoding error within image 'splash.bmp'");
849 [self endSplashScreen];
850 return;
851 }
852
853 glGenTextures( 1, &texture );
854 glBindTexture( GL_TEXTURE_2D, texture );
855
856 // Set the texture's stretching properties
857 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
858 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
859
860 // Set the texture image data with the information from SDL_Surface
861 glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, image->w, image->h, 0,
862 texture_format, GL_UNSIGNED_BYTE, image->pixels );
863
864 glBindTexture( GL_TEXTURE_2D, texture );
865 glBegin( GL_QUADS );
866
867 glTexCoord2i( 0, 0 );
868 glVertex2i( 0, 0 );
869 glTexCoord2i( 1, 0 );
870 glVertex2i( dest.w, 0 );
871 glTexCoord2i( 1, 1 );
872 glVertex2i( dest.w, dest.h );
873 glTexCoord2i( 0, 1 );
874 glVertex2i( 0, dest.h );
875
876 glEnd();
877
878 SDL_GL_SwapBuffers();
879 [matrixManager resetModelView];
880 [matrixManager syncModelView];
881
882 if ( image ) {
883 SDL_FreeSurface( image );
884 }
885 glDeleteTextures(1, &texture);
886
887 glDisable( GL_TEXTURE_2D );
889}
890
891
892#if OOLITE_WINDOWS
893- (MONITORINFOEX) currentMonitorInfo
894{
895 return monitorInfo;
896}
897
898
899- (BOOL) getCurrentMonitorInfo:(MONITORINFOEX *)mInfo
900{
901 HMONITOR hMon = MonitorFromWindow(SDL_Window, MONITOR_DEFAULTTOPRIMARY);
902 ZeroMemory(mInfo, sizeof(MONITORINFOEX));
903 mInfo->cbSize = sizeof(MONITORINFOEX);
904 if (GetMonitorInfo (hMon, (LPMONITORINFO)mInfo))
905 {
906 return YES;
907 }
908 return NO;
909}
910
911
912- (BOOL) isRunningOnPrimaryDisplayDevice
913{
914 BOOL result = YES;
915 [self getCurrentMonitorInfo:&monitorInfo];
916 if (!(monitorInfo.dwFlags & MONITORINFOF_PRIMARY))
917 {
918 result = NO;
919 }
920 return result;
921}
922
923
924- (void) grabMouseInsideGameWindow:(BOOL) value
925{
926 if(value)
927 {
928 RECT gameWindowRect;
929 GetWindowRect(SDL_Window, &gameWindowRect);
930 ClipCursor(&gameWindowRect);
931 }
932 else
933 {
934 ClipCursor(NULL);
935 }
936 grabMouseStatus = !!value;
937}
938
939
940- (void) stringToClipboard:(NSString *)stringToCopy
941{
942 if (stringToCopy)
943 {
944 const char *clipboardText = [stringToCopy cStringUsingEncoding:NSUTF8StringEncoding];
945 const size_t clipboardTextLength = strlen(clipboardText) + 1;
946 HGLOBAL clipboardMem = GlobalAlloc(GMEM_MOVEABLE, clipboardTextLength);
947 if (clipboardMem)
948 {
949 memcpy(GlobalLock(clipboardMem), clipboardText, clipboardTextLength);
950 GlobalUnlock(clipboardMem);
951 OpenClipboard(0);
952 EmptyClipboard();
953 if (!SetClipboardData(CF_TEXT, clipboardMem))
954 {
955 OOLog(@"stringToClipboard.failed", @"Failed to copy string %@ to clipboard", stringToCopy);
956 // free global allocated memory if clipboard copy failed
957 // note: no need to free it if copy succeeded; the OS becomes
958 // the owner of the copied memory once SetClipboardData has
959 // been executed successfully
960 GlobalFree(clipboardMem);
961 }
962 CloseClipboard();
963 }
964 }
965}
966
967
969{
970 // this is used when we regain focus to ensure that all
971 // modifier keys are reset to their correct status
972 SDLMod modState = SDL_GetModState();
973 Uint8 *keyState = SDL_GetKeyState(NULL);
974 BYTE keyboardStatus[256];
975 #define OO_RESET_SDLKEY_MODIFIER(vkCode, kModCode, sdlkCode) do {\
976 if (keyboardStatus[vkCode] & 0x0080) \
977 { \
978 modState |= kModCode; \
979 keyState[sdlkCode] = SDL_PRESSED; \
980 } \
981 else \
982 { \
983 modState &= ~kModCode; \
984 keyState[sdlkCode] = SDL_RELEASED; \
985 } \
986 } while(0)
987 if (GetKeyboardState(keyboardStatus))
988 {
989 // A bug noted here https://github.com/libsdl-org/SDL-1.2/issues/449
990 // was patched in SDL here https://github.com/libsdl-org/SDL-1.2/commit/09980c67290f11c3d088a6a039c550be83536c81
991 // This was replicated in our SDL binary (Windows-deps rev. 36fd5e6),
992 // so we no longer need to check the state of Alt when returning to the app.
993 // SDL change researched and implemented by Nikos 20220622.
994 // Alt key
995 //OO_RESET_SDLKEY_MODIFIER(VK_LMENU, KMOD_LALT, SDLK_LALT);
996 //OO_RESET_SDLKEY_MODIFIER(VK_RMENU, KMOD_RALT, SDLK_RALT);
997 //opt = (modState & KMOD_LALT || modState & KMOD_RALT);
998
999 //Ctrl key
1000 OO_RESET_SDLKEY_MODIFIER(VK_LCONTROL, KMOD_LCTRL, SDLK_LCTRL);
1001 OO_RESET_SDLKEY_MODIFIER(VK_RCONTROL, KMOD_RCTRL, SDLK_RCTRL);
1002 ctrl = (modState & KMOD_LCTRL || modState & KMOD_RCTRL);
1003
1004 // Shift key
1005 OO_RESET_SDLKEY_MODIFIER(VK_LSHIFT, KMOD_LSHIFT, SDLK_LSHIFT);
1006 OO_RESET_SDLKEY_MODIFIER(VK_RSHIFT, KMOD_RSHIFT, SDLK_RSHIFT);
1007 shift = (modState & KMOD_LSHIFT || modState & KMOD_RSHIFT);
1008
1009 // Caps Lock key state
1010 if (GetKeyState(VK_CAPITAL) & 0x0001)
1011 {
1012 modState |= KMOD_CAPS;
1013 keyState[SDLK_CAPSLOCK] = SDL_PRESSED;
1014 }
1015 else
1016 {
1017 modState &= ~KMOD_CAPS;
1018 keyState[SDLK_CAPSLOCK] = SDL_RELEASED;
1019 }
1020 }
1021
1022 SDL_SetModState(modState);
1023}
1024
1025
1026- (void) setWindowBorderless:(BOOL)borderless
1027{
1028 LONG currentWindowStyle = GetWindowLong(SDL_Window, GWL_STYLE);
1029
1030 // window already has the desired style?
1031 if ((!borderless && (currentWindowStyle & WS_CAPTION)) ||
1032 (borderless && !(currentWindowStyle & WS_CAPTION))) return;
1033
1034 if (borderless)
1035 {
1036 SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle & ~WS_CAPTION & ~WS_THICKFRAME);
1037 }
1038 else
1039 {
1040 SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle |
1041 WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX );
1042 [self refreshDarKOrLightMode];
1043 }
1044 SetWindowPos(SDL_Window, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
1045}
1046
1047
1048- (void) refreshDarKOrLightMode
1049{
1050 int shouldSetDarkMode = [self isDarkModeOn];
1051 DwmSetWindowAttribute (SDL_Window, DWMWA_USE_IMMERSIVE_DARK_MODE, &shouldSetDarkMode, sizeof(shouldSetDarkMode));
1052}
1053
1054
1055- (BOOL) isDarkModeOn
1056{
1057 char buffer[4];
1058 DWORD bufferSize = sizeof(buffer);
1059
1060 // reading a REG_DWORD value from the Registry
1061 HRESULT resultRegGetValue = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
1062 L"AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, buffer, &bufferSize);
1063 if (resultRegGetValue != ERROR_SUCCESS)
1064 {
1065 return NO;
1066 }
1067
1068 // get our 4 obtained bytes into integer little endian format
1069 int i = (int)(buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]);
1070
1071 // dark mode is 0, light mode is 1
1072 return i == 0;
1073}
1074
1075
1076- (BOOL) atDesktopResolution
1077{
1078 return atDesktopResolution;
1079}
1080
1081
1082- (BOOL) hdrOutput
1083{
1084 return _hdrOutput;
1085}
1086
1087
1088- (BOOL) isOutputDisplayHDREnabled
1089{
1090 UINT32 pathCount, modeCount;
1091 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
1092 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
1093 UINT32 flags = QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE;
1094 LONG tempResult = ERROR_SUCCESS;
1095 BOOL result = NO;
1096
1097 do
1098 {
1099 // determine how many path and mode structures to allocate
1100 tempResult = GetDisplayConfigBufferSizes(flags, &pathCount, &modeCount);
1101
1102 if (tempResult != ERROR_SUCCESS)
1103 {
1104 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: %d", HRESULT_FROM_WIN32(tempResult));
1105 return NO;
1106 }
1107
1108 // allocate the path and mode arrays
1109 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pathCount * sizeof(DISPLAYCONFIG_PATH_INFO));
1110 if (!pPathInfoArray)
1111 {
1112 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: -1");
1113 return NO;
1114 }
1115
1116 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(modeCount * sizeof(DISPLAYCONFIG_MODE_INFO));
1117 if (!pModeInfoArray)
1118 {
1119 if (pPathInfoArray)
1120 free(pPathInfoArray);
1121 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: -1");
1122 return NO;
1123 }
1124
1125 // get all active paths and their modes
1126 tempResult = QueryDisplayConfig(flags, &pathCount, pPathInfoArray, &modeCount, pModeInfoArray, NULL);
1127
1128 if (tempResult != ERROR_SUCCESS)
1129 {
1130 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: %d", HRESULT_FROM_WIN32(tempResult));
1131 return NO;
1132 }
1133
1134 // the function may have returned fewer paths/modes than estimated
1135 pPathInfoArray = realloc(pPathInfoArray, pathCount * sizeof(DISPLAYCONFIG_PATH_INFO));
1136 if (!pPathInfoArray)
1137 {
1138 OOLogERR(@"gameView.isOutputDisplayHDREnabled", @"Failed ro reallocate pPathInfoArray");
1139 exit (1);
1140 }
1141 pModeInfoArray = realloc(pModeInfoArray, modeCount * sizeof(DISPLAYCONFIG_MODE_INFO));
1142 if (!pModeInfoArray)
1143 {
1144 OOLogERR(@"gameView.isOutputDisplayHDREnabled", @"Failed to reallocate pModeInfoArray");
1145 exit (1);
1146 }
1147
1148 // it's possible that between the call to GetDisplayConfigBufferSizes and QueryDisplayConfig
1149 // that the display state changed, so loop on the case of ERROR_INSUFFICIENT_BUFFER.
1150 } while (tempResult == ERROR_INSUFFICIENT_BUFFER);
1151
1152 if (tempResult != ERROR_SUCCESS)
1153 {
1154 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: %d", HRESULT_FROM_WIN32(tempResult));
1155 return NO;
1156 }
1157
1158 // for each active path
1159 int i;
1160 for (i = 0; i < pathCount; i++)
1161 {
1162 DISPLAYCONFIG_PATH_INFO *path = &pPathInfoArray[i];
1163 // find the target (monitor) friendly name
1164 DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
1165 targetName.header.adapterId = path->targetInfo.adapterId;
1166 targetName.header.id = path->targetInfo.id;
1167 targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
1168 targetName.header.size = sizeof(targetName);
1169 tempResult = DisplayConfigGetDeviceInfo(&targetName.header);
1170
1171 if (tempResult != ERROR_SUCCESS)
1172 {
1173 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: %d", HRESULT_FROM_WIN32(tempResult));
1174 return NO;
1175 }
1176
1177 // find the advanced color information
1178 DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = {};
1179 advColorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
1180 advColorInfo.header.adapterId = path->targetInfo.adapterId;
1181 advColorInfo.header.id = path->targetInfo.id;
1182 advColorInfo.header.size = sizeof(advColorInfo);
1183
1184 tempResult = DisplayConfigGetDeviceInfo(&advColorInfo.header);
1185
1186 if (tempResult != ERROR_SUCCESS)
1187 {
1188 OOLog(@"gameView.isOutputDisplayHDREnabled", @"Error! Code: %d", HRESULT_FROM_WIN32(tempResult));
1189 return NO;
1190 }
1191
1192 char saveDeviceName[64];
1193 wchar_t wcsDeviceID[256];
1194 DISPLAY_DEVICE dd;
1195 ZeroMemory(&dd, sizeof(dd));
1196 dd.cb = sizeof(dd);
1197 EnumDisplayDevices(NULL, i, &dd, 0);
1198 BOOL isPrimaryDisplayDevice = dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE;
1199 // second call to EnumDisplayDevices gets us the monitor device ID
1200 strncpy(saveDeviceName, dd.DeviceName, 33);
1201 EnumDisplayDevices(saveDeviceName, 0, &dd, 0x00000001);
1202 mbstowcs(wcsDeviceID, dd.DeviceID, 129);
1203
1204 // we are starting om the primary device, so check that one for advanced color support
1205 // we also ensure that wide color gamut SDR displays do not get incorrectly detected as supporting HDR
1206 // just to be safe, ensure that the monitor device from QDC being checked is the same as the one from EnumDisplayDevices
1207 if (isPrimaryDisplayDevice && !wcscmp(targetName.monitorDevicePath, wcsDeviceID) &&
1208 advColorInfo.advancedColorSupported && advColorInfo.advancedColorEnabled && !advColorInfo.wideColorEnforced)
1209 {
1210 result = YES;
1211 break;
1212 }
1213 }
1214
1215 OOLog(@"gameView.isOutputDisplayHDREnabled", @"HDR display output requested - checking availability: %@", result ? @"YES" : @"NO");
1216
1217 free (pModeInfoArray);
1218 free (pPathInfoArray);
1219
1220 return result;
1221}
1222
1223
1224- (float) hdrMaxBrightness
1225{
1226 return _hdrMaxBrightness;
1227}
1228
1229
1230- (void) setHDRMaxBrightness: (float)newMaxBrightness
1231{
1232 if (newMaxBrightness < MIN_HDR_MAXBRIGHTNESS) newMaxBrightness = MIN_HDR_MAXBRIGHTNESS;
1233 if (newMaxBrightness > MAX_HDR_MAXBRIGHTNESS) newMaxBrightness = MAX_HDR_MAXBRIGHTNESS;
1234 _hdrMaxBrightness = newMaxBrightness;
1235
1236 [[NSUserDefaults standardUserDefaults] setFloat:_hdrMaxBrightness forKey:@"hdr-max-brightness"];
1237}
1238
1239
1240- (float) hdrPaperWhiteBrightness
1241{
1242 return _hdrPaperWhiteBrightness;
1243}
1244
1245
1246- (void) setHDRPaperWhiteBrightness: (float)newPaperWhiteBrightness
1247{
1248 if (newPaperWhiteBrightness < MIN_HDR_PAPERWHITE) newPaperWhiteBrightness = MIN_HDR_PAPERWHITE;
1249 if (newPaperWhiteBrightness > MAX_HDR_PAPERWHITE) newPaperWhiteBrightness = MAX_HDR_PAPERWHITE;
1250 _hdrPaperWhiteBrightness = newPaperWhiteBrightness;
1251
1252 [[NSUserDefaults standardUserDefaults] setFloat:_hdrPaperWhiteBrightness forKey:@"hdr-paperwhite-brightness"];
1253}
1254
1255
1256#else // Linus stub methods
1257
1258// for Linux we assume we are always on the primary monitor for now
1259- (BOOL) isRunningOnPrimaryDisplayDevice
1260{
1261 return YES;
1262}
1263
1264
1265- (void) grabMouseInsideGameWindow:(BOOL) value
1266{
1267 // do nothing
1268}
1269
1270
1271- (void) stringToClipboard:(NSString *)stringToCopy
1272{
1273 // TODO: implement string clipboard copy for Linux
1274}
1275
1276
1277- (void) resetSDLKeyModifiers
1278{
1279 // probably not needed for Linux
1280}
1281
1282
1283- (void) setWindowBorderless:(BOOL)borderless
1284{
1285 // do nothing on Linux
1286}
1287
1288
1289- (BOOL) hdrOutput
1290{
1291 return NO;
1292}
1293
1294
1295- (BOOL) isOutputDisplayHDREnabled
1296{
1297 return NO;
1298}
1299
1300#endif //OOLITE_WINDOWS
1301
1302
1303- (void) initialiseGLWithSize:(NSSize) v_size
1304{
1305 [self initialiseGLWithSize:v_size useVideoMode:YES];
1306}
1307
1308
1309- (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode
1310{
1311#if OOLITE_LINUX
1312 NSSize oldViewSize = viewSize;
1313#endif
1314 viewSize = v_size;
1315 OOLog(@"display.initGL", @"Requested a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed"));
1316 SDL_GL_SwapBuffers(); // clear the buffer before resize
1317
1318#if OOLITE_WINDOWS
1319 if (!updateContext) return;
1320
1321 DEVMODE settings;
1322 settings.dmSize = sizeof(DEVMODE);
1323 settings.dmDriverExtra = 0;
1324 EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &settings);
1325
1326 WINDOWPLACEMENT windowPlacement;
1327 windowPlacement.length = sizeof(WINDOWPLACEMENT);
1328 GetWindowPlacement(SDL_Window, &windowPlacement);
1329
1330 static BOOL lastWindowPlacementMaximized = NO;
1331 if (fullScreen && (windowPlacement.showCmd == SW_SHOWMAXIMIZED))
1332 {
1333 if (!wasFullScreen)
1334 {
1335 lastWindowPlacementMaximized = YES;
1336 }
1337 }
1338
1339 if (lastWindowPlacementMaximized)
1340 {
1341 windowPlacement.showCmd = SW_SHOWMAXIMIZED;
1342 }
1343
1344 // are we attempting to go to a different screen resolution? Note: this also takes care of secondary monitor situations because
1345 // by design the only resolution available for fullscreen on a secondary display device is its native one - Nikos 20150605
1346 BOOL changingResolution = [self isRunningOnPrimaryDisplayDevice] &&
1347 ((fullScreen && (settings.dmPelsWidth != viewSize.width || settings.dmPelsHeight != viewSize.height)) ||
1348 (wasFullScreen && (settings.dmPelsWidth != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayWidth] intValue]
1349 || settings.dmPelsHeight != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayHeight] intValue])));
1350
1351 RECT wDC;
1352
1353 if (fullScreen)
1354 {
1355 /*NOTE: If we ever decide to change the default behaviour of launching
1356 always on primary monitor to launching on the monitor the program was
1357 started on, all that needs to be done is comment out the line below, as
1358 well as the identical one in the else branch further down.
1359 Nikos 20141222
1360 */
1361 [self getCurrentMonitorInfo: &monitorInfo];
1362
1363 settings.dmPelsWidth = viewSize.width;
1364 settings.dmPelsHeight = viewSize.height;
1365 settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
1366
1367 // just before going fullscreen, save the location of the current window. It
1368 // may be needed in case of potential attempts to move our fullscreen window
1369 // in a maximized state (yes, in Windows this is entirely possible).
1370 if(lastWindowPlacementMaximized)
1371 {
1372 CopyRect(&lastGoodRect, &windowPlacement.rcNormalPosition);
1373 // if maximized, switch to normal placement before going full screen
1374 windowPlacement.showCmd = SW_SHOWNORMAL;
1375 SetWindowPlacement(SDL_Window, &windowPlacement);
1376 }
1377 else GetWindowRect(SDL_Window, &lastGoodRect);
1378
1379 // ok, can go fullscreen now
1380 SetForegroundWindow(SDL_Window);
1381 if (changingResolution)
1382 {
1383 if (ChangeDisplaySettingsEx(monitorInfo.szDevice, &settings, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
1384 {
1385 m_glContextInitialized = YES;
1386 OOLogERR(@"displayMode.change.error", @"Could not switch to requested display mode.");
1387 return;
1388 }
1389 atDesktopResolution = settings.dmPelsWidth == [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayWidth] intValue]
1390 && settings.dmPelsHeight == [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayHeight] intValue];
1391 }
1392
1393 MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (int)viewSize.width, (int)viewSize.height, TRUE);
1394 if(!wasFullScreen)
1395 {
1396 [self setWindowBorderless:YES];
1397 }
1398 }
1399
1400 else if ( wasFullScreen )
1401 {
1402 if (changingResolution)
1403 {
1404 // restore original desktop resolution
1405 if (ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL) == DISP_CHANGE_SUCCESSFUL)
1406 {
1407 atDesktopResolution = YES;
1408 }
1409 }
1410
1411 /*NOTE: If we ever decide to change the default behaviour of launching
1412 always on primary monitor to launching on the monitor the program was
1413 started on, we need to comment out the line below.
1414 For now, this line is needed for correct positioning of our window in case
1415 we return from a non-native resolution fullscreen and has to come after the
1416 display settings have been reverted.
1417 Nikos 20141222
1418 */
1419 [self getCurrentMonitorInfo: &monitorInfo];
1420
1421 if (lastWindowPlacementMaximized) CopyRect(&windowPlacement.rcNormalPosition, &lastGoodRect);
1422 SetWindowPlacement(SDL_Window, &windowPlacement);
1423 if (!lastWindowPlacementMaximized)
1424 {
1425 MoveWindow(SDL_Window, (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left - (int)viewSize.width)/2 +
1426 monitorInfo.rcMonitor.left,
1427 (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top - (int)viewSize.height)/2 +
1428 monitorInfo.rcMonitor.top,
1429 (int)viewSize.width, (int)viewSize.height, TRUE);
1430 }
1431
1432 [self setWindowBorderless:NO];
1433
1434 lastWindowPlacementMaximized = NO;
1435 ShowWindow(SDL_Window,SW_SHOW);
1436 }
1437
1438 // stop saveWindowSize from reacting to caption & frame if necessary
1439 saveSize = !wasFullScreen;
1440
1441 GetClientRect(SDL_Window, &wDC);
1442
1443 if (!fullScreen && (bounds.size.width != wDC.right - wDC.left
1444 || bounds.size.height != wDC.bottom - wDC.top))
1445 {
1446 // Resize the game window if needed. When we ask for a W x H
1447 // window, we intend that the client area be W x H. The actual
1448 // window itself must become big enough to accomodate an area
1449 // of such size.
1450 if (wasFullScreen) // this is true when switching from full screen or when starting in windowed mode
1451 //after the splash screen has ended
1452 {
1453 RECT desiredClientRect;
1454 GetWindowRect(SDL_Window, &desiredClientRect);
1455 AdjustWindowRect(&desiredClientRect, WS_CAPTION | WS_THICKFRAME, FALSE);
1456 SetWindowPos(SDL_Window, NULL, desiredClientRect.left, desiredClientRect.top,
1457 desiredClientRect.right - desiredClientRect.left,
1458 desiredClientRect.bottom - desiredClientRect.top, 0);
1459 }
1460 GetClientRect(SDL_Window, &wDC);
1461 viewSize.width = wDC.right - wDC.left;
1462 viewSize.height = wDC.bottom - wDC.top;
1463 }
1464
1465 // Reset bounds and viewSize to current values
1466 bounds.size.width = viewSize.width = wDC.right - wDC.left;
1467 bounds.size.height = viewSize.height = wDC.bottom - wDC.top;
1468
1469 if (fullScreen) // bounds on fullscreen coincide with client area, since we are borderless
1470 {
1471 bounds.origin.x = monitorInfo.rcMonitor.left;
1472 bounds.origin.y = monitorInfo.rcMonitor.top;
1473 }
1474 wasFullScreen=fullScreen;
1475
1476#else //OOLITE_LINUX
1477
1478 int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL;
1479
1480 if (v_mode == NO)
1481 videoModeFlags |= SDL_NOFRAME;
1482 if (fullScreen == YES)
1483 {
1484 videoModeFlags |= SDL_FULLSCREEN;
1485 }
1486 else
1487 {
1488 videoModeFlags |= SDL_RESIZABLE;
1489 }
1490 surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags);
1491
1492 if (!surface && fullScreen == YES)
1493 {
1494 [self setFullScreenMode: NO];
1495 viewSize = oldViewSize;
1496 videoModeFlags &= ~SDL_FULLSCREEN;
1497 videoModeFlags |= SDL_RESIZABLE;
1498 surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags);
1499 }
1500
1501 if (!surface)
1502 {
1503 // we should always have a valid surface, but in case we don't
1504 OOLogERR(@"display.mode.error",@"Unable to change display mode: %s",SDL_GetError());
1505 exit(1);
1506 }
1507
1508 bounds.size.width = surface->w;
1509 bounds.size.height = surface->h;
1510
1511#endif
1512 OOLog(@"display.initGL", @"Created a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed"));
1513
1514 if (viewSize.width/viewSize.height > 4.0/3.0) {
1515 display_z = 480.0 * bounds.size.width/bounds.size.height;
1516 x_offset = 240.0 * bounds.size.width/bounds.size.height;
1517 y_offset = 240.0;
1518 } else {
1519 display_z = 640.0;
1520 x_offset = 320.0;
1521 y_offset = 320.0 * bounds.size.height/bounds.size.width;
1522 }
1523
1524 if (surface != 0) SDL_FreeSurface(surface);
1525
1526 [self autoShowMouse];
1527
1528 [[self gameController] setUpBasicOpenGLStateWithSize:viewSize];
1529 SDL_GL_SwapBuffers();
1530 squareX = 0.0f;
1531
1532 m_glContextInitialized = YES;
1533}
1534
1535
1536- (float) colorSaturation
1537{
1538 return _colorSaturation;
1539}
1540
1541
1542- (void) adjustColorSaturation:(float)colorSaturationAdjustment;
1543{
1544 _colorSaturation += colorSaturationAdjustment;
1545 _colorSaturation = OOClamp_0_max_f(_colorSaturation, MAX_COLOR_SATURATION);
1546}
1547
1548
1549- (BOOL) snapShot:(NSString *)filename
1550{
1551 BOOL snapShotOK = YES;
1552 SDL_Surface* tmpSurface;
1553
1554 // backup the previous directory
1555 NSString* originalDirectory = [[NSFileManager defaultManager] currentDirectoryPath];
1556 // use the snapshots directory
1557 [[NSFileManager defaultManager] chdirToSnapshotPath];
1558
1559 BOOL withFilename = (filename != nil);
1560 static unsigned imageNo = 0;
1561 unsigned tmpImageNo = 0;
1562 NSString *pathToPic = nil;
1563 NSString *baseName = @"oolite";
1564
1565#if SNAPSHOTS_PNG_FORMAT
1566 NSString *extension = @".png";
1567#else
1568 NSString *extension = @".bmp";
1569#endif
1570
1571 if (withFilename)
1572 {
1573 baseName = filename;
1574 pathToPic = [filename stringByAppendingString:extension];
1575 }
1576 else
1577 {
1578 tmpImageNo = imageNo;
1579 }
1580
1581 if (withFilename && [[NSFileManager defaultManager] fileExistsAtPath:pathToPic])
1582 {
1583 OOLog(@"screenshot.filenameExists", @"Snapshot \"%@%@\" already exists - adding numerical sequence.", pathToPic, extension);
1584 pathToPic = nil;
1585 }
1586
1587 if (pathToPic == nil)
1588 {
1589 do
1590 {
1591 tmpImageNo++;
1592 pathToPic = [NSString stringWithFormat:@"%@-%03d%@", baseName, tmpImageNo, extension];
1593 } while ([[NSFileManager defaultManager] fileExistsAtPath:pathToPic]);
1594 }
1595
1596 if (!withFilename)
1597 {
1598 imageNo = tmpImageNo;
1599 }
1600
1601 OOLog(@"screenshot", @"Saved screen shot \"%@\" (%u x %u pixels).", pathToPic, surface->w, surface->h);
1602
1603 int pitch = surface->w * 3;
1604 unsigned char *pixls = malloc(pitch * surface->h);
1605 int y;
1606 int off;
1607
1608 if (surface->w % 4) glPixelStorei(GL_PACK_ALIGNMENT,1);
1609 else glPixelStorei(GL_PACK_ALIGNMENT,4);
1610 for (y=surface->h-1, off=0; y>=0; y--, off+=pitch)
1611 {
1612 glReadPixels(0, y, surface->w, 1, GL_RGB, GL_UNSIGNED_BYTE, pixls + off);
1613 }
1614
1615 tmpSurface=SDL_CreateRGBSurfaceFrom(pixls,surface->w,surface->h,24,surface->w*3,0xFF,0xFF00,0xFF0000,0x0);
1616#if SNAPSHOTS_PNG_FORMAT
1617 if(![self pngSaveSurface:pathToPic withSurface:tmpSurface])
1618 {
1619 OOLog(@"screenshotPNG", @"Failed to save %@", pathToPic);
1620 snapShotOK = NO;
1621 }
1622#else
1623 if (SDL_SaveBMP(tmpSurface, [pathToPic UTF8String]) == -1)
1624 {
1625 OOLog(@"screenshotBMP", @"Failed to save %@", pathToPic);
1626 snapShotOK = NO;
1627 }
1628#endif
1629 SDL_FreeSurface(tmpSurface);
1630 free(pixls);
1631
1632 // if outputting HDR signal, save also a Radiance .hdr snapshot
1633 if ([self hdrOutput])
1634 {
1635 NSString *pathToPicHDR = [pathToPic stringByReplacingString:@".png" withString:@".hdr"];
1636 OOLog(@"screenshot", @"Saved screen shot \"%@\" (%u x %u pixels).", pathToPicHDR, surface->w, surface->h);
1637 GLfloat *pixlsf = (GLfloat *)malloc(pitch * surface->h * sizeof(GLfloat));
1638 for (y=surface->h-1, off=0; y>=0; y--, off+=pitch)
1639 {
1640 glReadPixels(0, y, surface->w, 1, GL_RGB, GL_FLOAT, pixlsf + off);
1641 }
1642 if (!stbi_write_hdr([pathToPicHDR cStringUsingEncoding:NSUTF8StringEncoding], surface->w, surface->h, 3, pixlsf))
1643 {
1644 OOLog(@"screenshotHDR", @"Failed to save %@", pathToPicHDR);
1645 snapShotOK = NO;
1646 }
1647 free(pixlsf);
1648 }
1649
1650 // return to the previous directory
1651 [[NSFileManager defaultManager] changeCurrentDirectoryPath:originalDirectory];
1652 return snapShotOK;
1653}
1654
1655
1656#if SNAPSHOTS_PNG_FORMAT
1657// This method is heavily based on 'Mars, Land of No Mercy' SDL examples, by Angelo "Encelo" Theodorou, see http://encelo.netsons.org/programming/sdl
1658- (BOOL) pngSaveSurface:(NSString *)fileName withSurface:(SDL_Surface *)surf
1659{
1660 FILE *fp;
1661 png_structp pngPtr;
1662 png_infop infoPtr;
1663 int i, colorType;
1664 png_bytep *rowPointers;
1665
1666 fp = fopen([fileName UTF8String], "wb");
1667 if (fp == NULL)
1668 {
1669 OOLog(@"pngSaveSurface.fileCreate.failed", @"Failed to create output screenshot file %@", fileName);
1670 return NO;
1671 }
1672
1673 // initialize png structures (no callbacks)
1674 pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1675 if (pngPtr == NULL)
1676 {
1677 return NO;
1678 }
1679
1680 infoPtr = png_create_info_struct(pngPtr);
1681 if (infoPtr == NULL) {
1682 png_destroy_write_struct(&pngPtr, (png_infopp)NULL);
1683 OOLog(@"pngSaveSurface.info_struct.failed", @"%@", @"png_create_info_struct error");
1684 exit(-1);
1685 }
1686
1687 if (setjmp(png_jmpbuf(pngPtr)))
1688 {
1689 png_destroy_write_struct(&pngPtr, &infoPtr);
1690 fclose(fp);
1691 exit(-1);
1692 }
1693
1694 png_init_io(pngPtr, fp);
1695
1696 colorType = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
1697 if (surf->format->palette)
1698 {
1699 colorType |= PNG_COLOR_MASK_PALETTE;
1700 }
1701 else if (surf->format->Amask)
1702 {
1703 colorType |= PNG_COLOR_MASK_ALPHA;
1704 }
1705
1706 png_set_IHDR(pngPtr, infoPtr, surf->w, surf->h, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1707
1708 // if we are outputting HDR, our backbuffer is linear, so gamma is 1.0. Make sure our png has this info
1709 // note: some image viewers seem to ignore the gAMA chunk; still, this is better than not having it at all
1710 if ([self hdrOutput]) png_set_gAMA(pngPtr, infoPtr, 1.0f);
1711
1712 // write the image
1713 png_write_info(pngPtr, infoPtr);
1714 png_set_packing(pngPtr);
1715
1716 rowPointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h);
1717 for (i = 0; i < surf->h; i++)
1718 {
1719 rowPointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch;
1720 }
1721 png_write_image(pngPtr, rowPointers);
1722 png_write_end(pngPtr, infoPtr);
1723
1724 free(rowPointers);
1725 png_destroy_write_struct(&pngPtr, &infoPtr);
1726 fclose(fp);
1727
1728 return YES;
1729}
1730#endif // SNAPSHOTS_PNG_FORMAT
1731
1732
1733/* Turn the Cocoa ArrowKeys into our arrow key constants. */
1734- (int) translateKeyCode: (int) input
1735{
1736 int key = input;
1737 switch ( input )
1738 {
1739 case NSUpArrowFunctionKey:
1740 key = gvArrowKeyUp;
1741 break;
1742
1743 case NSDownArrowFunctionKey:
1744 key = gvArrowKeyDown;
1745 break;
1746
1747 case NSLeftArrowFunctionKey:
1748 key = gvArrowKeyLeft;
1749 break;
1750
1751 case NSRightArrowFunctionKey:
1752 key = gvArrowKeyRight;
1753 break;
1754
1755 case NSF1FunctionKey:
1756 key = gvFunctionKey1;
1757 break;
1758
1759 case NSF2FunctionKey:
1760 key = gvFunctionKey2;
1761 break;
1762
1763 case NSF3FunctionKey:
1764 key = gvFunctionKey3;
1765 break;
1766
1767 case NSF4FunctionKey:
1768 key = gvFunctionKey4;
1769 break;
1770
1771 case NSF5FunctionKey:
1772 key = gvFunctionKey5;
1773 break;
1774
1775 case NSF6FunctionKey:
1776 key = gvFunctionKey6;
1777 break;
1778
1779 case NSF7FunctionKey:
1780 key = gvFunctionKey7;
1781 break;
1782
1783 case NSF8FunctionKey:
1784 key = gvFunctionKey8;
1785 break;
1786
1787 case NSF9FunctionKey:
1788 key = gvFunctionKey9;
1789 break;
1790
1791 case NSF10FunctionKey:
1792 key = gvFunctionKey10;
1793 break;
1794
1795 case NSF11FunctionKey:
1796 key = gvFunctionKey11;
1797 break;
1798
1799 case NSHomeFunctionKey:
1800 key = gvHomeKey;
1801 break;
1802
1803 default:
1804 break;
1805 }
1806 return key;
1807}
1808
1809
1810- (void) setVirtualJoystick:(double) vmx :(double) vmy
1811{
1812 virtualJoystickPosition.x = vmx;
1813 virtualJoystickPosition.y = vmy;
1814}
1815
1816
1817- (NSPoint) virtualJoystickPosition
1818{
1819 return virtualJoystickPosition;
1820}
1821
1822
1824
1825- (void) clearKeys
1826{
1827 int i;
1828 lastKeyShifted = NO;
1829 for (i = 0; i < [self numKeys]; i++)
1830 keys[i] = NO;
1831}
1832
1833
1834- (void) clearMouse
1835{
1836 keys[gvMouseDoubleClick] = NO;
1837 keys[gvMouseLeftButton] = NO;
1838 doubleClick = NO;
1839}
1840
1841
1842- (void) clearKey: (int)theKey
1843{
1844 if (theKey >= 0 && theKey < [self numKeys])
1845 {
1846 keys[theKey] = NO;
1847 }
1848}
1849
1850
1851- (void) resetMouse
1852{
1853 [self setVirtualJoystick:0.0 :0.0];
1854 if ([[PlayerEntity sharedPlayer] isMouseControlOn])
1855 {
1856 SDL_WarpMouse([self viewSize].width / 2, [self viewSize].height / 2);
1857 mouseWarped = YES;
1858 }
1859}
1860
1861
1862- (BOOL) isAlphabetKeyDown
1863{
1864 return isAlphabetKeyDown = NO;;
1865}
1866
1867// DJS: When entering submenus in the gui, it is not helpful if the
1868// key down that brought you into the submenu is still registered
1869// as down when we're in. This makes isDown return NO until a key up
1870// event has been received from SDL.
1871- (void) suppressKeysUntilKeyUp
1872{
1873 if (keys[gvMouseDoubleClick] == NO)
1874 {
1875 suppressKeys = YES;
1876 [self clearKeys];
1877 }
1878 else
1879 {
1880 [self clearMouse];
1881 }
1882
1883}
1884
1885
1886- (BOOL) isDown: (int) key
1887{
1888 if ( suppressKeys )
1889 return NO;
1890 if ( key < 0 )
1891 return NO;
1892 if ( key >= [self numKeys] )
1893 return NO;
1894 return keys[key];
1895}
1896
1897
1898- (BOOL) isOptDown
1899{
1900 return opt;
1901}
1902
1903
1904- (BOOL) isCtrlDown
1905{
1906 return ctrl;
1907}
1908
1909
1910- (BOOL) isCommandDown
1911{
1912 return command;
1913}
1914
1915
1916- (BOOL) isShiftDown
1917{
1918 return shift;
1919}
1920
1921
1922- (BOOL) isCapsLockOn
1923{
1924 /* Caps Lock state check - This effectively gives us
1925 an alternate keyboard state to play with and, in
1926 the future, we could assign different behaviours
1927 to existing controls, depending on the state of
1928 Caps Lock. - Nikos 20160304
1929 */
1930 return (SDL_GetModState() & KMOD_CAPS) == KMOD_CAPS;
1931}
1932
1933
1934- (BOOL) lastKeyWasShifted
1935{
1936 return lastKeyShifted;
1937}
1938
1939- (int) numKeys
1940{
1941 return NUM_KEYS;
1942}
1943
1944
1945- (int) mouseWheelState
1946{
1947 if (_mouseWheelDelta > 0.0f)
1948 return gvMouseWheelUp;
1949 else if (_mouseWheelDelta < 0.0f)
1950 return gvMouseWheelDown;
1951 else
1952 return gvMouseWheelNeutral;
1953}
1954
1955
1956- (float) mouseWheelDelta
1957{
1958 return _mouseWheelDelta / OOMOUSEWHEEL_DELTA;
1959}
1960
1961
1962- (void) setMouseWheelDelta: (float) newWheelDelta
1963{
1964 _mouseWheelDelta = newWheelDelta * OOMOUSEWHEEL_DELTA;
1965}
1966
1967
1968- (BOOL) isCommandQDown
1969{
1970 return NO;
1971}
1972
1973
1974- (BOOL) isCommandFDown
1975{
1976 return NO;
1977}
1978
1979
1980- (void) clearCommandF
1981{
1982 // SDL stub for the mac function.
1983}
1984
1985
1986- (void)pollControls
1987{
1988 SDL_Event event;
1989 SDL_KeyboardEvent *kbd_event;
1990 SDL_MouseButtonEvent *mbtn_event;
1991 SDL_MouseMotionEvent *mmove_event;
1992 int mxdelta, mydelta;
1993 float mouseVirtualStickSensitivityX = viewSize.width * MOUSEVIRTUALSTICKSENSITIVITYFACTOR;
1994 float mouseVirtualStickSensitivityY = viewSize.height * MOUSEVIRTUALSTICKSENSITIVITYFACTOR;
1995 NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];
1996 Uint16 key_id;
1997 int scan_code;
1998
1999 while (SDL_PollEvent(&event))
2000 {
2001 switch (event.type) {
2002 case SDL_JOYAXISMOTION:
2003 case SDL_JOYBUTTONUP:
2004 case SDL_JOYBUTTONDOWN:
2005 case SDL_JOYHATMOTION:
2007 break;
2008
2009 case SDL_MOUSEBUTTONDOWN:
2010 mbtn_event = (SDL_MouseButtonEvent*)&event;
2011#if OOLITE_LINUX
2012 short inDelta = 0;
2013#else
2014 // specially built SDL.dll is required for this
2015 short inDelta = mbtn_event->wheelDelta;
2016#endif
2017 switch(mbtn_event->button)
2018 {
2019 case SDL_BUTTON_LEFT:
2020 keys[gvMouseLeftButton] = YES;
2021 break;
2022 case SDL_BUTTON_RIGHT:
2023 // Cocoa version does this in the GameController
2024 /*
2025 The mouseWarped variable is quite important as far as mouse control is concerned. When we
2026 reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call because we
2027 must recenter the pointer physically on screen. This goes together with a mouse motion event,
2028 so we use mouseWarped to simply ignore handling of motion events in this case. - Nikos 20110721
2029 */
2030 [self resetMouse]; // Will set mouseWarped to YES
2031 break;
2032 // mousewheel stuff
2033#if OOLITE_LINUX
2034 case SDL_BUTTON_WHEELUP:
2035 inDelta = OOMOUSEWHEEL_DELTA;
2036 // allow fallthrough
2037 case SDL_BUTTON_WHEELDOWN:
2038 if (inDelta == 0) inDelta = -OOMOUSEWHEEL_DELTA;
2039#else
2040 case SDL_BUTTON_WHEELUP:
2041 case SDL_BUTTON_WHEELDOWN:
2042#endif
2043 if (inDelta > 0)
2044 {
2045 if (_mouseWheelDelta >= 0.0f)
2046 _mouseWheelDelta += inDelta;
2047 else
2048 _mouseWheelDelta = 0.0f;
2049 }
2050 else if (inDelta < 0)
2051 {
2052 if (_mouseWheelDelta <= 0.0f)
2053 _mouseWheelDelta += inDelta;
2054 else
2055 _mouseWheelDelta = 0.0f;
2056 }
2057 break;
2058 }
2059 break;
2060
2061 case SDL_MOUSEBUTTONUP:
2062 mbtn_event = (SDL_MouseButtonEvent*)&event;
2063 NSTimeInterval timeBetweenClicks = timeNow - timeIntervalAtLastClick;
2064 timeIntervalAtLastClick += timeBetweenClicks;
2065 if (mbtn_event->button == SDL_BUTTON_LEFT)
2066 {
2067 if (!doubleClick)
2068 {
2069 doubleClick = (timeBetweenClicks < MOUSE_DOUBLE_CLICK_INTERVAL); // One fifth of a second
2070 keys[gvMouseDoubleClick] = doubleClick;
2071 }
2072 keys[gvMouseLeftButton] = NO;
2073 }
2074 /*
2075 Mousewheel handling - just note time since last use here and mark as inactive,
2076 if needed, at the end of this method. Note that the mousewheel button up event is
2077 kind of special, as in, it is sent at the same time as its corresponding mousewheel
2078 button down one - Nikos 20140809
2079 */
2080 if (mbtn_event->button == SDL_BUTTON_WHEELUP || mbtn_event->button == SDL_BUTTON_WHEELDOWN)
2081 {
2082 NSTimeInterval timeBetweenMouseWheels = timeNow - timeSinceLastMouseWheel;
2083 timeSinceLastMouseWheel += timeBetweenMouseWheels;
2084 }
2085 break;
2086
2087 case SDL_MOUSEMOTION:
2088 {
2089 // Delta mode is set when the game is in 'flight' mode.
2090 // In this mode, the mouse movement delta is used rather
2091 // than absolute position. This is because if the user
2092 // clicks the right button to recentre the virtual joystick,
2093 // if we are using absolute joystick positioning, as soon
2094 // as the player touches the mouse again, the virtual joystick
2095 // will snap back to the absolute position (which can be
2096 // annoyingly fatal in battle).
2097 if(mouseInDeltaMode)
2098 {
2099 // possible TODO - make virtual stick sensitivity configurable
2100 SDL_GetRelativeMouseState(&mxdelta, &mydelta);
2101 double mxd=(double)mxdelta / mouseVirtualStickSensitivityX;
2102 double myd=(double)mydelta / mouseVirtualStickSensitivityY;
2103
2104 if (!mouseWarped) // Standard event, update coordinates
2105 {
2106 virtualJoystickPosition.x += mxd;
2107 virtualJoystickPosition.y += myd;
2108
2109 // if we excceed the limits, revert changes
2110 if(fabs(virtualJoystickPosition.x) > MOUSEX_MAXIMUM)
2111 {
2112 virtualJoystickPosition.x -= mxd;
2113 }
2114 if(fabs(virtualJoystickPosition.y) > MOUSEY_MAXIMUM)
2115 {
2116 virtualJoystickPosition.y -= myd;
2117 }
2118 }
2119 else
2120 {
2121 // Motion event generated by WarpMouse is ignored and
2122 // we reset mouseWarped for the next time.
2123 mouseWarped = NO;
2124 }
2125 }
2126 else
2127 {
2128 // Windowed mode. Use the absolute position so the
2129 // Oolite mouse pointer appears under the X Window System
2130 // mouse pointer.
2131 mmove_event = (SDL_MouseMotionEvent*)&event;
2132
2133 int w=bounds.size.width;
2134 int h=bounds.size.height;
2135
2136 if (!mouseWarped) // standard event, handle it
2137 {
2138 double mx = mmove_event->x - w/2.0;
2139 double my = mmove_event->y - h/2.0;
2140 if (display_z > 640.0)
2141 {
2142 mx /= w * MAIN_GUI_PIXEL_WIDTH / display_z;
2143 my /= h;
2144 }
2145 else
2146 {
2147 mx /= MAIN_GUI_PIXEL_WIDTH * w / 640.0;
2148 my /= MAIN_GUI_PIXEL_HEIGHT * w / 640.0;
2149 }
2150
2151 [self setVirtualJoystick:mx :my];
2152 }
2153 else
2154 {
2155 // event coming from WarpMouse ignored, get ready for the next
2156 mouseWarped = NO;
2157 }
2158 }
2159 break;
2160 }
2161 case SDL_KEYDOWN:
2162 kbd_event = (SDL_KeyboardEvent*)&event;
2163 key_id = (Uint16)kbd_event->keysym.unicode;
2164 scan_code = kbd_event->keysym.scancode;
2165
2166 //char *keychar = SDL_GetKeyName(kbd_event->keysym.sym);
2167 // deal with modifiers first
2168 BOOL modifier_pressed = NO;
2169 BOOL special_key = NO;
2170
2171 // translate scancode to unicode equiv
2172 switch (kbd_event->keysym.sym)
2173 {
2174 case SDLK_LSHIFT:
2175 case SDLK_RSHIFT:
2176 shift = YES;
2177 modifier_pressed = YES;
2178 break;
2179
2180 case SDLK_LCTRL:
2181 case SDLK_RCTRL:
2182 ctrl = YES;
2183 modifier_pressed = YES;
2184 break;
2185
2186 case SDLK_LALT:
2187 case SDLK_RALT:
2188 opt = YES;
2189 modifier_pressed = YES;
2190 break;
2191
2192 case SDLK_KP0: key_id = (!allowingStringInput ? gvNumberPadKey0 : gvNumberKey0); special_key = YES; break;
2193 case SDLK_KP1: key_id = (!allowingStringInput ? gvNumberPadKey1 : gvNumberKey1); special_key = YES; break;
2194 case SDLK_KP2: key_id = (!allowingStringInput ? gvNumberPadKey2 : gvNumberKey2); special_key = YES; break;
2195 case SDLK_KP3: key_id = (!allowingStringInput ? gvNumberPadKey3 : gvNumberKey3); special_key = YES; break;
2196 case SDLK_KP4: key_id = (!allowingStringInput ? gvNumberPadKey4 : gvNumberKey4); special_key = YES; break;
2197 case SDLK_KP5: key_id = (!allowingStringInput ? gvNumberPadKey5 : gvNumberKey5); special_key = YES; break;
2198 case SDLK_KP6: key_id = (!allowingStringInput ? gvNumberPadKey6 : gvNumberKey6); special_key = YES; break;
2199 case SDLK_KP7: key_id = (!allowingStringInput ? gvNumberPadKey7 : gvNumberKey7); special_key = YES; break;
2200 case SDLK_KP8: key_id = (!allowingStringInput ? gvNumberPadKey8 : gvNumberKey8); special_key = YES; break;
2201 case SDLK_KP9: key_id = (!allowingStringInput ? gvNumberPadKey9 : gvNumberKey9); special_key = YES; break;
2202 case SDLK_KP_PERIOD: key_id = (!allowingStringInput ? gvNumberPadKeyPeriod : 46); special_key = YES; break;
2203 case SDLK_KP_DIVIDE: key_id = (!allowingStringInput ? gvNumberPadKeyDivide : 47); special_key = YES; break;
2204 case SDLK_KP_MULTIPLY: key_id = (!allowingStringInput ? gvNumberPadKeyMultiply : 42); special_key = YES; break;
2205 case SDLK_KP_MINUS: key_id = (!allowingStringInput ? gvNumberPadKeyMinus : 45); special_key = YES; break;
2206 case SDLK_KP_PLUS: key_id = (!allowingStringInput ? gvNumberPadKeyPlus : 43); special_key = YES; break;
2207 case SDLK_KP_EQUALS: key_id = (!allowingStringInput ? gvNumberPadKeyEquals : 61); special_key = YES; break;
2208 case SDLK_KP_ENTER: key_id = gvNumberPadKeyEnter; special_key = YES; break;
2209 case SDLK_HOME: key_id = gvHomeKey; special_key = YES; break;
2210 case SDLK_END: key_id = gvEndKey; special_key = YES; break;
2211 case SDLK_INSERT: key_id = gvInsertKey; special_key = YES; break;
2212 case SDLK_PAGEUP: key_id = gvPageUpKey; special_key = YES; break;
2213 case SDLK_PAGEDOWN: key_id = gvPageDownKey; special_key = YES; break;
2214 case SDLK_SPACE: key_id = 32; special_key = YES; break;
2215 case SDLK_RETURN: key_id = 13; special_key = YES; break;
2216 case SDLK_TAB: key_id = 9; special_key = YES; break;
2217 case SDLK_UP: key_id = gvArrowKeyUp; special_key = YES; break;
2218 case SDLK_DOWN: key_id = gvArrowKeyDown; special_key = YES; break;
2219 case SDLK_LEFT: key_id = gvArrowKeyLeft; special_key = YES; break;
2220 case SDLK_RIGHT: key_id = gvArrowKeyRight; special_key = YES; break;
2221 case SDLK_PAUSE: key_id = gvPauseKey; special_key = YES; break;
2222 case SDLK_BACKSPACE: key_id = gvBackspaceKey; special_key = YES; break;
2223 case SDLK_DELETE: key_id = gvDeleteKey; special_key = YES; break;
2224 case SDLK_F1: key_id = gvFunctionKey1; special_key = YES; break;
2225 case SDLK_F2: key_id = gvFunctionKey2; special_key = YES; break;
2226 case SDLK_F3: key_id = gvFunctionKey3; special_key = YES; break;
2227 case SDLK_F4: key_id = gvFunctionKey4; special_key = YES; break;
2228 case SDLK_F5: key_id = gvFunctionKey5; special_key = YES; break;
2229 case SDLK_F6: key_id = gvFunctionKey6; special_key = YES; break;
2230 case SDLK_F7: key_id = gvFunctionKey7; special_key = YES; break;
2231 case SDLK_F8: key_id = gvFunctionKey8; special_key = YES; break;
2232 case SDLK_F9: key_id = gvFunctionKey9; special_key = YES; break;
2233 case SDLK_F10: key_id = gvFunctionKey10; special_key = YES; break;
2234 case SDLK_F11: key_id = gvFunctionKey11; special_key = YES; break;
2235 case SDLK_F12:
2236 key_id = 327;
2237 [self toggleScreenMode];
2238 special_key = YES;
2239 break;
2240
2241 case SDLK_ESCAPE:
2242 if (shift)
2243 {
2244 SDL_FreeSurface(surface);
2245 [gameController exitAppWithContext:@"Shift-escape pressed"];
2246 }
2247 else
2248 key_id = 27;
2249 special_key = YES;
2250 break;
2251 default:
2252 //OOLog(@"keys.test", @"Unhandled Keydown scancode with unicode = 0: %d", scan_code);
2253 ;
2254 }
2255
2256 // the keyup event doesn't give us the unicode value, so store it here so it can be retrieved on keyup
2257 // the ctrl key tends to mix up the unicode values, so deal with some special cases
2258 // we also need (in most cases) to get the character without the impact of caps lock.
2259 if (((!special_key && (ctrl || key_id == 0)) || ([self isCapsLockOn] && (!special_key && !allowingStringInput))) && !modifier_pressed) //
2260 {
2261 // ctrl changes alpha characters to control codes (1-26)
2262 if (ctrl && key_id >=1 && key_id <= 26)
2263 {
2264 if (shift)
2265 key_id += 64; // A-Z is from 65, offset by -1 for the scancode start point
2266 else
2267 key_id += 96; // a-z is from 97, offset by -1 for the scancode start point
2268 }
2269 else
2270 {
2271 key_id = 0; // reset the value here to force a lookup from the keymappings data
2272 }
2273 }
2274
2275 // if we get here and we still don't have a key id, grab the unicode value from our keymappings dict
2276 if (key_id == 0)
2277 {
2278 // get unicode value for keycode from keymappings files
2279 // this handles all the non-functional keys. the function keys are handled in the switch above
2280 if (!shift)
2281 {
2282 NSString *keyNormal = [keyMappings_normal objectForKey:[NSString stringWithFormat:@"%d", scan_code]];
2283 if (keyNormal) key_id = [keyNormal integerValue];
2284 }
2285 else
2286 {
2287 NSString *keyShifted = [keyMappings_shifted objectForKey:[NSString stringWithFormat:@"%d", scan_code]];
2288 if (keyShifted) key_id = [keyShifted integerValue];
2289 }
2290 }
2291
2292 // if we've got the unicode value, we can store it in our array now
2293 if (key_id > 0) scancode2Unicode[scan_code] = key_id;
2294
2295 if(allowingStringInput)
2296 {
2297 [self handleStringInput:kbd_event keyID:key_id];
2298 }
2299
2300 OOLog(kOOLogKeyDown, @"Keydown scancode = %d, unicode = %i, sym = %i, character = %c, shift = %d, ctrl = %d, alt = %d", scan_code, key_id, kbd_event->keysym.sym, key_id, shift, ctrl, opt);
2301 //OOLog(kOOLogKeyDown, @"Keydown scancode = %d, unicode = %i", kbd_event->keysym.scancode, key_id);
2302
2303 if (key_id > 0 && key_id <= [self numKeys])
2304 {
2305 keys[key_id] = YES;
2306 }
2307 else
2308 {
2309 //OOLog(@"keys.test", @"Unhandled Keydown scancode/unicode: %d %i", scan_code, key_id);
2310 }
2311 break;
2312
2313 case SDL_KEYUP:
2314 suppressKeys = NO; // DJS
2315 kbd_event = (SDL_KeyboardEvent*)&event;
2316 scan_code = kbd_event->keysym.scancode;
2317
2318 // all the work should have been down on the keydown event, so all we need to do is get the unicode value from the array
2319 key_id = scancode2Unicode[scan_code];
2320
2321 // deal with modifiers first
2322 switch (kbd_event->keysym.sym)
2323 {
2324 case SDLK_LSHIFT:
2325 case SDLK_RSHIFT:
2326 shift = NO;
2327 break;
2328
2329 case SDLK_LCTRL:
2330 case SDLK_RCTRL:
2331 ctrl = NO;
2332 break;
2333
2334 case SDLK_LALT:
2335 case SDLK_RALT:
2336 opt = NO;
2337 break;
2338 default:
2339 ;
2340 }
2341 OOLog(kOOLogKeyUp, @"Keyup scancode = %d, unicode = %i, sym = %i, character = %c, shift = %d, ctrl = %d, alt = %d", scan_code, key_id, kbd_event->keysym.sym, key_id, shift, ctrl, opt);
2342 //OOLog(kOOLogKeyUp, @"Keyup scancode = %d, shift = %d, ctrl = %d, alt = %d", scan_code, shift, ctrl, opt);
2343
2344 // translate scancode to unicode equiv
2345 switch (kbd_event->keysym.sym)
2346 {
2347 case SDLK_KP0: key_id = (!allowingStringInput ? gvNumberPadKey0 : gvNumberKey0); break;
2348 case SDLK_KP1: key_id = (!allowingStringInput ? gvNumberPadKey1 : gvNumberKey1); break;
2349 case SDLK_KP2: key_id = (!allowingStringInput ? gvNumberPadKey2 : gvNumberKey2); break;
2350 case SDLK_KP3: key_id = (!allowingStringInput ? gvNumberPadKey3 : gvNumberKey3); break;
2351 case SDLK_KP4: key_id = (!allowingStringInput ? gvNumberPadKey4 : gvNumberKey4); break;
2352 case SDLK_KP5: key_id = (!allowingStringInput ? gvNumberPadKey5 : gvNumberKey5); break;
2353 case SDLK_KP6: key_id = (!allowingStringInput ? gvNumberPadKey6 : gvNumberKey6); break;
2354 case SDLK_KP7: key_id = (!allowingStringInput ? gvNumberPadKey7 : gvNumberKey7); break;
2355 case SDLK_KP8: key_id = (!allowingStringInput ? gvNumberPadKey8 : gvNumberKey8); break;
2356 case SDLK_KP9: key_id = (!allowingStringInput ? gvNumberPadKey9 : gvNumberKey9); break;
2357 case SDLK_KP_PERIOD: key_id = (!allowingStringInput ? gvNumberPadKeyPeriod : 46); break;
2358 case SDLK_KP_DIVIDE: key_id = (!allowingStringInput ? gvNumberPadKeyDivide : 47); break;
2359 case SDLK_KP_MULTIPLY: key_id = (!allowingStringInput ? gvNumberPadKeyMultiply : 42); break;
2360 case SDLK_KP_MINUS: key_id = (!allowingStringInput ? gvNumberPadKeyMinus : 45); break;
2361 case SDLK_KP_PLUS: key_id = (!allowingStringInput ? gvNumberPadKeyPlus : 43); break;
2362 case SDLK_KP_EQUALS: key_id = (!allowingStringInput ? gvNumberPadKeyEquals : 61); break;
2363 case SDLK_KP_ENTER: key_id = gvNumberPadKeyEnter; break;
2364 case SDLK_HOME: key_id = gvHomeKey; break;
2365 case SDLK_END: key_id = gvEndKey; break;
2366 case SDLK_INSERT: key_id = gvInsertKey; break;
2367 case SDLK_PAGEUP: key_id = gvPageUpKey; break;
2368 case SDLK_PAGEDOWN: key_id = gvPageDownKey; break;
2369 case SDLK_SPACE: key_id = 32; break;
2370 case SDLK_RETURN: key_id = 13; break;
2371 case SDLK_TAB: key_id = 9; break;
2372 case SDLK_ESCAPE: key_id = 27; break;
2373 case SDLK_UP: key_id = gvArrowKeyUp; break;
2374 case SDLK_DOWN: key_id = gvArrowKeyDown; break;
2375 case SDLK_LEFT: key_id = gvArrowKeyLeft; break;
2376 case SDLK_RIGHT: key_id = gvArrowKeyRight; break;
2377 case SDLK_PAUSE: key_id = gvPauseKey; break;
2378 case SDLK_F1: key_id = gvFunctionKey1; break;
2379 case SDLK_F2: key_id = gvFunctionKey2; break;
2380 case SDLK_F3: key_id = gvFunctionKey3; break;
2381 case SDLK_F4: key_id = gvFunctionKey4; break;
2382 case SDLK_F5: key_id = gvFunctionKey5; break;
2383 case SDLK_F6: key_id = gvFunctionKey6; break;
2384 case SDLK_F7: key_id = gvFunctionKey7; break;
2385 case SDLK_F8: key_id = gvFunctionKey8; break;
2386 case SDLK_F9: key_id = gvFunctionKey9; break;
2387 case SDLK_F10: key_id = gvFunctionKey10; break;
2388 case SDLK_F11: key_id = gvFunctionKey11; break;
2389 case SDLK_F12: key_id = 327; break;
2390 case SDLK_BACKSPACE: key_id = gvBackspaceKey; break;
2391 case SDLK_DELETE: key_id = gvDeleteKey; break;
2392
2393 default:
2394 //OOLog(@"keys.test", @"Unhandled Keyup scancode with unicode = 0: %d", kbd_event->keysym.scancode);
2395 ;
2396 }
2397
2398 if (key_id > 0 && key_id <= [self numKeys])
2399 {
2400 keys[key_id] = NO;
2401 }
2402 else
2403 {
2404 //OOLog(@"keys.test", @"Unhandled Keyup scancode: %d", kbd_event->keysym.scancode);
2405 }
2406 break;
2407
2408 case SDL_VIDEORESIZE:
2409 {
2410 SDL_ResizeEvent *rsevt=(SDL_ResizeEvent *)&event;
2411 NSSize newSize=NSMakeSize(rsevt->w, rsevt->h);
2412#if OOLITE_WINDOWS
2413 if (!fullScreen && updateContext)
2414 {
2415 if (saveSize == NO)
2416 {
2417 // event triggered by caption & frame
2418 // next event will be a real resize.
2419 saveSize = YES;
2420 }
2421 else
2422 {
2423 [self initialiseGLWithSize: newSize];
2424 [self saveWindowSize: newSize];
2425 }
2426 }
2427#else
2428 [self initialiseGLWithSize: newSize];
2429 [self saveWindowSize: newSize];
2430#endif
2431 // certain gui screens will require an immediate redraw after
2432 // a resize event - Nikos 20140129
2433 if ([PlayerEntity sharedPlayer])
2434 {
2436 }
2437 break;
2438 }
2439
2440#if OOLITE_WINDOWS
2441 // if we minimize the window while in fullscreen (e.g. via
2442 // Win+M or Win+DownArrow), restore the non-borderless window
2443 // style before minimuzing and reset it when we return, otherwise
2444 // there might be issues with the game window remaining stuck on
2445 // top in some cases (seen with some Intel gfx chips).
2446 // N.B. active event gain of zero means app is iconified
2447 case SDL_ACTIVEEVENT:
2448 {
2449 if ((event.active.state & SDL_APPACTIVE) && fullScreen)
2450 {
2451 [self setWindowBorderless:event.active.gain];
2452 }
2453 break;
2454 }
2455
2456 // need to track this because the user may move the game window
2457 // to a secondary monitor, in which case we must potentially
2458 // refresh the information displayed (e.g. Game Options screen)
2459 // Nikos - 20140920
2460 case SDL_SYSWMEVENT:
2461 {
2462 DWORD dwLastError = 0;
2463 switch (event.syswm.msg->msg)
2464 {
2465 case WM_WINDOWPOSCHANGING:
2466 /* if we are in fullscreen mode we normally don't worry about having the window moved.
2467 However, when using multiple monitors, one can use hotkey combinations to make the
2468 window "jump" from one monitor to the next. We don't want this to happen, so if we
2469 detect that our (fullscreen) window has moved, we immediately bring it back to its
2470 original position. Nikos - 20140922
2471 */
2472 if (fullScreen)
2473 {
2474 RECT rDC;
2475
2476 /* attempting to move our fullscreen window while in maximized state can freak
2477 Windows out and the window may not return to its original position properly.
2478 Solution: if such a move takes place, first change the window placement to
2479 normal, move it normally, then restore its placement to maximized again.
2480 Additionally, the last good known window position seems to be lost in such
2481 a case. While at it, update also the coordinates of the non-maximized window
2482 so that it can return to its original position - this is why we need lastGoodRect.
2483 */
2484 WINDOWPLACEMENT wp;
2485 wp.length = sizeof(WINDOWPLACEMENT);
2486 GetWindowPlacement(SDL_Window, &wp);
2487
2488 GetWindowRect(SDL_Window, &rDC);
2489 if (rDC.left != monitorInfo.rcMonitor.left || rDC.top != monitorInfo.rcMonitor.top)
2490 {
2491 BOOL fullScreenMaximized = NO;
2492 if (wp.showCmd == SW_SHOWMAXIMIZED && !fullScreenMaximized)
2493 {
2494 fullScreenMaximized = YES;
2495 wp.showCmd = SW_SHOWNORMAL;
2496 SetWindowPlacement(SDL_Window, &wp);
2497 }
2498
2499 if (wp.showCmd != SW_SHOWMINIMIZED && wp.showCmd != SW_MINIMIZE)
2500 {
2501 MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
2502 (int)viewSize.width, (int)viewSize.height, TRUE);
2503 }
2504
2505 if (fullScreenMaximized)
2506 {
2507 GetWindowPlacement(SDL_Window, &wp);
2508 wp.showCmd = SW_SHOWMAXIMIZED;
2509 CopyRect(&wp.rcNormalPosition, &lastGoodRect);
2510 SetWindowPlacement(SDL_Window, &wp);
2511 }
2512 }
2513 else if (wp.showCmd == SW_SHOWMAXIMIZED)
2514 {
2515 CopyRect(&wp.rcNormalPosition, &lastGoodRect);
2516 SetWindowPlacement(SDL_Window, &wp);
2517 }
2518 }
2519 // it is important that this gets done after we've dealt with possible fullscreen movements,
2520 // because -doGuiScreenResizeUpdates does itself an update on current monitor
2521 if ([PlayerEntity sharedPlayer])
2522 {
2524 }
2525 /*
2526 deliberately no break statement here - moving or resizing the window changes its bounds
2527 rectangle. Therefore we must check whether to clip the mouse or not inside the newly
2528 updated rectangle, so just let it fall through
2529 */
2530
2531 case WM_ACTIVATEAPP:
2532 if(grabMouseStatus) [self grabMouseInsideGameWindow:YES];
2533 break;
2534
2535 case WM_SETTINGCHANGE:
2536 // TODO: we really should be checking the status of event.syswm.msg->lParam here and run our
2537 // dark / light mode refresh check only if the lParam LPCTSTR matches "ImmersiveColorSet".
2538 // However, for some reason I cannot get an actual string on lParam. This means that the
2539 // mode refresh check runs every time something changes the Windows Registry while the game
2540 // is running. Still, should be OK because our refreshDarKOrLightMode will be transparent in
2541 // such cases, plus we would not practically expect too many events doing things to the Registry
2542 // while we are running. If in the future we need to respond to a different event which changes
2543 // system settings in real time, then yes, we will have to find a way to decode lParam properly.
2544 // Nikos, 20230805
2545 [self refreshDarKOrLightMode];
2546 break;
2547
2548 case WM_SETFOCUS:
2549 /*
2550 ` make sure that all modifier keys like Shift, Alt, Ctrl and Caps Lock
2551 ` are set correctly to what they should be when we get focus. We have
2552 ` to do it ourselves because SDL on Windows has problems with this
2553 ` when focus change events occur, like e.g. Alt-Tab in/out of the
2554 application
2555 ` */
2556 [self resetSDLKeyModifiers];
2557 if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
2558 {
2559 dwLastError = GetLastError();
2560 OOLog(@"wm_setfocus.message", @"Setting thread priority to time critical failed! (error code: %d)", dwLastError);
2561 }
2562 break;
2563
2564 case WM_KILLFOCUS:
2565 if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL))
2566 {
2567 dwLastError = GetLastError();
2568 OOLog(@"wm_killfocus.message", @"Setting thread priority to normal failed! (error code: %d)", dwLastError);
2569 }
2570 break;
2571
2572 default:
2573 ;
2574 }
2575 break;
2576 }
2577#endif
2578
2579 // caused by INTR or someone hitting close
2580 case SDL_QUIT:
2581 {
2582 SDL_FreeSurface(surface);
2583 [gameController exitAppWithContext:@"SDL_QUIT event received"];
2584 }
2585 }
2586 }
2587 // check if enough time has passed since last use of the mousewheel and act
2588 // if needed
2589 if (timeNow >= timeSinceLastMouseWheel + OOMOUSEWHEEL_EVENTS_DELAY_INTERVAL)
2590 {
2591 _mouseWheelDelta = 0.0f;
2592 }
2593}
2594
2595
2596// DJS: String input handler. Since for SDL versions we're also handling
2597// freeform typing this has necessarily got more complex than the non-SDL
2598// versions.
2599- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event keyID:(Uint16)key_id;
2600{
2601 SDLKey key=kbd_event->keysym.sym;
2602
2603 // Del, Backspace
2604 if((key == SDLK_BACKSPACE || key == SDLK_DELETE) && [typedString length] > 0)
2605 {
2606 // delete
2607 [typedString deleteCharactersInRange:NSMakeRange([typedString length]-1, 1)];
2608 }
2609
2610 isAlphabetKeyDown=NO;
2611
2612 // TODO: a more flexible mechanism for max. string length ?
2613 if([typedString length] < 40)
2614 {
2615 lastKeyShifted = shift;
2616 if (allowingStringInput == gvStringInputAlpha)
2617 {
2618 // inputAlpha - limited input for planet find screen
2619 if(key >= SDLK_a && key <= SDLK_z)
2620 {
2621 isAlphabetKeyDown=YES;
2622 [typedString appendFormat:@"%c", key];
2623 // if in inputAlpha, keep in lower case.
2624 }
2625 }
2626 else
2627 {
2628 //Uint16 unicode = kbd_event->keysym.unicode;
2629 // printable range
2630 if (key_id >= 32 && key_id <= 255) // 126
2631 {
2632 if ((char)key_id != '/' || allowingStringInput == gvStringInputAll)
2633 {
2634 isAlphabetKeyDown=YES;
2635 [typedString appendFormat:@"%c", key_id];
2636 }
2637 }
2638 }
2639 }
2640}
2641
2642
2643// Full screen mode enumerator.
2644- (void) populateFullScreenModelist
2645{
2646 int i;
2647 SDL_Rect **modes;
2648 NSMutableDictionary *mode;
2649
2650 screenSizes=[[NSMutableArray alloc] init];
2651
2652 // The default resolution (slot 0) is the resolution we are
2653 // already in since this is guaranteed to work.
2655 [screenSizes addObject: mode];
2656
2657 modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
2658 if(modes == (SDL_Rect **)NULL)
2659 {
2660 OOLog(@"display.mode.list.none", @"%@", @"SDL didn't return any screen modes");
2661 return;
2662 }
2663
2664 if(modes == (SDL_Rect **)-1)
2665 {
2666 OOLog(@"display.mode.list.none", @"%@", @"SDL claims 'all resolutions available' which is unhelpful in the extreme");
2667 return;
2668 }
2669
2670 int lastw=[[mode objectForKey: kOODisplayWidth] intValue];
2671 int lasth=[[mode objectForKey: kOODisplayHeight] intValue];
2672 for(i=0; modes[i]; i++)
2673 {
2674 // SDL_ListModes often lists a mode several times,
2675 // presumably because each mode has several refresh rates.
2676 // But the modes pointer is an SDL_Rect which can't represent
2677 // refresh rates. WHY!?
2678 if(modes[i]->w != lastw || modes[i]->h != lasth)
2679 {
2680 // new resolution, save it
2681 mode=[NSMutableDictionary dictionary];
2682 [mode setValue: [NSNumber numberWithInt: (int)modes[i]->w]
2683 forKey: kOODisplayWidth];
2684 [mode setValue: [NSNumber numberWithInt: (int)modes[i]->h]
2685 forKey: kOODisplayHeight];
2686 [mode setValue: [NSNumber numberWithInt: 0]
2687 forKey: kOODisplayRefreshRate];
2688 if (![screenSizes containsObject:mode])
2689 {
2690 [screenSizes addObject: mode];
2691 OOLog(@"display.mode.list", @"Added res %d x %d", modes[i]->w, modes[i]->h);
2692 lastw=modes[i]->w;
2693 lasth=modes[i]->h;
2694 }
2695 }
2696 }
2697}
2698
2699
2700// Save and restore window sizes to/from defaults.
2701- (void) saveWindowSize: (NSSize) windowSize
2702{
2703 NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
2704 [defaults setInteger: (int)windowSize.width forKey: @"window_width"];
2705 [defaults setInteger: (int)windowSize.height forKey: @"window_height"];
2706 currentWindowSize=windowSize;
2707}
2708
2709
2710- (NSSize) loadWindowSize
2711{
2712 NSSize windowSize;
2713 NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
2714 if([defaults objectForKey:@"window_width"] && [defaults objectForKey:@"window_height"])
2715 {
2716 windowSize=NSMakeSize([defaults integerForKey: @"window_width"],
2717 [defaults integerForKey: @"window_height"]);
2718 }
2719 else
2720 {
2722 }
2723 currentWindowSize=windowSize;
2724 return windowSize;
2725}
2726
2727
2728- (int) loadFullscreenSettings
2729{
2730 currentSize=0;
2731 int width=0, height=0, refresh=0;
2732 unsigned i;
2733
2734 NSArray* cmdline_arguments = [[NSProcessInfo processInfo] arguments];
2735
2736 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
2737 if ([userDefaults objectForKey:@"display_width"])
2738 width = [userDefaults integerForKey:@"display_width"];
2739 if ([userDefaults objectForKey:@"display_height"])
2740 height = [userDefaults integerForKey:@"display_height"];
2741 if ([userDefaults objectForKey:@"display_refresh"])
2742 refresh = [userDefaults integerForKey:@"display_refresh"];
2743 if([userDefaults objectForKey:@"fullscreen"])
2744 fullScreen=[userDefaults boolForKey:@"fullscreen"];
2745
2746 // Check if -fullscreen or -windowed has been passed on the command line. If yes,
2747 // set it regardless of what is set by .GNUstepDefaults. If both are found in the
2748 // arguments list, the one that comes last wins.
2749 for (i = 0; i < [cmdline_arguments count]; i++)
2750 {
2751 if ([[cmdline_arguments objectAtIndex:i] isEqual:@"-fullscreen"]) fullScreen = YES;
2752 if ([[cmdline_arguments objectAtIndex:i] isEqual:@"-windowed"]) fullScreen = NO;
2753 }
2754
2755 if(width && height)
2756 {
2757 currentSize=[self findDisplayModeForWidth: width Height: height Refresh: refresh];
2758 return currentSize;
2759 }
2760 return currentSize;
2761}
2762
2763
2764- (int) findDisplayModeForWidth:(unsigned int) d_width Height:(unsigned int) d_height Refresh:(unsigned int) d_refresh
2765{
2766 int i, modeCount;
2767 NSDictionary *mode;
2768 unsigned int modeWidth, modeHeight, modeRefresh;
2769
2770 modeCount = [screenSizes count];
2771
2772 for (i = 0; i < modeCount; i++)
2773 {
2774 mode = [screenSizes objectAtIndex: i];
2775 modeWidth = [[mode objectForKey: kOODisplayWidth] intValue];
2776 modeHeight = [[mode objectForKey: kOODisplayHeight] intValue];
2777 modeRefresh = [[mode objectForKey: kOODisplayRefreshRate] intValue];
2778 if ((modeWidth == d_width)&&(modeHeight == d_height)&&(modeRefresh == d_refresh))
2779 {
2780 OOLog(@"display.mode.found", @"Found mode %@", mode);
2781 return i;
2782 }
2783 }
2784
2785 OOLog(@"display.mode.found.failed", @"Failed to find mode: width=%d height=%d refresh=%d", d_width, d_height, d_refresh);
2786 OOLog(@"display.mode.found.failed.list", @"Contents of list: %@", screenSizes);
2787 return 0;
2788}
2789
2790
2791- (NSSize) currentScreenSize
2792{
2793 NSDictionary *mode=[screenSizes objectAtIndex: currentSize];
2794
2795 if(mode)
2796 {
2797 return NSMakeSize([[mode objectForKey: kOODisplayWidth] intValue],
2798 [[mode objectForKey: kOODisplayHeight] intValue]);
2799 }
2800 OOLog(@"display.mode.unknown", @"%@", @"Screen size unknown!");
2802}
2803
2804
2805- (void) setMouseInDeltaMode: (BOOL) inDelta
2806{
2807 mouseInDeltaMode=inDelta;
2808}
2809
2810
2811- (void) setGammaValue: (float) value
2812{
2813 if (value < 0.2f) value = 0.2f;
2814 if (value > 4.0f) value = 4.0f;
2815
2816 _gamma = value;
2817 SDL_SetGamma(_gamma, _gamma, _gamma);
2818
2819 [[NSUserDefaults standardUserDefaults] setFloat:_gamma forKey:@"gamma-value"];
2820}
2821
2822
2823- (float) gammaValue
2824{
2825 return _gamma;
2826}
2827
2828
2829- (void) setFov:(float)value fromFraction:(BOOL)fromFraction
2830{
2831 _fov = fromFraction ? value : tan((value / 2) * M_PI / 180);
2832}
2833
2834
2835- (float) fov:(BOOL)inFraction
2836{
2837 return inFraction ? _fov : 2 * atan(_fov) * 180 / M_PI;
2838}
2839
2840
2841- (BOOL) msaa
2842{
2843 return _msaa;
2844}
2845
2846
2847- (void) setMsaa:(BOOL)newMsaa
2848{
2849 _msaa = !!newMsaa;
2850}
2851
2852
2853- (OOOpenGLMatrixManager *) getOpenGLMatrixManager
2854{
2855 return matrixManager;
2856}
2857
2858
2859+ (BOOL)pollShiftKey
2860{
2861 return 0 != (SDL_GetModState() & (KMOD_LSHIFT | KMOD_RSHIFT));
2862}
2863
2864
2865#ifndef NDEBUG
2866- (void) dumpRGBAToFileNamed:(NSString *)name
2867 bytes:(uint8_t *)bytes
2868 width:(NSUInteger)width
2869 height:(NSUInteger)height
2870 rowBytes:(NSUInteger)rowBytes
2871{
2872 if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 4) return;
2873
2874 // use the snapshots directory
2875 NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR];
2876 dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]];
2877
2878 // convert transparency to black before saving to bmp
2879 SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 32, rowBytes, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
2880 SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]);
2881 SDL_FreeSurface(tmpSurface);
2882}
2883
2884
2885- (void) dumpRGBToFileNamed:(NSString *)name
2886 bytes:(uint8_t *)bytes
2887 width:(NSUInteger)width
2888 height:(NSUInteger)height
2889 rowBytes:(NSUInteger)rowBytes
2890{
2891 if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 3) return;
2892
2893 // use the snapshots directory
2894 NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR];
2895 dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]];
2896
2897 SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 24, rowBytes, 0xFF, 0xFF00, 0xFF0000, 0x0);
2898 SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]);
2899 SDL_FreeSurface(tmpSurface);
2900}
2901
2902
2903- (void) dumpGrayToFileNamed:(NSString *)name
2904 bytes:(uint8_t *)bytes
2905 width:(NSUInteger)width
2906 height:(NSUInteger)height
2907 rowBytes:(NSUInteger)rowBytes
2908{
2909 if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width) return;
2910
2911 // use the snapshots directory
2912 NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR];
2913 dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]];
2914
2915 SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 8, rowBytes, 0xFF, 0xFF, 0xFF, 0x0);
2916 SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]);
2917 SDL_FreeSurface(tmpSurface);
2918}
2919
2920
2921- (void) dumpGrayAlphaToFileNamed:(NSString *)name
2922 bytes:(uint8_t *)bytes
2923 width:(NSUInteger)width
2924 height:(NSUInteger)height
2925 rowBytes:(NSUInteger)rowBytes
2926{
2927 if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 2) return;
2928
2929 // use the snapshots directory
2930 NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR];
2931 dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]];
2932
2933 SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 16, rowBytes, 0xFF, 0xFF, 0xFF, 0xFF);
2934 SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]);
2935 SDL_FreeSurface(tmpSurface);
2936}
2937
2938
2939- (void) dumpRGBAToRGBFileNamed:(NSString *)rgbName
2940 andGrayFileNamed:(NSString *)grayName
2941 bytes:(uint8_t *)bytes
2942 width:(NSUInteger)width
2943 height:(NSUInteger)height
2944 rowBytes:(NSUInteger)rowBytes
2945{
2946 if ((rgbName == nil && grayName == nil) || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 4) return;
2947
2948 uint8_t *rgbBytes, *rgbPx, *grayBytes, *grayPx, *srcPx;
2949 NSUInteger x, y;
2950 BOOL trivalAlpha = YES;
2951
2952 rgbPx = rgbBytes = malloc(width * height * 3);
2953 if (rgbBytes == NULL) return;
2954
2955 grayPx = grayBytes = malloc(width * height);
2956 if (grayBytes == NULL)
2957 {
2958 free(rgbBytes);
2959 return;
2960 }
2961
2962 for (y = 0; y < height; y++)
2963 {
2964 srcPx = bytes + rowBytes * y;
2965
2966 for (x = 0; x < width; x++)
2967 {
2968 *rgbPx++ = *srcPx++;
2969 *rgbPx++ = *srcPx++;
2970 *rgbPx++ = *srcPx++;
2971 trivalAlpha = trivalAlpha && ((*srcPx == 0xFF) || (*srcPx == 0x00)); // Look for any "interesting" pixels in alpha.
2972 *grayPx++ = *srcPx++;
2973 }
2974 }
2975
2976 [self dumpRGBToFileNamed:rgbName
2977 bytes:rgbBytes
2978 width:width
2979 height:height
2980 rowBytes:width * 3];
2981 free(rgbBytes);
2982
2983 if (!trivalAlpha)
2984 {
2985 [self dumpGrayToFileNamed:grayName
2986 bytes:grayBytes
2987 width:width
2988 height:height
2989 rowBytes:width];
2990 }
2991 free(grayBytes);
2992}
2993#endif
2994
2995@end
#define MOUSE_DOUBLE_CLICK_INTERVAL
@ gvMouseWheelDown
@ gvMouseWheelNeutral
@ gvMouseWheelUp
@ gvNumberKey4
@ gvNumberPadKeyDivide
@ gvNumberPadKeyMultiply
@ gvNumberKey9
@ gvNumberKey5
@ gvNumberPadKeyPeriod
@ gvFunctionKey2
@ gvBackspaceKey
@ gvInsertKey
@ gvNumberPadKeyPlus
@ gvNumberPadKey9
@ gvNumberPadKey1
@ gvFunctionKey10
@ gvFunctionKey5
@ gvDeleteKey
@ gvNumberKey2
@ gvArrowKeyDown
@ gvNumberPadKey2
@ gvFunctionKey9
@ gvNumberPadKey3
@ gvFunctionKey4
@ gvEndKey
@ gvNumberKey0
@ gvNumberKey7
@ gvMouseDoubleClick
@ gvHomeKey
@ gvNumberPadKeyEquals
@ gvNumberPadKey6
@ gvNumberPadKeyEnter
@ gvNumberPadKey5
@ gvNumberPadKey4
@ gvNumberKey8
@ gvNumberKey3
@ gvNumberKey6
@ gvPauseKey
@ gvNumberPadKeyMinus
@ gvNumberPadKey7
@ gvPrintScreenKey
@ gvFunctionKey11
@ gvFunctionKey8
@ gvNumberKey1
@ gvPageDownKey
@ gvNumberPadKey8
@ gvFunctionKey3
@ gvArrowKeyUp
@ gvArrowKeyRight
@ gvFunctionKey6
@ gvArrowKeyLeft
@ gvFunctionKey7
@ gvPageUpKey
@ gvNumberPadKey0
@ gvFunctionKey1
#define OOMOUSEWHEEL_EVENTS_DELAY_INTERVAL
#define NUM_KEYS
#define OOMOUSEWHEEL_DELTA
StringInput
@ gvStringInputAlpha
@ gvStringInputNo
@ gvStringInputAll
static NSString * kOOLogKeyDown
static NSString * kOOLogKeyUp
#define MAIN_GUI_PIXEL_WIDTH
#define MAIN_GUI_PIXEL_HEIGHT
#define OOLITE_WINDOWS
Definition OOCocoa.h:247
#define kOODisplayHeight
#define kOODisplayWidth
#define OOLogWARN(class, format,...)
Definition OOLogging.h:113
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define M_PI
Definition OOMaths.h:73
OOMouseInteractionMode
@ OPENGL_STATE_OVERLAY
Definition OOOpenGL.h:126
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
return nil
float y
float x
#define MOUSEVIRTUALSTICKSENSITIVITYFACTOR
#define MAX_COLOR_SATURATION
#define MOUSEY_MAXIMUM
#define WINDOW_SIZE_DEFAULT_HEIGHT
#define MOUSEX_MAXIMUM
#define MIN_HDR_MAXBRIGHTNESS
#define MIN_HDR_PAPERWHITE
#define WINDOW_SIZE_DEFAULT_WIDTH
#define MAX_HDR_MAXBRIGHTNESS
#define MAX_HDR_PAPERWHITE
#define UNIVERSE
Definition Universe.h:833
NSMutableDictionary * getNativeSize()
BOOL setStickHandlerClass:(Class aClass)
BOOL handleSDLEvent:(SDL_Event *evt)
BOOL setUp()
Definition OOALSound.m:46
void doGuiScreenResizeUpdates()
PlayerEntity * sharedPlayer()
NSDictionary * dictionaryFromFilesNamed:inFolder:mergeMode:cache:(NSString *fileName,[inFolder] NSString *folderName,[mergeMode] OOResourceMergeMode mergeMode,[cache] BOOL useCache)
const char * filename
Definition ioapi.h:133
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char int mode
Definition ioapi.h:133
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data)